Aleo, Noto Sans, Open Dyslexic fonts (#163)

## Summary

* Swap out Bookerly font due to licensing issues, replace default font
with Aleo
* I did a bunch of searching around for a nice replacement font, and
this trumped several other like Literata, Merriwether, Vollkorn, etc
* Add Noto Sans, and Open Dyslexic as font options
  * They can be selected in the settings screen
* Add font size options (Small, Medium, Large, Extra Large)
  * Adjustable in settings
* Swap out uses of reader font in headings and replaced with slightly
larger Ubuntu font
* Replaced PixelArial14 font as it was difficult to track down, replace
with Space Grotesk
* Remove auto formatting on generated font files
* Massively speeds up formatting step now that there is a lot more CPP
font source
* Include fonts with their licenses in the repo

## Additional Context

Line compression setting will follow

| Font | Small | Medium | Large | X Large |
| --- | --- | --- | --- | --- |
| Aleo |
![IMG_5704](https://github.com/user-attachments/assets/7acb054f-ddef-4080-b3c8-590cfaf13115)
|
![IMG_5705](https://github.com/user-attachments/assets/d4819036-5c89-486e-92c3-86094fa4d89a)
|
![IMG_5706](https://github.com/user-attachments/assets/35caf622-d126-4396-9c3e-f927eba1e1f4)
|
![IMG_5707](https://github.com/user-attachments/assets/af32370a-6244-400f-bea9-5c27db040b5b)
|
| Noto Sans |
![IMG_5708](https://github.com/user-attachments/assets/1f9264a5-c069-4e22-9099-a082bfcaabc5)
|
![IMG_5709](https://github.com/user-attachments/assets/ef6b07fe-8d87-403a-b152-05f50b69b78e)
|
![IMG_5710](https://github.com/user-attachments/assets/112a5d20-262c-4dc0-b67d-980b237e4607)
|
![IMG_5711](https://github.com/user-attachments/assets/d25e0e1d-2ace-450d-96dd-618e4efd4805)
|
| Open Dyslexic |
![IMG_5712](https://github.com/user-attachments/assets/ead64690-f261-4fae-a4a2-0becd1162e2d)
|
![IMG_5713](https://github.com/user-attachments/assets/59d60f7d-5142-4591-96b0-c04e0a4c6436)
|
![IMG_5714](https://github.com/user-attachments/assets/bb6652cd-1790-46a3-93ea-2b8f70d0d36d)
|
![IMG_5715](https://github.com/user-attachments/assets/496e7eb4-c81a-4232-83e9-9ba9148fdea4)
|
This commit is contained in:
Dave Allie
2025-12-30 18:21:47 +10:00
committed by GitHub
parent 9f31f80c80
commit bf7bffd506
104 changed files with 211365 additions and 20841 deletions

View File

@@ -4,13 +4,15 @@
#include <SDCardManager.h>
#include <Serialization.h>
#include "fontIds.h"
// Initialize the static instance
CrossPointSettings CrossPointSettings::instance;
namespace {
constexpr uint8_t SETTINGS_FILE_VERSION = 1;
// Increment this when adding new persisted settings fields
constexpr uint8_t SETTINGS_COUNT = 7;
constexpr uint8_t SETTINGS_COUNT = 9;
constexpr char SETTINGS_FILE[] = "/.crosspoint/settings.bin";
} // namespace
@@ -32,6 +34,8 @@ bool CrossPointSettings::saveToFile() const {
serialization::writePod(outputFile, orientation);
serialization::writePod(outputFile, frontButtonLayout);
serialization::writePod(outputFile, sideButtonLayout);
serialization::writePod(outputFile, fontFamily);
serialization::writePod(outputFile, fontSize);
outputFile.close();
Serial.printf("[%lu] [CPS] Settings saved to file\n", millis());
@@ -72,9 +76,55 @@ bool CrossPointSettings::loadFromFile() {
if (++settingsRead >= fileSettingsCount) break;
serialization::readPod(inputFile, sideButtonLayout);
if (++settingsRead >= fileSettingsCount) break;
serialization::readPod(inputFile, fontFamily);
if (++settingsRead >= fileSettingsCount) break;
serialization::readPod(inputFile, fontSize);
if (++settingsRead >= fileSettingsCount) break;
} while (false);
inputFile.close();
Serial.printf("[%lu] [CPS] Settings loaded from file\n", millis());
return true;
}
int CrossPointSettings::getReaderFontId() const {
switch (fontFamily) {
case ALEO:
default:
switch (fontSize) {
case SMALL:
return ALEO_12_FONT_ID;
case MEDIUM:
default:
return ALEO_14_FONT_ID;
case LARGE:
return ALEO_16_FONT_ID;
case EXTRA_LARGE:
return ALEO_18_FONT_ID;
}
case NOTOSANS:
switch (fontSize) {
case SMALL:
return NOTOSANS_12_FONT_ID;
case MEDIUM:
default:
return NOTOSANS_14_FONT_ID;
case LARGE:
return NOTOSANS_16_FONT_ID;
case EXTRA_LARGE:
return NOTOSANS_18_FONT_ID;
}
case OPENDYSLEXIC:
switch (fontSize) {
case SMALL:
return OPENDYSLEXIC_8_FONT_ID;
case MEDIUM:
default:
return OPENDYSLEXIC_10_FONT_ID;
case LARGE:
return OPENDYSLEXIC_12_FONT_ID;
case EXTRA_LARGE:
return OPENDYSLEXIC_14_FONT_ID;
}
}
}

View File

@@ -38,6 +38,11 @@ class CrossPointSettings {
// Swapped: Next, Previous
enum SIDE_BUTTON_LAYOUT { PREV_NEXT = 0, NEXT_PREV = 1 };
// Font family options
enum FONT_FAMILY { ALEO = 0, NOTOSANS = 1, OPENDYSLEXIC = 2 };
// Font size options
enum FONT_SIZE { SMALL = 0, MEDIUM = 1, LARGE = 2, EXTRA_LARGE = 3 };
// Sleep screen settings
uint8_t sleepScreen = DARK;
// Status bar settings
@@ -53,6 +58,10 @@ class CrossPointSettings {
uint8_t frontButtonLayout = BACK_CONFIRM_LEFT_RIGHT;
// Side button layout
uint8_t sideButtonLayout = PREV_NEXT;
// Font family
uint8_t fontFamily = ALEO;
// Font size
uint8_t fontSize = MEDIUM;
~CrossPointSettings() = default;
@@ -60,6 +69,7 @@ class CrossPointSettings {
static CrossPointSettings& getInstance() { return instance; }
uint16_t getPowerButtonDuration() const { return shortPwrBtn ? 10 : 400; }
int getReaderFontId() const;
bool saveToFile() const;
bool loadFromFile();

View File

@@ -2,7 +2,7 @@
#include <GfxRenderer.h>
#include "config.h"
#include "fontIds.h"
#include "images/CrossLarge.h"
void BootActivity::onEnter() {
@@ -13,7 +13,7 @@ void BootActivity::onEnter() {
renderer.clearScreen();
renderer.drawImage(CrossLarge, (pageWidth + 128) / 2, (pageHeight - 128) / 2, 128, 128);
renderer.drawCenteredText(UI_FONT_ID, pageHeight / 2 + 70, "CrossPoint", true, BOLD);
renderer.drawCenteredText(UI_10_FONT_ID, pageHeight / 2 + 70, "CrossPoint", true, BOLD);
renderer.drawCenteredText(SMALL_FONT_ID, pageHeight / 2 + 95, "BOOTING");
renderer.drawCenteredText(SMALL_FONT_ID, pageHeight - 30, CROSSPOINT_VERSION);
renderer.displayBuffer();

View File

@@ -1,7 +1,6 @@
#include "SleepActivity.h"
#include <Epub.h>
#include <FsHelpers.h>
#include <GfxRenderer.h>
#include <SDCardManager.h>
#include <Xtc.h>
@@ -10,7 +9,7 @@
#include "CrossPointSettings.h"
#include "CrossPointState.h"
#include "config.h"
#include "fontIds.h"
#include "images/CrossLarge.h"
namespace {
@@ -43,15 +42,15 @@ void SleepActivity::onEnter() {
}
void SleepActivity::renderPopup(const char* message) const {
const int textWidth = renderer.getTextWidth(READER_FONT_ID, message);
const int textWidth = renderer.getTextWidth(UI_12_FONT_ID, message);
constexpr int margin = 20;
const int x = (renderer.getScreenWidth() - textWidth - margin * 2) / 2;
constexpr int y = 117;
const int w = textWidth + margin * 2;
const int h = renderer.getLineHeight(READER_FONT_ID) + margin * 2;
const int h = renderer.getLineHeight(UI_12_FONT_ID) + margin * 2;
// renderer.clearScreen();
renderer.fillRect(x + 5, y + 5, w - 10, h - 10, false);
renderer.drawText(READER_FONT_ID, x + margin, y + margin, message);
renderer.drawText(UI_12_FONT_ID, x + margin, y + margin, message);
renderer.drawRect(x + 5, y + 5, w - 10, h - 10);
renderer.displayBuffer();
}
@@ -130,7 +129,7 @@ void SleepActivity::renderDefaultSleepScreen() const {
renderer.clearScreen();
renderer.drawImage(CrossLarge, (pageWidth + 128) / 2, (pageHeight - 128) / 2, 128, 128);
renderer.drawCenteredText(UI_FONT_ID, pageHeight / 2 + 70, "CrossPoint", true, BOLD);
renderer.drawCenteredText(UI_10_FONT_ID, pageHeight / 2 + 70, "CrossPoint", true, BOLD);
renderer.drawCenteredText(SMALL_FONT_ID, pageHeight / 2 + 95, "SLEEPING");
// Make sleep screen dark unless light is selected in settings

View File

@@ -5,7 +5,7 @@
#include "CrossPointState.h"
#include "MappedInputManager.h"
#include "config.h"
#include "fontIds.h"
void HomeActivity::taskTrampoline(void* param) {
auto* self = static_cast<HomeActivity*>(param);
@@ -103,7 +103,7 @@ void HomeActivity::render() const {
renderer.clearScreen();
const auto pageWidth = renderer.getScreenWidth();
renderer.drawCenteredText(READER_FONT_ID, 10, "CrossPoint Reader", true, BOLD);
renderer.drawCenteredText(UI_12_FONT_ID, 10, "CrossPoint Reader", true, BOLD);
// Draw selection
renderer.fillRect(0, 60 + selectorIndex * 30 - 2, pageWidth - 1, 30);
@@ -125,30 +125,30 @@ void HomeActivity::render() const {
// Truncate if too long
std::string continueLabel = "Continue: " + bookName;
int itemWidth = renderer.getTextWidth(UI_FONT_ID, continueLabel.c_str());
int itemWidth = renderer.getTextWidth(UI_10_FONT_ID, continueLabel.c_str());
while (itemWidth > renderer.getScreenWidth() - 40 && continueLabel.length() > 8) {
continueLabel.replace(continueLabel.length() - 5, 5, "...");
itemWidth = renderer.getTextWidth(UI_FONT_ID, continueLabel.c_str());
itemWidth = renderer.getTextWidth(UI_10_FONT_ID, continueLabel.c_str());
Serial.printf("[%lu] [HOM] width: %lu, pageWidth: %lu\n", millis(), itemWidth, pageWidth);
}
renderer.drawText(UI_FONT_ID, 20, menuY, continueLabel.c_str(), selectorIndex != menuIndex);
renderer.drawText(UI_10_FONT_ID, 20, menuY, continueLabel.c_str(), selectorIndex != menuIndex);
menuY += 30;
menuIndex++;
}
renderer.drawText(UI_FONT_ID, 20, menuY, "Browse", selectorIndex != menuIndex);
renderer.drawText(UI_10_FONT_ID, 20, menuY, "Browse", selectorIndex != menuIndex);
menuY += 30;
menuIndex++;
renderer.drawText(UI_FONT_ID, 20, menuY, "File transfer", selectorIndex != menuIndex);
renderer.drawText(UI_10_FONT_ID, 20, menuY, "File transfer", selectorIndex != menuIndex);
menuY += 30;
menuIndex++;
renderer.drawText(UI_FONT_ID, 20, menuY, "Settings", selectorIndex != menuIndex);
renderer.drawText(UI_10_FONT_ID, 20, menuY, "Settings", selectorIndex != menuIndex);
const auto labels = mappedInput.mapLabels("Back", "Confirm", "Left", "Right");
renderer.drawButtonHints(UI_FONT_ID, labels.btn1, labels.btn2, labels.btn3, labels.btn4);
renderer.drawButtonHints(UI_10_FONT_ID, labels.btn1, labels.btn2, labels.btn3, labels.btn4);
renderer.displayBuffer();
}

View File

@@ -11,7 +11,7 @@
#include "MappedInputManager.h"
#include "NetworkModeSelectionActivity.h"
#include "WifiSelectionActivity.h"
#include "config.h"
#include "fontIds.h"
namespace {
// AP Mode configuration
@@ -334,7 +334,7 @@ void CrossPointWebServerActivity::render() const {
} else if (state == WebServerActivityState::AP_STARTING) {
renderer.clearScreen();
const auto pageHeight = renderer.getScreenHeight();
renderer.drawCenteredText(READER_FONT_ID, pageHeight / 2 - 20, "Starting Hotspot...", true, BOLD);
renderer.drawCenteredText(UI_12_FONT_ID, pageHeight / 2 - 20, "Starting Hotspot...", true, BOLD);
renderer.displayBuffer();
}
}
@@ -365,22 +365,21 @@ void CrossPointWebServerActivity::renderServerRunning() const {
// Use consistent line spacing
constexpr int LINE_SPACING = 28; // Space between lines
renderer.drawCenteredText(READER_FONT_ID, 15, "File Transfer", true, BOLD);
renderer.drawCenteredText(UI_12_FONT_ID, 15, "File Transfer", true, BOLD);
if (isApMode) {
// AP mode display - center the content block
int startY = 55;
renderer.drawCenteredText(UI_FONT_ID, startY, "Hotspot Mode", true, BOLD);
renderer.drawCenteredText(UI_10_FONT_ID, startY, "Hotspot Mode", true, BOLD);
std::string ssidInfo = "Network: " + connectedSSID;
renderer.drawCenteredText(UI_FONT_ID, startY + LINE_SPACING, ssidInfo.c_str(), true, REGULAR);
renderer.drawCenteredText(UI_10_FONT_ID, startY + LINE_SPACING, ssidInfo.c_str());
renderer.drawCenteredText(SMALL_FONT_ID, startY + LINE_SPACING * 2, "Connect your device to this WiFi network",
true, REGULAR);
renderer.drawCenteredText(SMALL_FONT_ID, startY + LINE_SPACING * 2, "Connect your device to this WiFi network");
renderer.drawCenteredText(SMALL_FONT_ID, startY + LINE_SPACING * 3,
"or scan QR code with your phone to connect to Wifi.", true, REGULAR);
"or scan QR code with your phone to connect to Wifi.");
// Show QR code for URL
std::string wifiConfig = std::string("WIFI:T:WPA;S:") + connectedSSID + ";P:" + "" + ";;";
drawQRCode(renderer, (480 - 6 * 33) / 2, startY + LINE_SPACING * 4, wifiConfig);
@@ -388,16 +387,15 @@ void CrossPointWebServerActivity::renderServerRunning() const {
startY += 6 * 29 + 3 * LINE_SPACING;
// Show primary URL (hostname)
std::string hostnameUrl = std::string("http://") + AP_HOSTNAME + ".local/";
renderer.drawCenteredText(UI_FONT_ID, startY + LINE_SPACING * 3, hostnameUrl.c_str(), true, BOLD);
renderer.drawCenteredText(UI_10_FONT_ID, startY + LINE_SPACING * 3, hostnameUrl.c_str(), true, BOLD);
// Show IP address as fallback
std::string ipUrl = "or http://" + connectedIP + "/";
renderer.drawCenteredText(SMALL_FONT_ID, startY + LINE_SPACING * 4, ipUrl.c_str(), true, REGULAR);
renderer.drawCenteredText(SMALL_FONT_ID, startY + LINE_SPACING * 5, "Open this URL in your browser", true, REGULAR);
renderer.drawCenteredText(SMALL_FONT_ID, startY + LINE_SPACING * 4, ipUrl.c_str());
renderer.drawCenteredText(SMALL_FONT_ID, startY + LINE_SPACING * 5, "Open this URL in your browser");
// Show QR code for URL
renderer.drawCenteredText(SMALL_FONT_ID, startY + LINE_SPACING * 6, "or scan QR code with your phone:", true,
REGULAR);
renderer.drawCenteredText(SMALL_FONT_ID, startY + LINE_SPACING * 6, "or scan QR code with your phone:");
drawQRCode(renderer, (480 - 6 * 33) / 2, startY + LINE_SPACING * 7, hostnameUrl);
} else {
// STA mode display (original behavior)
@@ -407,27 +405,26 @@ void CrossPointWebServerActivity::renderServerRunning() const {
if (ssidInfo.length() > 28) {
ssidInfo.replace(25, ssidInfo.length() - 25, "...");
}
renderer.drawCenteredText(UI_FONT_ID, startY, ssidInfo.c_str(), true, REGULAR);
renderer.drawCenteredText(UI_10_FONT_ID, startY, ssidInfo.c_str());
std::string ipInfo = "IP Address: " + connectedIP;
renderer.drawCenteredText(UI_FONT_ID, startY + LINE_SPACING, ipInfo.c_str(), true, REGULAR);
renderer.drawCenteredText(UI_10_FONT_ID, startY + LINE_SPACING, ipInfo.c_str());
// Show web server URL prominently
std::string webInfo = "http://" + connectedIP + "/";
renderer.drawCenteredText(UI_FONT_ID, startY + LINE_SPACING * 2, webInfo.c_str(), true, BOLD);
renderer.drawCenteredText(UI_10_FONT_ID, startY + LINE_SPACING * 2, webInfo.c_str(), true, BOLD);
// Also show hostname URL
std::string hostnameUrl = std::string("or http://") + AP_HOSTNAME + ".local/";
renderer.drawCenteredText(SMALL_FONT_ID, startY + LINE_SPACING * 3, hostnameUrl.c_str(), true, REGULAR);
renderer.drawCenteredText(SMALL_FONT_ID, startY + LINE_SPACING * 3, hostnameUrl.c_str());
renderer.drawCenteredText(SMALL_FONT_ID, startY + LINE_SPACING * 4, "Open this URL in your browser", true, REGULAR);
renderer.drawCenteredText(SMALL_FONT_ID, startY + LINE_SPACING * 4, "Open this URL in your browser");
// Show QR code for URL
drawQRCode(renderer, (480 - 6 * 33) / 2, startY + LINE_SPACING * 6, webInfo);
renderer.drawCenteredText(SMALL_FONT_ID, startY + LINE_SPACING * 5, "or scan QR code with your phone:", true,
REGULAR);
renderer.drawCenteredText(SMALL_FONT_ID, startY + LINE_SPACING * 5, "or scan QR code with your phone:");
}
const auto labels = mappedInput.mapLabels("« Exit", "", "", "");
renderer.drawButtonHints(UI_FONT_ID, labels.btn1, labels.btn2, labels.btn3, labels.btn4);
renderer.drawButtonHints(UI_10_FONT_ID, labels.btn1, labels.btn2, labels.btn3, labels.btn4);
}

View File

@@ -3,7 +3,7 @@
#include <GfxRenderer.h>
#include "MappedInputManager.h"
#include "config.h"
#include "fontIds.h"
namespace {
constexpr int MENU_ITEM_COUNT = 2;
@@ -97,10 +97,10 @@ void NetworkModeSelectionActivity::render() const {
const auto pageHeight = renderer.getScreenHeight();
// Draw header
renderer.drawCenteredText(READER_FONT_ID, 10, "File Transfer", true, BOLD);
renderer.drawCenteredText(UI_12_FONT_ID, 10, "File Transfer", true, BOLD);
// Draw subtitle
renderer.drawCenteredText(UI_FONT_ID, 50, "How would you like to connect?", true, REGULAR);
renderer.drawCenteredText(UI_10_FONT_ID, 50, "How would you like to connect?");
// Draw menu items centered on screen
constexpr int itemHeight = 50; // Height for each menu item (including description)
@@ -117,13 +117,13 @@ void NetworkModeSelectionActivity::render() const {
// Draw text: black=false (white text) when selected (on black background)
// black=true (black text) when not selected (on white background)
renderer.drawText(UI_FONT_ID, 30, itemY, MENU_ITEMS[i], /*black=*/!isSelected);
renderer.drawText(UI_10_FONT_ID, 30, itemY, MENU_ITEMS[i], /*black=*/!isSelected);
renderer.drawText(SMALL_FONT_ID, 30, itemY + 22, MENU_DESCRIPTIONS[i], /*black=*/!isSelected);
}
// Draw help text at bottom
const auto labels = mappedInput.mapLabels("« Back", "Select", "", "");
renderer.drawButtonHints(UI_FONT_ID, labels.btn1, labels.btn2, labels.btn3, labels.btn4);
renderer.drawButtonHints(UI_10_FONT_ID, labels.btn1, labels.btn2, labels.btn3, labels.btn4);
renderer.displayBuffer();
}

View File

@@ -8,7 +8,7 @@
#include "MappedInputManager.h"
#include "WifiCredentialStore.h"
#include "activities/util/KeyboardEntryActivity.h"
#include "config.h"
#include "fontIds.h"
void WifiSelectionActivity::taskTrampoline(void* param) {
auto* self = static_cast<WifiSelectionActivity*>(param);
@@ -496,14 +496,14 @@ void WifiSelectionActivity::renderNetworkList() const {
const auto pageHeight = renderer.getScreenHeight();
// Draw header
renderer.drawCenteredText(READER_FONT_ID, 10, "WiFi Networks", true, BOLD);
renderer.drawCenteredText(UI_12_FONT_ID, 10, "WiFi Networks", true, BOLD);
if (networks.empty()) {
// No networks found or scan failed
const auto height = renderer.getLineHeight(UI_FONT_ID);
const auto height = renderer.getLineHeight(UI_10_FONT_ID);
const auto top = (pageHeight - height) / 2;
renderer.drawCenteredText(UI_FONT_ID, top, "No networks found", true, REGULAR);
renderer.drawCenteredText(SMALL_FONT_ID, top + height + 10, "Press OK to scan again", true, REGULAR);
renderer.drawCenteredText(UI_10_FONT_ID, top, "No networks found");
renderer.drawCenteredText(SMALL_FONT_ID, top + height + 10, "Press OK to scan again");
} else {
// Calculate how many networks we can display
constexpr int startY = 60;
@@ -524,7 +524,7 @@ void WifiSelectionActivity::renderNetworkList() const {
// Draw selection indicator
if (static_cast<int>(i) == selectedNetworkIndex) {
renderer.drawText(UI_FONT_ID, 5, networkY, ">");
renderer.drawText(UI_10_FONT_ID, 5, networkY, ">");
}
// Draw network name (truncate if too long)
@@ -532,20 +532,20 @@ void WifiSelectionActivity::renderNetworkList() const {
if (displayName.length() > 16) {
displayName.replace(13, displayName.length() - 13, "...");
}
renderer.drawText(UI_FONT_ID, 20, networkY, displayName.c_str());
renderer.drawText(UI_10_FONT_ID, 20, networkY, displayName.c_str());
// Draw signal strength indicator
std::string signalStr = getSignalStrengthIndicator(network.rssi);
renderer.drawText(UI_FONT_ID, pageWidth - 90, networkY, signalStr.c_str());
renderer.drawText(UI_10_FONT_ID, pageWidth - 90, networkY, signalStr.c_str());
// Draw saved indicator (checkmark) for networks with saved passwords
if (network.hasSavedPassword) {
renderer.drawText(UI_FONT_ID, pageWidth - 50, networkY, "+");
renderer.drawText(UI_10_FONT_ID, pageWidth - 50, networkY, "+");
}
// Draw lock icon for encrypted networks
if (network.isEncrypted) {
renderer.drawText(UI_FONT_ID, pageWidth - 30, networkY, "*");
renderer.drawText(UI_10_FONT_ID, pageWidth - 30, networkY, "*");
}
}
@@ -566,61 +566,61 @@ void WifiSelectionActivity::renderNetworkList() const {
// Draw help text
renderer.drawText(SMALL_FONT_ID, 20, pageHeight - 75, "* = Encrypted | + = Saved");
const auto labels = mappedInput.mapLabels("« Back", "Connect", "", "");
renderer.drawButtonHints(UI_FONT_ID, labels.btn1, labels.btn2, labels.btn3, labels.btn4);
renderer.drawButtonHints(UI_10_FONT_ID, labels.btn1, labels.btn2, labels.btn3, labels.btn4);
}
void WifiSelectionActivity::renderConnecting() const {
const auto pageHeight = renderer.getScreenHeight();
const auto height = renderer.getLineHeight(UI_FONT_ID);
const auto height = renderer.getLineHeight(UI_10_FONT_ID);
const auto top = (pageHeight - height) / 2;
if (state == WifiSelectionState::SCANNING) {
renderer.drawCenteredText(UI_FONT_ID, top, "Scanning...", true, REGULAR);
renderer.drawCenteredText(UI_10_FONT_ID, top, "Scanning...");
} else {
renderer.drawCenteredText(READER_FONT_ID, top - 40, "Connecting...", true, BOLD);
renderer.drawCenteredText(UI_12_FONT_ID, top - 40, "Connecting...", true, BOLD);
std::string ssidInfo = "to " + selectedSSID;
if (ssidInfo.length() > 25) {
ssidInfo.replace(22, ssidInfo.length() - 22, "...");
}
renderer.drawCenteredText(UI_FONT_ID, top, ssidInfo.c_str(), true, REGULAR);
renderer.drawCenteredText(UI_10_FONT_ID, top, ssidInfo.c_str());
}
}
void WifiSelectionActivity::renderConnected() const {
const auto pageHeight = renderer.getScreenHeight();
const auto height = renderer.getLineHeight(UI_FONT_ID);
const auto height = renderer.getLineHeight(UI_10_FONT_ID);
const auto top = (pageHeight - height * 4) / 2;
renderer.drawCenteredText(READER_FONT_ID, top - 30, "Connected!", true, BOLD);
renderer.drawCenteredText(UI_12_FONT_ID, top - 30, "Connected!", true, BOLD);
std::string ssidInfo = "Network: " + selectedSSID;
if (ssidInfo.length() > 28) {
ssidInfo.replace(25, ssidInfo.length() - 25, "...");
}
renderer.drawCenteredText(UI_FONT_ID, top + 10, ssidInfo.c_str(), true, REGULAR);
renderer.drawCenteredText(UI_10_FONT_ID, top + 10, ssidInfo.c_str());
const std::string ipInfo = "IP Address: " + connectedIP;
renderer.drawCenteredText(UI_FONT_ID, top + 40, ipInfo.c_str(), true, REGULAR);
renderer.drawCenteredText(UI_10_FONT_ID, top + 40, ipInfo.c_str());
renderer.drawCenteredText(SMALL_FONT_ID, pageHeight - 30, "Press any button to continue", true, REGULAR);
renderer.drawCenteredText(SMALL_FONT_ID, pageHeight - 30, "Press any button to continue");
}
void WifiSelectionActivity::renderSavePrompt() const {
const auto pageWidth = renderer.getScreenWidth();
const auto pageHeight = renderer.getScreenHeight();
const auto height = renderer.getLineHeight(UI_FONT_ID);
const auto height = renderer.getLineHeight(UI_10_FONT_ID);
const auto top = (pageHeight - height * 3) / 2;
renderer.drawCenteredText(READER_FONT_ID, top - 40, "Connected!", true, BOLD);
renderer.drawCenteredText(UI_12_FONT_ID, top - 40, "Connected!", true, BOLD);
std::string ssidInfo = "Network: " + selectedSSID;
if (ssidInfo.length() > 28) {
ssidInfo.replace(25, ssidInfo.length() - 25, "...");
}
renderer.drawCenteredText(UI_FONT_ID, top, ssidInfo.c_str(), true, REGULAR);
renderer.drawCenteredText(UI_10_FONT_ID, top, ssidInfo.c_str());
renderer.drawCenteredText(UI_FONT_ID, top + 40, "Save password for next time?", true, REGULAR);
renderer.drawCenteredText(UI_10_FONT_ID, top + 40, "Save password for next time?");
// Draw Yes/No buttons
const int buttonY = top + 80;
@@ -631,46 +631,46 @@ void WifiSelectionActivity::renderSavePrompt() const {
// Draw "Yes" button
if (savePromptSelection == 0) {
renderer.drawText(UI_FONT_ID, startX, buttonY, "[Yes]");
renderer.drawText(UI_10_FONT_ID, startX, buttonY, "[Yes]");
} else {
renderer.drawText(UI_FONT_ID, startX + 4, buttonY, "Yes");
renderer.drawText(UI_10_FONT_ID, startX + 4, buttonY, "Yes");
}
// Draw "No" button
if (savePromptSelection == 1) {
renderer.drawText(UI_FONT_ID, startX + buttonWidth + buttonSpacing, buttonY, "[No]");
renderer.drawText(UI_10_FONT_ID, startX + buttonWidth + buttonSpacing, buttonY, "[No]");
} else {
renderer.drawText(UI_FONT_ID, startX + buttonWidth + buttonSpacing + 4, buttonY, "No");
renderer.drawText(UI_10_FONT_ID, startX + buttonWidth + buttonSpacing + 4, buttonY, "No");
}
renderer.drawCenteredText(SMALL_FONT_ID, pageHeight - 30, "LEFT/RIGHT: Select | OK: Confirm", true, REGULAR);
renderer.drawCenteredText(SMALL_FONT_ID, pageHeight - 30, "LEFT/RIGHT: Select | OK: Confirm");
}
void WifiSelectionActivity::renderConnectionFailed() const {
const auto pageHeight = renderer.getScreenHeight();
const auto height = renderer.getLineHeight(UI_FONT_ID);
const auto height = renderer.getLineHeight(UI_10_FONT_ID);
const auto top = (pageHeight - height * 2) / 2;
renderer.drawCenteredText(READER_FONT_ID, top - 20, "Connection Failed", true, BOLD);
renderer.drawCenteredText(UI_FONT_ID, top + 20, connectionError.c_str(), true, REGULAR);
renderer.drawCenteredText(SMALL_FONT_ID, pageHeight - 30, "Press any button to continue", true, REGULAR);
renderer.drawCenteredText(UI_12_FONT_ID, top - 20, "Connection Failed", true, BOLD);
renderer.drawCenteredText(UI_10_FONT_ID, top + 20, connectionError.c_str());
renderer.drawCenteredText(SMALL_FONT_ID, pageHeight - 30, "Press any button to continue");
}
void WifiSelectionActivity::renderForgetPrompt() const {
const auto pageWidth = renderer.getScreenWidth();
const auto pageHeight = renderer.getScreenHeight();
const auto height = renderer.getLineHeight(UI_FONT_ID);
const auto height = renderer.getLineHeight(UI_10_FONT_ID);
const auto top = (pageHeight - height * 3) / 2;
renderer.drawCenteredText(READER_FONT_ID, top - 40, "Forget Network?", true, BOLD);
renderer.drawCenteredText(UI_12_FONT_ID, top - 40, "Forget Network?", true, BOLD);
std::string ssidInfo = "Network: " + selectedSSID;
if (ssidInfo.length() > 28) {
ssidInfo.replace(25, ssidInfo.length() - 25, "...");
}
renderer.drawCenteredText(UI_FONT_ID, top, ssidInfo.c_str(), true, REGULAR);
renderer.drawCenteredText(UI_10_FONT_ID, top, ssidInfo.c_str());
renderer.drawCenteredText(UI_FONT_ID, top + 40, "Remove saved password?", true, REGULAR);
renderer.drawCenteredText(UI_10_FONT_ID, top + 40, "Remove saved password?");
// Draw Yes/No buttons
const int buttonY = top + 80;
@@ -681,17 +681,17 @@ void WifiSelectionActivity::renderForgetPrompt() const {
// Draw "Yes" button
if (forgetPromptSelection == 0) {
renderer.drawText(UI_FONT_ID, startX, buttonY, "[Yes]");
renderer.drawText(UI_10_FONT_ID, startX, buttonY, "[Yes]");
} else {
renderer.drawText(UI_FONT_ID, startX + 4, buttonY, "Yes");
renderer.drawText(UI_10_FONT_ID, startX + 4, buttonY, "Yes");
}
// Draw "No" button
if (forgetPromptSelection == 1) {
renderer.drawText(UI_FONT_ID, startX + buttonWidth + buttonSpacing, buttonY, "[No]");
renderer.drawText(UI_10_FONT_ID, startX + buttonWidth + buttonSpacing, buttonY, "[No]");
} else {
renderer.drawText(UI_FONT_ID, startX + buttonWidth + buttonSpacing + 4, buttonY, "No");
renderer.drawText(UI_10_FONT_ID, startX + buttonWidth + buttonSpacing + 4, buttonY, "No");
}
renderer.drawCenteredText(SMALL_FONT_ID, pageHeight - 30, "LEFT/RIGHT: Select | OK: Confirm", true, REGULAR);
renderer.drawCenteredText(SMALL_FONT_ID, pageHeight - 30, "LEFT/RIGHT: Select | OK: Confirm");
}

View File

@@ -10,13 +10,14 @@
#include "CrossPointState.h"
#include "EpubReaderChapterSelectionActivity.h"
#include "MappedInputManager.h"
#include "config.h"
#include "fontIds.h"
namespace {
constexpr int pagesPerRefresh = 15;
constexpr unsigned long skipChapterMs = 700;
constexpr unsigned long goHomeMs = 1000;
constexpr float lineCompression = 0.95f;
constexpr int topPadding = 5;
constexpr int horizontalPadding = 5;
constexpr int statusBarMargin = 19;
} // namespace
@@ -234,7 +235,7 @@ void EpubReaderActivity::renderScreen() {
// Show end of book screen
if (currentSpineIndex == epub->getSpineItemsCount()) {
renderer.clearScreen();
renderer.drawCenteredText(READER_FONT_ID, 300, "End of book", true, BOLD);
renderer.drawCenteredText(UI_12_FONT_ID, 300, "End of book", true, BOLD);
renderer.displayBuffer();
return;
}
@@ -243,6 +244,7 @@ void EpubReaderActivity::renderScreen() {
int orientedMarginTop, orientedMarginRight, orientedMarginBottom, orientedMarginLeft;
renderer.getOrientedViewableTRBL(&orientedMarginTop, &orientedMarginRight, &orientedMarginBottom,
&orientedMarginLeft);
orientedMarginTop += topPadding;
orientedMarginLeft += horizontalPadding;
orientedMarginRight += horizontalPadding;
orientedMarginBottom += statusBarMargin;
@@ -255,29 +257,29 @@ void EpubReaderActivity::renderScreen() {
const auto viewportWidth = renderer.getScreenWidth() - orientedMarginLeft - orientedMarginRight;
const auto viewportHeight = renderer.getScreenHeight() - orientedMarginTop - orientedMarginBottom;
if (!section->loadSectionFile(READER_FONT_ID, lineCompression, SETTINGS.extraParagraphSpacing, viewportWidth,
viewportHeight)) {
if (!section->loadSectionFile(SETTINGS.getReaderFontId(), lineCompression, SETTINGS.extraParagraphSpacing,
viewportWidth, viewportHeight)) {
Serial.printf("[%lu] [ERS] Cache not found, building...\n", millis());
// Progress bar dimensions
constexpr int barWidth = 200;
constexpr int barHeight = 10;
constexpr int boxMargin = 20;
const int textWidth = renderer.getTextWidth(READER_FONT_ID, "Indexing...");
const int textWidth = renderer.getTextWidth(UI_12_FONT_ID, "Indexing...");
const int boxWidthWithBar = (barWidth > textWidth ? barWidth : textWidth) + boxMargin * 2;
const int boxWidthNoBar = textWidth + boxMargin * 2;
const int boxHeightWithBar = renderer.getLineHeight(READER_FONT_ID) + barHeight + boxMargin * 3;
const int boxHeightNoBar = renderer.getLineHeight(READER_FONT_ID) + boxMargin * 2;
const int boxHeightWithBar = renderer.getLineHeight(UI_12_FONT_ID) + barHeight + boxMargin * 3;
const int boxHeightNoBar = renderer.getLineHeight(UI_12_FONT_ID) + boxMargin * 2;
const int boxXWithBar = (renderer.getScreenWidth() - boxWidthWithBar) / 2;
const int boxXNoBar = (renderer.getScreenWidth() - boxWidthNoBar) / 2;
constexpr int boxY = 50;
const int barX = boxXWithBar + (boxWidthWithBar - barWidth) / 2;
const int barY = boxY + renderer.getLineHeight(READER_FONT_ID) + boxMargin * 2;
const int barY = boxY + renderer.getLineHeight(UI_12_FONT_ID) + boxMargin * 2;
// Always show "Indexing..." text first
{
renderer.fillRect(boxXNoBar, boxY, boxWidthNoBar, boxHeightNoBar, false);
renderer.drawText(READER_FONT_ID, boxXNoBar + boxMargin, boxY + boxMargin, "Indexing...");
renderer.drawText(UI_12_FONT_ID, boxXNoBar + boxMargin, boxY + boxMargin, "Indexing...");
renderer.drawRect(boxXNoBar + 5, boxY + 5, boxWidthNoBar - 10, boxHeightNoBar - 10);
renderer.displayBuffer();
pagesUntilFullRefresh = 0;
@@ -286,7 +288,7 @@ void EpubReaderActivity::renderScreen() {
// Setup callback - only called for chapters >= 50KB, redraws with progress bar
auto progressSetup = [this, boxXWithBar, boxWidthWithBar, boxHeightWithBar, barX, barY] {
renderer.fillRect(boxXWithBar, boxY, boxWidthWithBar, boxHeightWithBar, false);
renderer.drawText(READER_FONT_ID, boxXWithBar + boxMargin, boxY + boxMargin, "Indexing...");
renderer.drawText(UI_12_FONT_ID, boxXWithBar + boxMargin, boxY + boxMargin, "Indexing...");
renderer.drawRect(boxXWithBar + 5, boxY + 5, boxWidthWithBar - 10, boxHeightWithBar - 10);
renderer.drawRect(barX, barY, barWidth, barHeight);
renderer.displayBuffer();
@@ -299,8 +301,8 @@ void EpubReaderActivity::renderScreen() {
renderer.displayBuffer(EInkDisplay::FAST_REFRESH);
};
if (!section->createSectionFile(READER_FONT_ID, lineCompression, SETTINGS.extraParagraphSpacing, viewportWidth,
viewportHeight, progressSetup, progressCallback)) {
if (!section->createSectionFile(SETTINGS.getReaderFontId(), lineCompression, SETTINGS.extraParagraphSpacing,
viewportWidth, viewportHeight, progressSetup, progressCallback)) {
Serial.printf("[%lu] [ERS] Failed to persist page data to SD\n", millis());
section.reset();
return;
@@ -320,7 +322,7 @@ void EpubReaderActivity::renderScreen() {
if (section->pageCount == 0) {
Serial.printf("[%lu] [ERS] No pages to render\n", millis());
renderer.drawCenteredText(READER_FONT_ID, 300, "Empty chapter", true, BOLD);
renderer.drawCenteredText(UI_12_FONT_ID, 300, "Empty chapter", true, BOLD);
renderStatusBar(orientedMarginRight, orientedMarginBottom, orientedMarginLeft);
renderer.displayBuffer();
return;
@@ -328,7 +330,7 @@ void EpubReaderActivity::renderScreen() {
if (section->currentPage < 0 || section->currentPage >= section->pageCount) {
Serial.printf("[%lu] [ERS] Page out of bounds: %d (max %d)\n", millis(), section->currentPage, section->pageCount);
renderer.drawCenteredText(READER_FONT_ID, 300, "Out of bounds", true, BOLD);
renderer.drawCenteredText(UI_12_FONT_ID, 300, "Out of bounds", true, BOLD);
renderStatusBar(orientedMarginRight, orientedMarginBottom, orientedMarginLeft);
renderer.displayBuffer();
return;
@@ -362,7 +364,7 @@ void EpubReaderActivity::renderScreen() {
void EpubReaderActivity::renderContents(std::unique_ptr<Page> page, const int orientedMarginTop,
const int orientedMarginRight, const int orientedMarginBottom,
const int orientedMarginLeft) {
page->render(renderer, READER_FONT_ID, orientedMarginLeft, orientedMarginTop);
page->render(renderer, SETTINGS.getReaderFontId(), orientedMarginLeft, orientedMarginTop);
renderStatusBar(orientedMarginRight, orientedMarginBottom, orientedMarginLeft);
if (pagesUntilFullRefresh <= 1) {
renderer.displayBuffer(EInkDisplay::HALF_REFRESH);
@@ -380,13 +382,13 @@ void EpubReaderActivity::renderContents(std::unique_ptr<Page> page, const int or
{
renderer.clearScreen(0x00);
renderer.setRenderMode(GfxRenderer::GRAYSCALE_LSB);
page->render(renderer, READER_FONT_ID, orientedMarginLeft, orientedMarginTop);
page->render(renderer, SETTINGS.getReaderFontId(), orientedMarginLeft, orientedMarginTop);
renderer.copyGrayscaleLsbBuffers();
// Render and copy to MSB buffer
renderer.clearScreen(0x00);
renderer.setRenderMode(GfxRenderer::GRAYSCALE_MSB);
page->render(renderer, READER_FONT_ID, orientedMarginLeft, orientedMarginTop);
page->render(renderer, SETTINGS.getReaderFontId(), orientedMarginLeft, orientedMarginTop);
renderer.copyGrayscaleMsbBuffers();
// display grayscale part
@@ -409,7 +411,7 @@ void EpubReaderActivity::renderStatusBar(const int orientedMarginRight, const in
// Position status bar near the bottom of the logical screen, regardless of orientation
const auto screenHeight = renderer.getScreenHeight();
const auto textY = screenHeight - orientedMarginBottom + 2;
const auto textY = screenHeight - orientedMarginBottom - 2;
int percentageTextWidth = 0;
int progressTextWidth = 0;

View File

@@ -3,7 +3,7 @@
#include <GfxRenderer.h>
#include "MappedInputManager.h"
#include "config.h"
#include "fontIds.h"
namespace {
// Time threshold for treating a long press as a page-up/page-down
@@ -120,14 +120,14 @@ void EpubReaderChapterSelectionActivity::renderScreen() {
const auto pageWidth = renderer.getScreenWidth();
const int pageItems = getPageItems();
renderer.drawCenteredText(READER_FONT_ID, 10, "Select Chapter", true, BOLD);
renderer.drawCenteredText(UI_12_FONT_ID, 10, "Select Chapter", true, BOLD);
const auto pageStartIndex = selectorIndex / pageItems * pageItems;
renderer.fillRect(0, 60 + (selectorIndex % pageItems) * 30 - 2, pageWidth - 1, 30);
for (int tocIndex = pageStartIndex; tocIndex < epub->getTocItemsCount() && tocIndex < pageStartIndex + pageItems;
tocIndex++) {
auto item = epub->getTocItem(tocIndex);
renderer.drawText(UI_FONT_ID, 20 + (item.level - 1) * 15, 60 + (tocIndex % pageItems) * 30, item.title.c_str(),
renderer.drawText(UI_10_FONT_ID, 20 + (item.level - 1) * 15, 60 + (tocIndex % pageItems) * 30, item.title.c_str(),
tocIndex != selectorIndex);
}

View File

@@ -4,7 +4,7 @@
#include <SDCardManager.h>
#include "MappedInputManager.h"
#include "config.h"
#include "fontIds.h"
namespace {
constexpr int PAGE_ITEMS = 23;
@@ -165,14 +165,14 @@ void FileSelectionActivity::render() const {
renderer.clearScreen();
const auto pageWidth = renderer.getScreenWidth();
renderer.drawCenteredText(READER_FONT_ID, 10, "Books", true, BOLD);
renderer.drawCenteredText(UI_12_FONT_ID, 10, "Books", true, BOLD);
// Help text
const auto labels = mappedInput.mapLabels("« Home", "Open", "", "");
renderer.drawButtonHints(UI_FONT_ID, labels.btn1, labels.btn2, labels.btn3, labels.btn4);
renderer.drawButtonHints(UI_10_FONT_ID, labels.btn1, labels.btn2, labels.btn3, labels.btn4);
if (files.empty()) {
renderer.drawText(UI_FONT_ID, 20, 60, "No books found");
renderer.drawText(UI_10_FONT_ID, 20, 60, "No books found");
renderer.displayBuffer();
return;
}
@@ -181,12 +181,12 @@ void FileSelectionActivity::render() const {
renderer.fillRect(0, 60 + (selectorIndex % PAGE_ITEMS) * 30 - 2, pageWidth - 1, 30);
for (int i = pageStartIndex; i < files.size() && i < pageStartIndex + PAGE_ITEMS; i++) {
auto item = files[i];
int itemWidth = renderer.getTextWidth(UI_FONT_ID, item.c_str());
int itemWidth = renderer.getTextWidth(UI_10_FONT_ID, item.c_str());
while (itemWidth > renderer.getScreenWidth() - 40 && item.length() > 8) {
item.replace(item.length() - 5, 5, "...");
itemWidth = renderer.getTextWidth(UI_FONT_ID, item.c_str());
itemWidth = renderer.getTextWidth(UI_10_FONT_ID, item.c_str());
}
renderer.drawText(UI_FONT_ID, 20, 60 + (i % PAGE_ITEMS) * 30, item.c_str(), i != selectorIndex);
renderer.drawText(UI_10_FONT_ID, 20, 60 + (i % PAGE_ITEMS) * 30, item.c_str(), i != selectorIndex);
}
renderer.displayBuffer();

View File

@@ -14,7 +14,7 @@
#include "CrossPointState.h"
#include "MappedInputManager.h"
#include "XtcReaderChapterSelectionActivity.h"
#include "config.h"
#include "fontIds.h"
namespace {
constexpr int pagesPerRefresh = 15;
@@ -165,7 +165,7 @@ void XtcReaderActivity::renderScreen() {
if (currentPage >= xtc->getPageCount()) {
// Show end of book screen
renderer.clearScreen();
renderer.drawCenteredText(UI_FONT_ID, 300, "End of book", true, BOLD);
renderer.drawCenteredText(UI_12_FONT_ID, 300, "End of book", true, BOLD);
renderer.displayBuffer();
return;
}
@@ -194,7 +194,7 @@ void XtcReaderActivity::renderPage() {
if (!pageBuffer) {
Serial.printf("[%lu] [XTR] Failed to allocate page buffer (%lu bytes)\n", millis(), pageBufferSize);
renderer.clearScreen();
renderer.drawCenteredText(UI_FONT_ID, 300, "Memory error", true, BOLD);
renderer.drawCenteredText(UI_12_FONT_ID, 300, "Memory error", true, BOLD);
renderer.displayBuffer();
return;
}
@@ -205,7 +205,7 @@ void XtcReaderActivity::renderPage() {
Serial.printf("[%lu] [XTR] Failed to load page %lu\n", millis(), currentPage);
free(pageBuffer);
renderer.clearScreen();
renderer.drawCenteredText(UI_FONT_ID, 300, "Page load error", true, BOLD);
renderer.drawCenteredText(UI_12_FONT_ID, 300, "Page load error", true, BOLD);
renderer.displayBuffer();
return;
}

View File

@@ -3,7 +3,7 @@
#include <GfxRenderer.h>
#include "MappedInputManager.h"
#include "config.h"
#include "fontIds.h"
namespace {
constexpr int SKIP_PAGE_MS = 700;
@@ -130,11 +130,11 @@ void XtcReaderChapterSelectionActivity::renderScreen() {
const auto pageWidth = renderer.getScreenWidth();
const int pageItems = getPageItems();
renderer.drawCenteredText(READER_FONT_ID, 10, "Select Chapter", true, BOLD);
renderer.drawCenteredText(UI_12_FONT_ID, 10, "Select Chapter", true, BOLD);
const auto& chapters = xtc->getChapters();
if (chapters.empty()) {
renderer.drawCenteredText(UI_FONT_ID, 120, "No chapters", true, REGULAR);
renderer.drawCenteredText(UI_10_FONT_ID, 120, "No chapters");
renderer.displayBuffer();
return;
}
@@ -144,7 +144,7 @@ void XtcReaderChapterSelectionActivity::renderScreen() {
for (int i = pageStartIndex; i < static_cast<int>(chapters.size()) && i < pageStartIndex + pageItems; i++) {
const auto& chapter = chapters[i];
const char* title = chapter.name.empty() ? "Unnamed" : chapter.name.c_str();
renderer.drawText(UI_FONT_ID, 20, 60 + (i % pageItems) * 30, title, i != selectorIndex);
renderer.drawText(UI_10_FONT_ID, 20, 60 + (i % pageItems) * 30, title, i != selectorIndex);
}
renderer.displayBuffer();

View File

@@ -5,7 +5,7 @@
#include "MappedInputManager.h"
#include "activities/network/WifiSelectionActivity.h"
#include "config.h"
#include "fontIds.h"
#include "network/OtaUpdater.h"
void OtaUpdateActivity::taskTrampoline(void* param) {
@@ -128,56 +128,58 @@ void OtaUpdateActivity::render() {
const auto pageWidth = renderer.getScreenWidth();
renderer.clearScreen();
renderer.drawCenteredText(READER_FONT_ID, 10, "Update", true, BOLD);
renderer.drawCenteredText(UI_12_FONT_ID, 10, "Update", true, BOLD);
if (state == CHECKING_FOR_UPDATE) {
renderer.drawCenteredText(UI_FONT_ID, 300, "Checking for update...", true, BOLD);
renderer.drawCenteredText(UI_10_FONT_ID, 300, "Checking for update...", true, BOLD);
renderer.displayBuffer();
return;
}
if (state == WAITING_CONFIRMATION) {
renderer.drawCenteredText(UI_FONT_ID, 200, "New update available!", true, BOLD);
renderer.drawText(UI_FONT_ID, 20, 250, "Current Version: " CROSSPOINT_VERSION);
renderer.drawText(UI_FONT_ID, 20, 270, ("New Version: " + updater.getLatestVersion()).c_str());
renderer.drawCenteredText(UI_10_FONT_ID, 200, "New update available!", true, BOLD);
renderer.drawText(UI_10_FONT_ID, 20, 250, "Current Version: " CROSSPOINT_VERSION);
renderer.drawText(UI_10_FONT_ID, 20, 270, ("New Version: " + updater.getLatestVersion()).c_str());
renderer.drawRect(25, pageHeight - 40, 106, 40);
renderer.drawText(UI_FONT_ID, 25 + (105 - renderer.getTextWidth(UI_FONT_ID, "Cancel")) / 2, pageHeight - 35,
renderer.drawText(UI_10_FONT_ID, 25 + (105 - renderer.getTextWidth(UI_10_FONT_ID, "Cancel")) / 2, pageHeight - 35,
"Cancel");
renderer.drawRect(130, pageHeight - 40, 106, 40);
renderer.drawText(UI_FONT_ID, 130 + (105 - renderer.getTextWidth(UI_FONT_ID, "Update")) / 2, pageHeight - 35,
renderer.drawText(UI_10_FONT_ID, 130 + (105 - renderer.getTextWidth(UI_10_FONT_ID, "Update")) / 2, pageHeight - 35,
"Update");
renderer.displayBuffer();
return;
}
if (state == UPDATE_IN_PROGRESS) {
renderer.drawCenteredText(UI_FONT_ID, 310, "Updating...", true, BOLD);
renderer.drawCenteredText(UI_10_FONT_ID, 310, "Updating...", true, BOLD);
renderer.drawRect(20, 350, pageWidth - 40, 50);
renderer.fillRect(24, 354, static_cast<int>(updaterProgress * static_cast<float>(pageWidth - 44)), 42);
renderer.drawCenteredText(UI_FONT_ID, 420, (std::to_string(static_cast<int>(updaterProgress * 100)) + "%").c_str());
renderer.drawCenteredText(UI_10_FONT_ID, 420,
(std::to_string(static_cast<int>(updaterProgress * 100)) + "%").c_str());
renderer.drawCenteredText(
UI_FONT_ID, 440, (std::to_string(updater.processedSize) + " / " + std::to_string(updater.totalSize)).c_str());
UI_10_FONT_ID, 440,
(std::to_string(updater.processedSize) + " / " + std::to_string(updater.totalSize)).c_str());
renderer.displayBuffer();
return;
}
if (state == NO_UPDATE) {
renderer.drawCenteredText(UI_FONT_ID, 300, "No update available", true, BOLD);
renderer.drawCenteredText(UI_10_FONT_ID, 300, "No update available", true, BOLD);
renderer.displayBuffer();
return;
}
if (state == FAILED) {
renderer.drawCenteredText(UI_FONT_ID, 300, "Update failed", true, BOLD);
renderer.drawCenteredText(UI_10_FONT_ID, 300, "Update failed", true, BOLD);
renderer.displayBuffer();
return;
}
if (state == FINISHED) {
renderer.drawCenteredText(UI_FONT_ID, 300, "Update complete", true, BOLD);
renderer.drawCenteredText(UI_FONT_ID, 350, "Press and hold power button to turn back on");
renderer.drawCenteredText(UI_10_FONT_ID, 300, "Update complete", true, BOLD);
renderer.drawCenteredText(UI_10_FONT_ID, 350, "Press and hold power button to turn back on");
renderer.displayBuffer();
state = SHUTTING_DOWN;
return;

View File

@@ -5,11 +5,11 @@
#include "CrossPointSettings.h"
#include "MappedInputManager.h"
#include "OtaUpdateActivity.h"
#include "config.h"
#include "fontIds.h"
// Define the static settings list
namespace {
constexpr int settingsCount = 8;
constexpr int settingsCount = 10;
const SettingInfo settingsList[settingsCount] = {
// Should match with SLEEP_SCREEN_MODE
{"Sleep Screen", SettingType::ENUM, &CrossPointSettings::sleepScreen, {"Dark", "Light", "Custom", "Cover"}},
@@ -28,6 +28,8 @@ const SettingInfo settingsList[settingsCount] = {
SettingType::ENUM,
&CrossPointSettings::sideButtonLayout,
{"Prev, Next", "Next, Prev"}},
{"Reader Font Family", SettingType::ENUM, &CrossPointSettings::fontFamily, {"Aleo", "Noto Sans", "Open Dyslexic"}},
{"Reader Font Size", SettingType::ENUM, &CrossPointSettings::fontSize, {"Small", "Medium", "Large", "X Large"}},
{"Check for updates", SettingType::ACTION, nullptr, {}},
};
} // namespace
@@ -157,7 +159,7 @@ void SettingsActivity::render() const {
const auto pageHeight = renderer.getScreenHeight();
// Draw header
renderer.drawCenteredText(READER_FONT_ID, 10, "Settings", true, BOLD);
renderer.drawCenteredText(UI_12_FONT_ID, 10, "Settings", true, BOLD);
// Draw selection
renderer.fillRect(0, 60 + selectedSettingIndex * 30 - 2, pageWidth - 1, 30);
@@ -168,11 +170,11 @@ void SettingsActivity::render() const {
// Draw selection indicator for the selected setting
if (i == selectedSettingIndex) {
renderer.drawText(UI_FONT_ID, 5, settingY, ">");
renderer.drawText(UI_10_FONT_ID, 5, settingY, ">");
}
// Draw setting name
renderer.drawText(UI_FONT_ID, 20, settingY, settingsList[i].name, i != selectedSettingIndex);
renderer.drawText(UI_10_FONT_ID, 20, settingY, settingsList[i].name, i != selectedSettingIndex);
// Draw value based on setting type
std::string valueText = "";
@@ -183,8 +185,8 @@ void SettingsActivity::render() const {
const uint8_t value = SETTINGS.*(settingsList[i].valuePtr);
valueText = settingsList[i].enumValues[value];
}
const auto width = renderer.getTextWidth(UI_FONT_ID, valueText.c_str());
renderer.drawText(UI_FONT_ID, pageWidth - 20 - width, settingY, valueText.c_str(), i != selectedSettingIndex);
const auto width = renderer.getTextWidth(UI_10_FONT_ID, valueText.c_str());
renderer.drawText(UI_10_FONT_ID, pageWidth - 20 - width, settingY, valueText.c_str(), i != selectedSettingIndex);
}
// Draw version text above button hints
@@ -193,7 +195,7 @@ void SettingsActivity::render() const {
// Draw help text
const auto labels = mappedInput.mapLabels("« Save", "Toggle", "", "");
renderer.drawButtonHints(UI_FONT_ID, labels.btn1, labels.btn2, labels.btn3, labels.btn4);
renderer.drawButtonHints(UI_10_FONT_ID, labels.btn1, labels.btn2, labels.btn3, labels.btn4);
// Always use standard refresh for settings screen
renderer.displayBuffer();

View File

@@ -2,15 +2,15 @@
#include <GfxRenderer.h>
#include "config.h"
#include "fontIds.h"
void FullScreenMessageActivity::onEnter() {
Activity::onEnter();
const auto height = renderer.getLineHeight(UI_FONT_ID);
const auto height = renderer.getLineHeight(UI_10_FONT_ID);
const auto top = (renderer.getScreenHeight() - height) / 2;
renderer.clearScreen();
renderer.drawCenteredText(UI_FONT_ID, top, text.c_str(), true, style);
renderer.drawCenteredText(UI_10_FONT_ID, top, text.c_str(), true, style);
renderer.displayBuffer(refreshMode);
}

View File

@@ -1,7 +1,7 @@
#include "KeyboardEntryActivity.h"
#include "../../config.h"
#include "MappedInputManager.h"
#include "fontIds.h"
// Keyboard layouts - lowercase
const char* const KeyboardEntryActivity::keyboard[NUM_ROWS] = {
@@ -241,11 +241,11 @@ void KeyboardEntryActivity::render() const {
renderer.clearScreen();
// Draw title
renderer.drawCenteredText(UI_FONT_ID, startY, title.c_str(), true, REGULAR);
renderer.drawCenteredText(UI_10_FONT_ID, startY, title.c_str());
// Draw input field
const int inputY = startY + 22;
renderer.drawText(UI_FONT_ID, 10, inputY, "[");
renderer.drawText(UI_10_FONT_ID, 10, inputY, "[");
std::string displayText;
if (isPassword) {
@@ -258,15 +258,15 @@ void KeyboardEntryActivity::render() const {
displayText += "_";
// Truncate if too long for display - use actual character width from font
int approxCharWidth = renderer.getSpaceWidth(UI_FONT_ID);
int approxCharWidth = renderer.getSpaceWidth(UI_10_FONT_ID);
if (approxCharWidth < 1) approxCharWidth = 8; // Fallback to approximate width
const int maxDisplayLen = (pageWidth - 40) / approxCharWidth;
if (displayText.length() > static_cast<size_t>(maxDisplayLen)) {
displayText = "..." + displayText.substr(displayText.length() - maxDisplayLen + 3);
}
renderer.drawText(UI_FONT_ID, 20, inputY, displayText.c_str());
renderer.drawText(UI_FONT_ID, pageWidth - 15, inputY, "]");
renderer.drawText(UI_10_FONT_ID, 20, inputY, displayText.c_str());
renderer.drawText(UI_10_FONT_ID, pageWidth - 15, inputY, "]");
// Draw keyboard - use compact spacing to fit 5 rows on screen
const int keyboardStartY = inputY + 25;
@@ -300,7 +300,7 @@ void KeyboardEntryActivity::render() const {
// Space bar (logical cols 2-6, spans 5 key widths)
const bool spaceSelected = (selectedRow == 4 && selectedCol >= SPACE_COL && selectedCol < BACKSPACE_COL);
const int spaceTextWidth = renderer.getTextWidth(UI_FONT_ID, "_____");
const int spaceTextWidth = renderer.getTextWidth(UI_10_FONT_ID, "_____");
const int spaceXWidth = 5 * (keyWidth + keySpacing);
const int spaceXPos = currentX + (spaceXWidth - spaceTextWidth) / 2;
renderItemWithSelector(spaceXPos, rowY, "_____", spaceSelected);
@@ -320,7 +320,7 @@ void KeyboardEntryActivity::render() const {
// Get the character to display
const char c = layout[row][col];
std::string keyLabel(1, c);
const int charWidth = renderer.getTextWidth(UI_FONT_ID, keyLabel.c_str());
const int charWidth = renderer.getTextWidth(UI_10_FONT_ID, keyLabel.c_str());
const int keyX = startX + col * (keyWidth + keySpacing) + (keyWidth - charWidth) / 2;
const bool isSelected = row == selectedRow && col == selectedCol;
@@ -338,9 +338,9 @@ void KeyboardEntryActivity::render() const {
void KeyboardEntryActivity::renderItemWithSelector(const int x, const int y, const char* item,
const bool isSelected) const {
if (isSelected) {
const int itemWidth = renderer.getTextWidth(UI_FONT_ID, item);
renderer.drawText(UI_FONT_ID, x - 6, y, "[");
renderer.drawText(UI_FONT_ID, x + itemWidth, y, "]");
const int itemWidth = renderer.getTextWidth(UI_10_FONT_ID, item);
renderer.drawText(UI_10_FONT_ID, x - 6, y, "[");
renderer.drawText(UI_10_FONT_ID, x + itemWidth, y, "]");
}
renderer.drawText(UI_FONT_ID, x, y, item);
renderer.drawText(UI_10_FONT_ID, x, y, item);
}

View File

@@ -1,29 +0,0 @@
#pragma once
/**
* Generated with:
* ruby -rdigest -e 'puts [
* "./lib/EpdFont/builtinFonts/bookerly_2b.h",
* "./lib/EpdFont/builtinFonts/bookerly_bold_2b.h",
* "./lib/EpdFont/builtinFonts/bookerly_bold_italic_2b.h",
* "./lib/EpdFont/builtinFonts/bookerly_italic_2b.h",
* ].map{|f| Digest::SHA256.hexdigest(File.read(f)).to_i(16) }.sum % (2 ** 32) - (2 ** 31)'
*/
#define READER_FONT_ID 1818981670
/**
* Generated with:
* ruby -rdigest -e 'puts [
* "./lib/EpdFont/builtinFonts/ubuntu_10.h",
* "./lib/EpdFont/builtinFonts/ubuntu_bold_10.h",
* ].map{|f| Digest::SHA256.hexdigest(File.read(f)).to_i(16) }.sum % (2 ** 32) - (2 ** 31)'
*/
#define UI_FONT_ID (-1619831379)
/**
* Generated with:
* ruby -rdigest -e 'puts [
* "./lib/EpdFont/builtinFonts/pixelarial14.h",
* ].map{|f| Digest::SHA256.hexdigest(File.read(f)).to_i(16) }.sum % (2 ** 32) - (2 ** 31)'
*/
#define SMALL_FONT_ID 1482513144

18
src/fontIds.h Normal file
View File

@@ -0,0 +1,18 @@
// The contents of this file are generated by ./lib/EpdFont/scripts/build-font-ids.sh
#pragma once
#define ALEO_12_FONT_ID (2101191384)
#define ALEO_14_FONT_ID (-1834656672)
#define ALEO_16_FONT_ID (-1982848762)
#define ALEO_18_FONT_ID (-365302307)
#define NOTOSANS_12_FONT_ID (-1646794343)
#define NOTOSANS_14_FONT_ID (-890242897)
#define NOTOSANS_16_FONT_ID (241925189)
#define NOTOSANS_18_FONT_ID (1503221336)
#define OPENDYSLEXIC_8_FONT_ID (875216341)
#define OPENDYSLEXIC_10_FONT_ID (-1234231183)
#define OPENDYSLEXIC_12_FONT_ID (1682200414)
#define OPENDYSLEXIC_14_FONT_ID (-1851285286)
#define UI_10_FONT_ID (-823541435)
#define UI_12_FONT_ID (-126318184)
#define SMALL_FONT_ID (-706443385)

View File

@@ -5,13 +5,7 @@
#include <InputManager.h>
#include <SDCardManager.h>
#include <SPI.h>
#include <builtinFonts/bookerly_2b.h>
#include <builtinFonts/bookerly_bold_2b.h>
#include <builtinFonts/bookerly_bold_italic_2b.h>
#include <builtinFonts/bookerly_italic_2b.h>
#include <builtinFonts/pixelarial14.h>
#include <builtinFonts/ubuntu_10.h>
#include <builtinFonts/ubuntu_bold_10.h>
#include <builtinFonts/all.h>
#include "Battery.h"
#include "CrossPointSettings.h"
@@ -24,7 +18,7 @@
#include "activities/reader/ReaderActivity.h"
#include "activities/settings/SettingsActivity.h"
#include "activities/util/FullScreenMessageActivity.h"
#include "config.h"
#include "fontIds.h"
#define SPI_FQ 40000000
// Display SPI pins (custom pins for XteinkX4, not hardware SPI defaults)
@@ -46,18 +40,87 @@ GfxRenderer renderer(einkDisplay);
Activity* currentActivity;
// Fonts
EpdFont bookerlyFont(&bookerly_2b);
EpdFont bookerlyBoldFont(&bookerly_bold_2b);
EpdFont bookerlyItalicFont(&bookerly_italic_2b);
EpdFont bookerlyBoldItalicFont(&bookerly_bold_italic_2b);
EpdFontFamily bookerlyFontFamily(&bookerlyFont, &bookerlyBoldFont, &bookerlyItalicFont, &bookerlyBoldItalicFont);
EpdFont aleo12RegularFont(&aleo_12_regular);
EpdFont aleo12BoldFont(&aleo_12_bold);
EpdFont aleo12ItalicFont(&aleo_12_italic);
EpdFont aleo12BoldItalicFont(&aleo_12_bolditalic);
EpdFontFamily aleo12FontFamily(&aleo12RegularFont, &aleo12BoldFont, &aleo12ItalicFont, &aleo12BoldItalicFont);
EpdFont aleo14RegularFont(&aleo_14_regular);
EpdFont aleo14BoldFont(&aleo_14_bold);
EpdFont aleo14ItalicFont(&aleo_14_italic);
EpdFont aleo14BoldItalicFont(&aleo_14_bolditalic);
EpdFontFamily aleo14FontFamily(&aleo14RegularFont, &aleo14BoldFont, &aleo14ItalicFont, &aleo14BoldItalicFont);
EpdFont aleo16RegularFont(&aleo_16_regular);
EpdFont aleo16BoldFont(&aleo_16_bold);
EpdFont aleo16ItalicFont(&aleo_16_italic);
EpdFont aleo16BoldItalicFont(&aleo_16_bolditalic);
EpdFontFamily aleo16FontFamily(&aleo16RegularFont, &aleo16BoldFont, &aleo16ItalicFont, &aleo16BoldItalicFont);
EpdFont aleo18RegularFont(&aleo_18_regular);
EpdFont aleo18BoldFont(&aleo_18_bold);
EpdFont aleo18ItalicFont(&aleo_18_italic);
EpdFont aleo18BoldItalicFont(&aleo_18_bolditalic);
EpdFontFamily aleo18FontFamily(&aleo18RegularFont, &aleo18BoldFont, &aleo18ItalicFont, &aleo18BoldItalicFont);
EpdFont smallFont(&pixelarial14);
EpdFont notosans12RegularFont(&notosans_12_regular);
EpdFont notosans12BoldFont(&notosans_12_bold);
EpdFont notosans12ItalicFont(&notosans_12_italic);
EpdFont notosans12BoldItalicFont(&notosans_12_bolditalic);
EpdFontFamily notosans12FontFamily(&notosans12RegularFont, &notosans12BoldFont, &notosans12ItalicFont,
&notosans12BoldItalicFont);
EpdFont notosans14RegularFont(&notosans_14_regular);
EpdFont notosans14BoldFont(&notosans_14_bold);
EpdFont notosans14ItalicFont(&notosans_14_italic);
EpdFont notosans14BoldItalicFont(&notosans_14_bolditalic);
EpdFontFamily notosans14FontFamily(&notosans14RegularFont, &notosans14BoldFont, &notosans14ItalicFont,
&notosans14BoldItalicFont);
EpdFont notosans16RegularFont(&notosans_16_regular);
EpdFont notosans16BoldFont(&notosans_16_bold);
EpdFont notosans16ItalicFont(&notosans_16_italic);
EpdFont notosans16BoldItalicFont(&notosans_16_bolditalic);
EpdFontFamily notosans16FontFamily(&notosans16RegularFont, &notosans16BoldFont, &notosans16ItalicFont,
&notosans16BoldItalicFont);
EpdFont notosans18RegularFont(&notosans_18_regular);
EpdFont notosans18BoldFont(&notosans_18_bold);
EpdFont notosans18ItalicFont(&notosans_18_italic);
EpdFont notosans18BoldItalicFont(&notosans_18_bolditalic);
EpdFontFamily notosans18FontFamily(&notosans18RegularFont, &notosans18BoldFont, &notosans18ItalicFont,
&notosans18BoldItalicFont);
EpdFont opendyslexic8RegularFont(&opendyslexic_8_regular);
EpdFont opendyslexic8BoldFont(&opendyslexic_8_bold);
EpdFont opendyslexic8ItalicFont(&opendyslexic_8_italic);
EpdFont opendyslexic8BoldItalicFont(&opendyslexic_8_bolditalic);
EpdFontFamily opendyslexic8FontFamily(&opendyslexic8RegularFont, &opendyslexic8BoldFont, &opendyslexic8ItalicFont,
&opendyslexic8BoldItalicFont);
EpdFont opendyslexic10RegularFont(&opendyslexic_10_regular);
EpdFont opendyslexic10BoldFont(&opendyslexic_10_bold);
EpdFont opendyslexic10ItalicFont(&opendyslexic_10_italic);
EpdFont opendyslexic10BoldItalicFont(&opendyslexic_10_bolditalic);
EpdFontFamily opendyslexic10FontFamily(&opendyslexic10RegularFont, &opendyslexic10BoldFont, &opendyslexic10ItalicFont,
&opendyslexic10BoldItalicFont);
EpdFont opendyslexic12RegularFont(&opendyslexic_12_regular);
EpdFont opendyslexic12BoldFont(&opendyslexic_12_bold);
EpdFont opendyslexic12ItalicFont(&opendyslexic_12_italic);
EpdFont opendyslexic12BoldItalicFont(&opendyslexic_12_bolditalic);
EpdFontFamily opendyslexic12FontFamily(&opendyslexic12RegularFont, &opendyslexic12BoldFont, &opendyslexic12ItalicFont,
&opendyslexic12BoldItalicFont);
EpdFont opendyslexic14RegularFont(&opendyslexic_14_regular);
EpdFont opendyslexic14BoldFont(&opendyslexic_14_bold);
EpdFont opendyslexic14ItalicFont(&opendyslexic_14_italic);
EpdFont opendyslexic14BoldItalicFont(&opendyslexic_14_bolditalic);
EpdFontFamily opendyslexic14FontFamily(&opendyslexic14RegularFont, &opendyslexic14BoldFont, &opendyslexic14ItalicFont,
&opendyslexic14BoldItalicFont);
EpdFont smallFont(&spacegrotesk);
EpdFontFamily smallFontFamily(&smallFont);
EpdFont ubuntu10Font(&ubuntu_10);
EpdFont ubuntuBold10Font(&ubuntu_bold_10);
EpdFontFamily ubuntuFontFamily(&ubuntu10Font, &ubuntuBold10Font);
EpdFont ui10RegularFont(&ubuntu_10_regular);
EpdFont ui10BoldFont(&ubuntu_10_bold);
EpdFontFamily ui10FontFamily(&ui10RegularFont, &ui10BoldFont);
EpdFont ui12RegularFont(&ubuntu_12_regular);
EpdFont ui12BoldFont(&ubuntu_12_bold);
EpdFontFamily ui12FontFamily(&ui12RegularFont, &ui12BoldFont);
// Auto-sleep timeout (10 minutes of inactivity)
constexpr unsigned long AUTO_SLEEP_TIMEOUT_MS = 10 * 60 * 1000;
@@ -164,8 +227,20 @@ void onGoHome() {
void setupDisplayAndFonts() {
einkDisplay.begin();
Serial.printf("[%lu] [ ] Display initialized\n", millis());
renderer.insertFont(READER_FONT_ID, bookerlyFontFamily);
renderer.insertFont(UI_FONT_ID, ubuntuFontFamily);
renderer.insertFont(ALEO_12_FONT_ID, aleo12FontFamily);
renderer.insertFont(ALEO_14_FONT_ID, aleo14FontFamily);
renderer.insertFont(ALEO_16_FONT_ID, aleo16FontFamily);
renderer.insertFont(ALEO_18_FONT_ID, aleo18FontFamily);
renderer.insertFont(NOTOSANS_12_FONT_ID, notosans12FontFamily);
renderer.insertFont(NOTOSANS_14_FONT_ID, notosans14FontFamily);
renderer.insertFont(NOTOSANS_16_FONT_ID, notosans16FontFamily);
renderer.insertFont(NOTOSANS_18_FONT_ID, notosans18FontFamily);
renderer.insertFont(OPENDYSLEXIC_8_FONT_ID, opendyslexic8FontFamily);
renderer.insertFont(OPENDYSLEXIC_10_FONT_ID, opendyslexic10FontFamily);
renderer.insertFont(OPENDYSLEXIC_12_FONT_ID, opendyslexic12FontFamily);
renderer.insertFont(OPENDYSLEXIC_14_FONT_ID, opendyslexic14FontFamily);
renderer.insertFont(UI_10_FONT_ID, ui10FontFamily);
renderer.insertFont(UI_12_FONT_ID, ui12FontFamily);
renderer.insertFont(SMALL_FONT_ID, smallFontFamily);
Serial.printf("[%lu] [ ] Fonts setup\n", millis());
}