Skip to content
74 changes: 74 additions & 0 deletions lib/GfxRenderer/GfxRenderer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -659,6 +659,80 @@ void GfxRenderer::displayBuffer(const HalDisplay::RefreshMode refreshMode) const
display.displayBuffer(refreshMode, fadingFix);
}

std::vector<std::string> GfxRenderer::wrappedText(
const int fontId,
const char* text,
const int maxWidth,
const int maxLines,
const EpdFontFamily::Style style) const
{
std::vector<std::string> lines;

if (!text || maxWidth <= 0 || maxLines <= 0)
return lines;

std::string remaining = text;
std::string currentLine;

while (!remaining.empty())
{
if ((int)lines.size() == maxLines - 1)
{
std::string lastLine = truncatedText(fontId, remaining.c_str(), maxWidth, style);
lines.push_back(lastLine);
return lines;
}

// Find next word
size_t spacePos = remaining.find(' ');
std::string word;

if (spacePos == std::string::npos)
{
word = remaining;
remaining.clear();
}
else
{
word = remaining.substr(0, spacePos);
remaining.erase(0, spacePos + 1);
}

std::string testLine = currentLine.empty()
? word
: currentLine + " " + word;

if (getTextWidth(fontId, testLine.c_str(), style) <= maxWidth)
{
currentLine = testLine;
}
else
{
if (!currentLine.empty())
{
lines.push_back(currentLine);
currentLine = word;
}
else
{
// If a single word longer than maxWidth, we will truncate it and return
// this is to avoid complicated splitting rules since they are different
// between languages. This results in an aesthetically pleasing end.
std::string truncated = truncatedText(fontId, word.c_str(), maxWidth, style);
lines.push_back(truncated);
return lines;
}
}
}

if (!currentLine.empty() && (int)lines.size() < maxLines)
{
lines.push_back(currentLine);
}

return lines;
}

std::string GfxRenderer::truncatedText(const int fontId, const char* text, const int maxWidth,
const EpdFontFamily::Style style) const {
if (!text || maxWidth <= 0) return "";
Expand Down
2 changes: 2 additions & 0 deletions lib/GfxRenderer/GfxRenderer.h
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,8 @@ class GfxRenderer {
std::string truncatedText(int fontId, const char* text, int maxWidth,
EpdFontFamily::Style style = EpdFontFamily::REGULAR) const;

std::vector<std::string> wrappedText(int fontId, const char* text, int maxWidth, int maxLines,
EpdFontFamily::Style style = EpdFontFamily::REGULAR) const;
// Helper for drawing rotated text (90 degrees clockwise, for side buttons)
void drawTextRotated90CW(int fontId, int x, int y, const char* text, bool black = true,
EpdFontFamily::Style style = EpdFontFamily::REGULAR) const;
Expand Down
2 changes: 1 addition & 1 deletion src/CrossPointSettings.h
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ class CrossPointSettings {
enum HIDE_BATTERY_PERCENTAGE { HIDE_NEVER = 0, HIDE_READER = 1, HIDE_ALWAYS = 2, HIDE_BATTERY_PERCENTAGE_COUNT };

// UI Theme
enum UI_THEME { CLASSIC = 0, LYRA = 1 };
enum UI_THEME { CLASSIC = 0, LYRA = 1, LYRA_3_COVERS = 2 };

// Sleep screen settings
uint8_t sleepScreen = DARK;
Expand Down
3 changes: 2 additions & 1 deletion src/SettingsList.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ inline std::vector<SettingInfo> getSettingsList() {
"hideBatteryPercentage", "Display"),
SettingInfo::Enum("Refresh Frequency", &CrossPointSettings::refreshFrequency,
{"1 page", "5 pages", "10 pages", "15 pages", "30 pages"}, "refreshFrequency", "Display"),
SettingInfo::Enum("UI Theme", &CrossPointSettings::uiTheme, {"Classic", "Lyra"}, "uiTheme", "Display"),
SettingInfo::Enum("UI Theme", &CrossPointSettings::uiTheme, {"Classic", "Lyra", "Lyra Extended"}, "uiTheme",
"Display"),
SettingInfo::Toggle("Sunlight Fading Fix", &CrossPointSettings::fadingFix, "fadingFix", "Display"),

// --- Reader ---
Expand Down
1 change: 0 additions & 1 deletion src/activities/home/MyLibraryActivity.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,6 @@ void MyLibraryActivity::loop() {
}

int listSize = static_cast<int>(files.size());

buttonNavigator.onNextRelease([this, listSize] {
selectorIndex = ButtonNavigator::nextIndex(static_cast<int>(selectorIndex), listSize);
updateRequired = true;
Expand Down
111 changes: 51 additions & 60 deletions src/activities/network/CalibreConnectActivity.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -201,75 +201,66 @@ void CalibreConnectActivity::displayTaskLoop() {
}

void CalibreConnectActivity::render() const {
if (state == CalibreConnectState::SERVER_RUNNING) {
renderer.clearScreen();
renderServerRunning();
renderer.displayBuffer();
if (subActivity) {
return;
}

renderer.clearScreen();
auto metrics = UITheme::getInstance().getMetrics();
const auto pageWidth = renderer.getScreenWidth();
const auto pageHeight = renderer.getScreenHeight();

renderer.clearScreen();

GUI.drawHeader(renderer, Rect{0, metrics.topPadding, pageWidth, metrics.headerHeight}, "Connect to Calibre");
const auto height = renderer.getLineHeight(UI_10_FONT_ID);
const auto top = (pageHeight - height) / 2;

if (state == CalibreConnectState::SERVER_STARTING) {
renderer.drawCenteredText(UI_12_FONT_ID, pageHeight / 2 - 20, "Starting Calibre...", true, EpdFontFamily::BOLD);
renderer.drawCenteredText(UI_12_FONT_ID, top, "Starting Calibre...");
} else if (state == CalibreConnectState::ERROR) {
renderer.drawCenteredText(UI_12_FONT_ID, pageHeight / 2 - 20, "Calibre setup failed", true, EpdFontFamily::BOLD);
}
renderer.displayBuffer();
}

void CalibreConnectActivity::renderServerRunning() const {
constexpr int LINE_SPACING = 24;
constexpr int SMALL_SPACING = 20;
constexpr int SECTION_SPACING = 40;
constexpr int TOP_PADDING = 14;
renderer.drawCenteredText(UI_12_FONT_ID, 15, "Connect to Calibre", true, EpdFontFamily::BOLD);

int y = 55 + TOP_PADDING;
renderer.drawCenteredText(UI_10_FONT_ID, y, "Network", true, EpdFontFamily::BOLD);
y += LINE_SPACING;
std::string ssidInfo = "Network: " + connectedSSID;
if (ssidInfo.length() > 28) {
ssidInfo.replace(25, ssidInfo.length() - 25, "...");
}
renderer.drawCenteredText(UI_10_FONT_ID, y, ssidInfo.c_str());
renderer.drawCenteredText(UI_10_FONT_ID, y + LINE_SPACING, ("IP: " + connectedIP).c_str());

y += LINE_SPACING * 2 + SECTION_SPACING;
renderer.drawCenteredText(UI_10_FONT_ID, y, "Setup", true, EpdFontFamily::BOLD);
y += LINE_SPACING;
renderer.drawCenteredText(SMALL_FONT_ID, y, "1) Install CrossPoint Reader plugin");
renderer.drawCenteredText(SMALL_FONT_ID, y + SMALL_SPACING, "2) Be on the same WiFi network");
renderer.drawCenteredText(SMALL_FONT_ID, y + SMALL_SPACING * 2, "3) In Calibre: \"Send to device\"");
renderer.drawCenteredText(SMALL_FONT_ID, y + SMALL_SPACING * 3, "Keep this screen open while sending");

y += SMALL_SPACING * 3 + SECTION_SPACING;
renderer.drawCenteredText(UI_10_FONT_ID, y, "Status", true, EpdFontFamily::BOLD);
y += LINE_SPACING;
if (lastProgressTotal > 0 && lastProgressReceived <= lastProgressTotal) {
std::string label = "Receiving";
if (!currentUploadName.empty()) {
label += ": " + currentUploadName;
if (label.length() > 34) {
label.replace(31, label.length() - 31, "...");
renderer.drawCenteredText(UI_12_FONT_ID, top, "Calibre setup failed", true, EpdFontFamily::BOLD);
} else if (state == CalibreConnectState::SERVER_RUNNING) {
GUI.drawSubHeader(renderer, Rect{0, metrics.topPadding + metrics.headerHeight, pageWidth, metrics.tabBarHeight},
connectedSSID.c_str(), ("IP: " + connectedIP).c_str());

int y = metrics.topPadding + metrics.headerHeight + metrics.tabBarHeight + metrics.verticalSpacing * 4;
const auto heightText12 = renderer.getTextHeight(UI_12_FONT_ID);
renderer.drawText(UI_12_FONT_ID, metrics.contentSidePadding, y, "Setup", true, EpdFontFamily::BOLD);
y += heightText12 + metrics.verticalSpacing * 2;

renderer.drawText(SMALL_FONT_ID, metrics.contentSidePadding, y, "1) Install CrossPoint Reader plugin");
renderer.drawText(SMALL_FONT_ID, metrics.contentSidePadding, y + height, "2) Be on the same WiFi network");
renderer.drawText(SMALL_FONT_ID, metrics.contentSidePadding, y + height * 2, "3) In Calibre: \"Send to device\"");
renderer.drawText(SMALL_FONT_ID, metrics.contentSidePadding, y + height * 3, "Keep this screen open while sending");

y += height * 3 + metrics.verticalSpacing * 4;
renderer.drawText(UI_12_FONT_ID, metrics.contentSidePadding, y, "Status", true, EpdFontFamily::BOLD);
y += heightText12 + metrics.verticalSpacing * 2;

if (lastProgressTotal > 0 && lastProgressReceived <= lastProgressTotal) {
std::string label = "Receiving";
if (!currentUploadName.empty()) {
label += ": " + currentUploadName;
label = renderer.truncatedText(SMALL_FONT_ID, label.c_str(), pageWidth - metrics.contentSidePadding * 2,
EpdFontFamily::REGULAR);
}
renderer.drawText(SMALL_FONT_ID, metrics.contentSidePadding, y, label.c_str());
GUI.drawProgressBar(renderer,
Rect{metrics.contentSidePadding, y + height + metrics.verticalSpacing,
pageWidth - metrics.contentSidePadding * 2, metrics.progressBarHeight},
lastProgressReceived, lastProgressTotal);
y += height + metrics.verticalSpacing * 2 + metrics.progressBarHeight;
}
renderer.drawCenteredText(SMALL_FONT_ID, y, label.c_str());
constexpr int barWidth = 300;
constexpr int barHeight = 16;
constexpr int barX = (480 - barWidth) / 2;
GUI.drawProgressBar(renderer, Rect{barX, y + 22, barWidth, barHeight}, lastProgressReceived, lastProgressTotal);
y += 40;
}

if (lastCompleteAt > 0 && (millis() - lastCompleteAt) < 6000) {
std::string msg = "Received: " + lastCompleteName;
if (msg.length() > 36) {
msg.replace(33, msg.length() - 33, "...");
if (lastCompleteAt > 0 && (millis() - lastCompleteAt) < 6000) {
std::string msg = "Received: " + lastCompleteName;
msg = renderer.truncatedText(SMALL_FONT_ID, msg.c_str(), pageWidth - metrics.contentSidePadding * 2,
EpdFontFamily::REGULAR);
renderer.drawText(SMALL_FONT_ID, metrics.contentSidePadding, y, msg.c_str());
}
renderer.drawCenteredText(SMALL_FONT_ID, y, msg.c_str());
}

const auto labels = mappedInput.mapLabels("« Exit", "", "", "");
GUI.drawButtonHints(renderer, labels.btn1, labels.btn2, labels.btn3, labels.btn4);
const auto labels = mappedInput.mapLabels("« Exit", "", "", "");
GUI.drawButtonHints(renderer, labels.btn1, labels.btn2, labels.btn3, labels.btn4);
}
renderer.displayBuffer();
}
Loading