feat: Lyra Icons (#725)
/!\ This PR depends on https://github.com/crosspoint-reader/crosspoint-reader/pull/732 being merged first Also requires the https://github.com/open-x4-epaper/community-sdk/pull/18 PR ## Summary Lyra theme icons on the home menu, in the file browser and on empty book covers     ## Additional Context - Added a function to the open-x4-sdk renderer to draw transparent images - Added a scripts/convert_icon.py script to convert svg/png icons into a C array that can be directly imported into the project. Usage: ```bash python ./scripts/convert_icon.py 'path/to/icon.png' cover 32 32 ``` This will create a components/icons/cover.h file with a C array called CoverIcon, of size 32x32px. Lyra uses icons from https://lucide.dev/icons with a stroke width of 2px, that can be downloaded with any desired size on the site. > The file browser is noticeably slower with the addition of icons, and using an image buffer like on the home page doesn't help very much. Any suggestions to optimize this are welcome. --- ### AI Usage While CrossPoint doesn't have restrictions on AI tools in contributing, please be transparent about their usage as it helps set the right context for reviewers. Did you use AI tools to help write this code? _**PARTIALLY**_ The icon conversion python script was generated by Copilot as I am not a python dev. --------- Co-authored-by: Dave Allie <dave@daveallie.com>
This commit is contained in:
@@ -419,7 +419,7 @@ void GfxRenderer::drawImage(const uint8_t bitmap[], const int x, const int y, co
|
||||
}
|
||||
|
||||
void GfxRenderer::drawIcon(const uint8_t bitmap[], const int x, const int y, const int width, const int height) const {
|
||||
display.drawImage(bitmap, y, getScreenWidth() - width - x, height, width);
|
||||
display.drawImageTransparent(bitmap, y, getScreenWidth() - width - x, height, width);
|
||||
}
|
||||
|
||||
void GfxRenderer::drawBitmap(const Bitmap& bitmap, const int x, const int y, const int maxWidth, const int maxHeight,
|
||||
|
||||
@@ -16,6 +16,11 @@ void HalDisplay::drawImage(const uint8_t* imageData, uint16_t x, uint16_t y, uin
|
||||
einkDisplay.drawImage(imageData, x, y, w, h, fromProgmem);
|
||||
}
|
||||
|
||||
void HalDisplay::drawImageTransparent(const uint8_t* imageData, uint16_t x, uint16_t y, uint16_t w, uint16_t h,
|
||||
bool fromProgmem) const {
|
||||
einkDisplay.drawImageTransparent(imageData, x, y, w, h, fromProgmem);
|
||||
}
|
||||
|
||||
EInkDisplay::RefreshMode convertRefreshMode(HalDisplay::RefreshMode mode) {
|
||||
switch (mode) {
|
||||
case HalDisplay::FULL_REFRESH:
|
||||
|
||||
@@ -30,6 +30,8 @@ class HalDisplay {
|
||||
void clearScreen(uint8_t color = 0xFF) const;
|
||||
void drawImage(const uint8_t* imageData, uint16_t x, uint16_t y, uint16_t w, uint16_t h,
|
||||
bool fromProgmem = false) const;
|
||||
void drawImageTransparent(const uint8_t* imageData, uint16_t x, uint16_t y, uint16_t w, uint16_t h,
|
||||
bool fromProgmem = false) const;
|
||||
|
||||
void displayBuffer(RefreshMode mode = RefreshMode::FAST_REFRESH, bool turnOffScreen = false);
|
||||
void refreshDisplay(RefreshMode mode = RefreshMode::FAST_REFRESH, bool turnOffScreen = false);
|
||||
|
||||
80
scripts/convert_icon.py
Normal file
80
scripts/convert_icon.py
Normal file
@@ -0,0 +1,80 @@
|
||||
import sys
|
||||
import os
|
||||
from PIL import Image
|
||||
import cairosvg
|
||||
import io
|
||||
|
||||
threshold = 128
|
||||
|
||||
def svg_to_png_bytes(svg_path, width, height):
|
||||
with open(svg_path, 'rb') as f:
|
||||
svg_data = f.read()
|
||||
png_bytes = cairosvg.svg2png(bytestring=svg_data, output_width=width, output_height=height)
|
||||
return png_bytes
|
||||
|
||||
def load_image(path, width, height):
|
||||
ext = os.path.splitext(path)[1].lower()
|
||||
if ext == '.svg':
|
||||
png_bytes = svg_to_png_bytes(path, width, height)
|
||||
img = Image.open(io.BytesIO(png_bytes))
|
||||
else:
|
||||
img = Image.open(path)
|
||||
img = img.convert('RGBA')
|
||||
img = img.resize((width, height), Image.LANCZOS)
|
||||
# Flatten alpha: paste on white background
|
||||
background = Image.new('RGBA', img.size, (255, 255, 255, 255))
|
||||
background.paste(img, mask=img.split()[3])
|
||||
img = background
|
||||
# Rotate 90 degrees counterclockwise
|
||||
img = img.rotate(90, expand=True)
|
||||
return img
|
||||
|
||||
def image_to_c_array(img, array_name):
|
||||
# Convert to grayscale, then threshold to get white=1, black=0
|
||||
# Convert to grayscale
|
||||
img = img.convert('L')
|
||||
width, height = img.size
|
||||
pixels = list(img.getdata())
|
||||
packed = []
|
||||
for y in range(height):
|
||||
for x in range(0, width, 8):
|
||||
byte = 0
|
||||
for b in range(8):
|
||||
if x + b < width:
|
||||
v = pixels[y * width + x + b]
|
||||
# 1 for white, 0 for black
|
||||
bit = 1 if v >= threshold else 0
|
||||
byte |= (bit << (7 - b))
|
||||
packed.append(byte)
|
||||
# Format as C array
|
||||
c = f'#pragma once\n#include <cstdint>\n\n'
|
||||
c += f'// size: {width}x{height}\n'
|
||||
c += f'static const uint8_t {array_name}[] = {{\n '
|
||||
for i, v in enumerate(packed):
|
||||
c += f'0x{v:02X}, '
|
||||
if (i + 1) % 16 == 0:
|
||||
c += '\n '
|
||||
c = c.rstrip(', \n') + '\n};\n'
|
||||
return c
|
||||
|
||||
def main():
|
||||
if len(sys.argv) < 5:
|
||||
print('Usage: python convert_image.py input.png output_name width height')
|
||||
sys.exit(1)
|
||||
input_path, output_name, width, height = sys.argv[1:5]
|
||||
array_name = output_name.capitalize() + 'Icon'
|
||||
width, height = int(width), int(height)
|
||||
img = load_image(input_path, width, height)
|
||||
c_array = image_to_c_array(img, array_name)
|
||||
|
||||
# Always save to src/components/icons/[output_name].h relative to project root
|
||||
project_root = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||
output_dir = os.path.join(project_root, 'src', 'components', 'icons')
|
||||
os.makedirs(output_dir, exist_ok=True)
|
||||
output_path = os.path.join(output_dir, f'{output_name}.h')
|
||||
with open(output_path, 'w') as f:
|
||||
f.write(c_array)
|
||||
print(f'Wrote {output_path}')
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -229,9 +229,12 @@ void HomeActivity::render(Activity::RenderLock&&) {
|
||||
// Build menu items dynamically
|
||||
std::vector<const char*> menuItems = {tr(STR_BROWSE_FILES), tr(STR_MENU_RECENT_BOOKS), tr(STR_FILE_TRANSFER),
|
||||
tr(STR_SETTINGS_TITLE)};
|
||||
std::vector<UIIcon> menuIcons = {Folder, Recent, Transfer, Settings};
|
||||
|
||||
if (hasOpdsUrl) {
|
||||
// Insert OPDS Browser after My Library
|
||||
menuItems.insert(menuItems.begin() + 2, tr(STR_OPDS_BROWSER));
|
||||
menuIcons.insert(menuIcons.begin() + 2, Library);
|
||||
}
|
||||
|
||||
GUI.drawButtonMenu(
|
||||
@@ -240,7 +243,8 @@ void HomeActivity::render(Activity::RenderLock&&) {
|
||||
pageHeight - (metrics.headerHeight + metrics.homeTopPadding + metrics.verticalSpacing * 2 +
|
||||
metrics.buttonHintsHeight)},
|
||||
static_cast<int>(menuItems.size()), selectorIndex - recentBooks.size(),
|
||||
[&menuItems](int index) { return std::string(menuItems[index]); }, nullptr);
|
||||
[&menuItems](int index) { return std::string(menuItems[index]); },
|
||||
[&menuIcons](int index) { return menuIcons[index]; });
|
||||
|
||||
const auto labels = mappedInput.mapLabels("", tr(STR_SELECT), tr(STR_DIR_UP), tr(STR_DIR_DOWN));
|
||||
GUI.drawButtonHints(renderer, labels.btn1, labels.btn2, labels.btn3, labels.btn4);
|
||||
|
||||
@@ -188,6 +188,14 @@ void MyLibraryActivity::loop() {
|
||||
});
|
||||
}
|
||||
|
||||
std::string getFileName(std::string filename) {
|
||||
if (filename.back() == '/') {
|
||||
return filename.substr(0, filename.length() - 1);
|
||||
}
|
||||
const auto pos = filename.rfind('.');
|
||||
return filename.substr(0, pos);
|
||||
}
|
||||
|
||||
void MyLibraryActivity::render(Activity::RenderLock&&) {
|
||||
renderer.clearScreen();
|
||||
|
||||
@@ -205,7 +213,8 @@ void MyLibraryActivity::render(Activity::RenderLock&&) {
|
||||
} else {
|
||||
GUI.drawList(
|
||||
renderer, Rect{0, contentTop, pageWidth, contentHeight}, files.size(), selectorIndex,
|
||||
[this](int index) { return files[index]; }, nullptr, nullptr, nullptr);
|
||||
[this](int index) { return getFileName(files[index]); }, nullptr,
|
||||
[this](int index) { return UITheme::getFileIcon(files[index]); });
|
||||
}
|
||||
|
||||
// Help text
|
||||
|
||||
@@ -102,7 +102,7 @@ void RecentBooksActivity::render(Activity::RenderLock&&) {
|
||||
GUI.drawList(
|
||||
renderer, Rect{0, contentTop, pageWidth, contentHeight}, recentBooks.size(), selectorIndex,
|
||||
[this](int index) { return recentBooks[index].title; }, [this](int index) { return recentBooks[index].author; },
|
||||
nullptr, nullptr);
|
||||
[this](int index) { return UITheme::getFileIcon(recentBooks[index].path); });
|
||||
}
|
||||
|
||||
// Help text
|
||||
|
||||
@@ -70,11 +70,12 @@ void NetworkModeSelectionActivity::render(Activity::RenderLock&&) {
|
||||
StrId::STR_CREATE_HOTSPOT};
|
||||
static constexpr StrId menuDescs[MENU_ITEM_COUNT] = {StrId::STR_JOIN_DESC, StrId::STR_CALIBRE_DESC,
|
||||
StrId::STR_HOTSPOT_DESC};
|
||||
static constexpr UIIcon menuIcons[MENU_ITEM_COUNT] = {UIIcon::Wifi, UIIcon::Library, UIIcon::Hotspot};
|
||||
|
||||
GUI.drawList(
|
||||
renderer, Rect{0, contentTop, pageWidth, contentHeight}, static_cast<int>(MENU_ITEM_COUNT), selectedIndex,
|
||||
[](int index) { return std::string(I18N.get(menuItems[index])); },
|
||||
[](int index) { return std::string(I18N.get(menuDescs[index])); });
|
||||
[](int index) { return std::string(I18N.get(menuDescs[index])); }, [](int index) { return menuIcons[index]; });
|
||||
|
||||
// Draw help text at bottom
|
||||
const auto labels = mappedInput.mapLabels(tr(STR_BACK), tr(STR_SELECT), tr(STR_DIR_UP), tr(STR_DIR_DOWN));
|
||||
|
||||
@@ -5,10 +5,16 @@
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "MappedInputManager.h"
|
||||
#include "RecentBooksStore.h"
|
||||
#include "components/themes/BaseTheme.h"
|
||||
#include "components/themes/lyra/Lyra3CoversTheme.h"
|
||||
#include "components/themes/lyra/LyraTheme.h"
|
||||
#include "util/StringUtils.h"
|
||||
|
||||
namespace {
|
||||
constexpr int SKIP_PAGE_MS = 700;
|
||||
} // namespace
|
||||
|
||||
UITheme UITheme::instance;
|
||||
|
||||
@@ -67,3 +73,20 @@ std::string UITheme::getCoverThumbPath(std::string coverBmpPath, int coverHeight
|
||||
}
|
||||
return coverBmpPath;
|
||||
}
|
||||
|
||||
UIIcon UITheme::getFileIcon(std::string filename) {
|
||||
if (filename.back() == '/') {
|
||||
return Folder;
|
||||
}
|
||||
if (StringUtils::checkFileExtension(filename, ".epub") || StringUtils::checkFileExtension(filename, ".xtch") ||
|
||||
StringUtils::checkFileExtension(filename, ".xtc")) {
|
||||
return Book;
|
||||
}
|
||||
if (StringUtils::checkFileExtension(filename, ".txt") || StringUtils::checkFileExtension(filename, ".md")) {
|
||||
return Text;
|
||||
}
|
||||
if (StringUtils::checkFileExtension(filename, ".bmp")) {
|
||||
return Image;
|
||||
}
|
||||
return File;
|
||||
}
|
||||
@@ -5,6 +5,8 @@
|
||||
#include "CrossPointSettings.h"
|
||||
#include "components/themes/BaseTheme.h"
|
||||
|
||||
class MappedInputManager;
|
||||
|
||||
class UITheme {
|
||||
// Static instance
|
||||
static UITheme instance;
|
||||
@@ -20,6 +22,7 @@ class UITheme {
|
||||
static int getNumberOfItemsPerPage(const GfxRenderer& renderer, bool hasHeader, bool hasTabBar, bool hasButtonHints,
|
||||
bool hasSubtitle);
|
||||
static std::string getCoverThumbPath(std::string coverBmpPath, int coverHeight);
|
||||
static UIIcon getFileIcon(std::string filename);
|
||||
|
||||
private:
|
||||
const ThemeMetrics* currentMetrics;
|
||||
|
||||
12
src/components/icons/book.h
Normal file
12
src/components/icons/book.h
Normal file
@@ -0,0 +1,12 @@
|
||||
#pragma once
|
||||
#include <cstdint>
|
||||
|
||||
// size: 32x32
|
||||
static const uint8_t BookIcon[] = {
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00,
|
||||
0x07, 0xC0, 0x00, 0x00, 0x03, 0xCF, 0xFF, 0xF8, 0xF3, 0xCF, 0xFF, 0xFC, 0xF3, 0xCF, 0xFF, 0xFC, 0xF3, 0xCF, 0xFF,
|
||||
0xFC, 0xF3, 0xCF, 0xFF, 0xFC, 0xF3, 0xCF, 0xFF, 0xFC, 0xF3, 0xCF, 0xFF, 0xFC, 0xF3, 0xCF, 0xFF, 0xFC, 0xF3, 0xCF,
|
||||
0xFF, 0xFC, 0xF3, 0xCF, 0xFF, 0xFC, 0xF3, 0xCF, 0xFF, 0xFC, 0xF3, 0xCF, 0xFF, 0xFC, 0xF3, 0xCF, 0xFF, 0xFC, 0xF3,
|
||||
0xCF, 0xFF, 0xFC, 0xF3, 0xCF, 0xFF, 0xFC, 0xF3, 0xCF, 0xFF, 0xFC, 0xF3, 0xCF, 0xFF, 0xFC, 0xF3, 0xCF, 0xFF, 0xFC,
|
||||
0xF3, 0xCF, 0xFF, 0xFC, 0xF3, 0xC3, 0xFF, 0xFC, 0x23, 0xE0, 0x00, 0x00, 0x07, 0xF8, 0x00, 0x00, 0x1F, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
|
||||
9
src/components/icons/book24.h
Normal file
9
src/components/icons/book24.h
Normal file
@@ -0,0 +1,9 @@
|
||||
#pragma once
|
||||
#include <cstdint>
|
||||
|
||||
// size: 24x24
|
||||
static const uint8_t Book24Icon[] = {
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x00, 0x03, 0x80, 0x00, 0x01, 0x9F, 0xFF, 0x39,
|
||||
0x9F, 0xFF, 0x39, 0x9F, 0xFF, 0x39, 0x9F, 0xFF, 0x39, 0x9F, 0xFF, 0x39, 0x9F, 0xFF, 0x39, 0x9F, 0xFF, 0x39,
|
||||
0x9F, 0xFF, 0x39, 0x9F, 0xFF, 0x39, 0x9F, 0xFF, 0x39, 0x9F, 0xFF, 0x39, 0x9F, 0xFF, 0x39, 0x9F, 0xFF, 0x39,
|
||||
0x9F, 0xFF, 0x39, 0xC0, 0x00, 0x03, 0xE0, 0x00, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
|
||||
12
src/components/icons/cog.h
Normal file
12
src/components/icons/cog.h
Normal file
@@ -0,0 +1,12 @@
|
||||
#pragma once
|
||||
#include <cstdint>
|
||||
|
||||
// size: 32x32
|
||||
static const uint8_t CogIcon[] = {
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x7F, 0xFF, 0xFF, 0xBE, 0x7D, 0xFF, 0xFF, 0x1C, 0x38,
|
||||
0xFF, 0xFF, 0x80, 0x01, 0xFF, 0xFF, 0x82, 0x41, 0xFF, 0xFF, 0x0E, 0x70, 0xFF, 0xF6, 0x3E, 0x7C, 0x6F, 0xE0, 0x7E,
|
||||
0x7E, 0x07, 0xF0, 0xFE, 0x7F, 0x0F, 0xF8, 0xFE, 0x7F, 0x1F, 0xF9, 0xFE, 0x7F, 0x9F, 0xF9, 0xF8, 0x1F, 0x9F, 0xF3,
|
||||
0xF8, 0x1F, 0xCF, 0xC3, 0xF3, 0xCF, 0xC3, 0xC3, 0xF1, 0x8F, 0xC3, 0xF3, 0xE1, 0x87, 0xCF, 0xF9, 0xC0, 0x03, 0x9F,
|
||||
0xF9, 0x0E, 0x70, 0x9F, 0xF8, 0x3F, 0xFC, 0x1F, 0xF0, 0x7F, 0xFE, 0x0F, 0xE0, 0x7F, 0xFE, 0x07, 0xF6, 0x3F, 0xFC,
|
||||
0x6F, 0xFF, 0x0F, 0xF0, 0xFF, 0xFF, 0x83, 0xC1, 0xFF, 0xFF, 0x80, 0x01, 0xFF, 0xFF, 0x1C, 0x38, 0xFF, 0xFF, 0xBE,
|
||||
0x7D, 0xFF, 0xFF, 0xFE, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
|
||||
12
src/components/icons/cover.h
Normal file
12
src/components/icons/cover.h
Normal file
@@ -0,0 +1,12 @@
|
||||
#pragma once
|
||||
#include <cstdint>
|
||||
|
||||
// size: 32x32
|
||||
static const uint8_t CoverIcon[] = {
|
||||
0xFF, 0x00, 0x00, 0x1F, 0xFF, 0x00, 0x00, 0x1F, 0xFF, 0xFF, 0xFE, 0x1F, 0xE0, 0x00, 0x02, 0x1F, 0xE0, 0x00, 0x03,
|
||||
0x1F, 0xE0, 0x00, 0x03, 0x1F, 0xF0, 0x00, 0x01, 0x1F, 0xF0, 0x00, 0x01, 0x1F, 0xF0, 0x00, 0x01, 0x9F, 0xF8, 0x00,
|
||||
0x00, 0x9F, 0xF8, 0x00, 0x00, 0xDF, 0xFC, 0x00, 0x00, 0x6F, 0xFE, 0x00, 0x00, 0x3F, 0xFF, 0x00, 0x00, 0x1F, 0xFF,
|
||||
0x80, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x0F, 0xFF, 0x00, 0x00, 0x1F,
|
||||
0xFE, 0x00, 0x00, 0x3F, 0xFC, 0x00, 0x00, 0x6F, 0xF8, 0x00, 0x00, 0xDF, 0xF8, 0x00, 0x00, 0x9F, 0xF0, 0x00, 0x01,
|
||||
0x9F, 0xF0, 0x00, 0x01, 0x1F, 0xE0, 0x00, 0x01, 0x1F, 0xE0, 0x00, 0x03, 0x1F, 0xE0, 0x00, 0x02, 0x1F, 0xE0, 0x00,
|
||||
0x02, 0x1F, 0xFF, 0xFF, 0xFE, 0x1F, 0xFF, 0x00, 0x00, 0x1F, 0xFF, 0x00, 0x00, 0x1F};
|
||||
9
src/components/icons/file24.h
Normal file
9
src/components/icons/file24.h
Normal file
@@ -0,0 +1,9 @@
|
||||
#pragma once
|
||||
#include <cstdint>
|
||||
|
||||
// size: 24x24
|
||||
static const uint8_t File24Icon[] = {
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x03, 0xF8, 0x00, 0x03, 0xF0, 0x7F, 0xF1,
|
||||
0xE2, 0x7F, 0xF9, 0xC6, 0x7F, 0xF9, 0x8E, 0x7F, 0xF9, 0x80, 0x7F, 0xF9, 0x80, 0xFF, 0xF9, 0x9F, 0xFF, 0xF9,
|
||||
0x9F, 0xFF, 0xF9, 0x9F, 0xFF, 0xF9, 0x9F, 0xFF, 0xF9, 0x9F, 0xFF, 0xF9, 0x9F, 0xFF, 0xF9, 0x9F, 0xFF, 0xF9,
|
||||
0x8F, 0xFF, 0xF1, 0xC0, 0x00, 0x01, 0xC0, 0x00, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
|
||||
12
src/components/icons/folder.h
Normal file
12
src/components/icons/folder.h
Normal file
@@ -0,0 +1,12 @@
|
||||
#pragma once
|
||||
#include <cstdint>
|
||||
|
||||
// size: 32x32
|
||||
static const uint8_t FolderIcon[] = {
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x1F, 0xFE, 0x00, 0x00, 0x1F, 0xFE, 0x3F, 0xFF,
|
||||
0x9F, 0xFE, 0x7F, 0xFF, 0xCF, 0xFE, 0x7F, 0xFF, 0xCF, 0xFE, 0x7F, 0xFF, 0xCF, 0xFE, 0x7F, 0xFF, 0xCF, 0xFE, 0x7F,
|
||||
0xFF, 0xCF, 0xFE, 0x7F, 0xFF, 0xCF, 0xFE, 0x7F, 0xFF, 0xCF, 0xFE, 0x7F, 0xFF, 0xCF, 0xFE, 0x7F, 0xFF, 0xCF, 0xFE,
|
||||
0x7F, 0xFF, 0xCF, 0xFE, 0x7F, 0xFF, 0xCF, 0xFE, 0x7F, 0xFF, 0xCF, 0xFC, 0x7F, 0xFF, 0xCF, 0xF0, 0xFF, 0xFF, 0xCF,
|
||||
0xE1, 0xFF, 0xFF, 0xCF, 0xE3, 0xFF, 0xFF, 0xCF, 0xE7, 0xFF, 0xFF, 0xCF, 0xE7, 0xFF, 0xFF, 0xCF, 0xE7, 0xFF, 0xFF,
|
||||
0xCF, 0xE7, 0xFF, 0xFF, 0xCF, 0xE7, 0xFF, 0xFF, 0xCF, 0xE7, 0xFF, 0xFF, 0x8F, 0xE7, 0xFF, 0xFF, 0x8F, 0xF0, 0x00,
|
||||
0x00, 0x1F, 0xF0, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
|
||||
9
src/components/icons/folder24.h
Normal file
9
src/components/icons/folder24.h
Normal file
@@ -0,0 +1,9 @@
|
||||
#pragma once
|
||||
#include <cstdint>
|
||||
|
||||
// size: 24x24
|
||||
static const uint8_t Folder24Icon[] = {
|
||||
0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x1F, 0xFC, 0x00, 0x0F, 0xF9, 0xFF, 0xE7, 0xF9, 0xFF, 0xE7, 0xF9, 0xFF, 0xE7,
|
||||
0xF9, 0xFF, 0xE7, 0xF9, 0xFF, 0xE7, 0xF9, 0xFF, 0xE7, 0xF9, 0xFF, 0xE7, 0xF9, 0xFF, 0xE7, 0xF9, 0xFF, 0xE7,
|
||||
0xF9, 0xFF, 0xE7, 0xF3, 0xFF, 0xE7, 0xE7, 0xFF, 0xE7, 0xCF, 0xFF, 0xE7, 0xCF, 0xFF, 0xE7, 0xCF, 0xFF, 0xE7,
|
||||
0xCF, 0xFF, 0xE7, 0xCF, 0xFF, 0xE7, 0xCF, 0xFF, 0xE7, 0xE0, 0x00, 0x0F, 0xF0, 0x00, 0x1F, 0xFF, 0xFF, 0xFF};
|
||||
12
src/components/icons/hotspot.h
Normal file
12
src/components/icons/hotspot.h
Normal file
@@ -0,0 +1,12 @@
|
||||
#pragma once
|
||||
#include <cstdint>
|
||||
|
||||
// size: 32x32
|
||||
static const uint8_t HotspotIcon[] = {
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x07, 0xFF, 0xFF, 0x80, 0x01, 0xFF, 0xFE, 0x0F, 0xF0,
|
||||
0x7F, 0xFC, 0x3F, 0xFC, 0x3F, 0xFC, 0xFF, 0xFE, 0x3F, 0xFD, 0xF8, 0x1F, 0xBF, 0xFF, 0xE0, 0x07, 0xFF, 0xFF, 0xC3,
|
||||
0xC3, 0xFF, 0xFF, 0xCF, 0xF1, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x7F, 0xFF, 0xFF, 0xF8, 0x1F, 0xFF, 0xFF,
|
||||
0xF9, 0x9F, 0xFF, 0xFF, 0xF3, 0xCF, 0xFF, 0xFF, 0xF3, 0xCF, 0xFF, 0xFF, 0xF9, 0x9F, 0xFF, 0xFF, 0xF8, 0x1F, 0xFF,
|
||||
0xFF, 0xFE, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x8F, 0xF3, 0xFF, 0xFF, 0xC3, 0xC3, 0xFF, 0xFF, 0xE0, 0x07,
|
||||
0xFF, 0xFD, 0xF8, 0x1F, 0xBF, 0xFC, 0x7F, 0xFF, 0x3F, 0xFC, 0x3F, 0xFC, 0x3F, 0xFE, 0x0F, 0xF0, 0x7F, 0xFF, 0x80,
|
||||
0x01, 0xFF, 0xFF, 0xE0, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
|
||||
9
src/components/icons/image24.h
Normal file
9
src/components/icons/image24.h
Normal file
@@ -0,0 +1,9 @@
|
||||
#pragma once
|
||||
#include <cstdint>
|
||||
|
||||
// size: 24x24
|
||||
static const uint8_t Image24Icon[] = {
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x0F, 0xE0, 0x00, 0x07, 0xCF, 0xF1, 0xF3, 0xCF, 0xE3, 0xF3,
|
||||
0xCF, 0xE7, 0xF3, 0xCF, 0xEF, 0xF3, 0xCF, 0xE7, 0xF3, 0xCF, 0xE3, 0xF3, 0xCF, 0xF1, 0xF3, 0xCF, 0xF8, 0xF3,
|
||||
0xCF, 0x3C, 0x73, 0xCE, 0x1E, 0x33, 0xCC, 0xCF, 0x13, 0xCC, 0xCF, 0x83, 0xCE, 0x1F, 0xC3, 0xCF, 0x3F, 0xE3,
|
||||
0xCF, 0xFF, 0xF3, 0xCF, 0xFF, 0xF3, 0xE0, 0x00, 0x07, 0xF0, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
|
||||
12
src/components/icons/library.h
Normal file
12
src/components/icons/library.h
Normal file
@@ -0,0 +1,12 @@
|
||||
#pragma once
|
||||
#include <cstdint>
|
||||
|
||||
// size: 32x32
|
||||
static const uint8_t LibraryIcon[] = {
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE,
|
||||
0x1F, 0xFF, 0xFF, 0xF0, 0x0F, 0xFF, 0xFF, 0xC1, 0xCF, 0xFF, 0xFE, 0x07, 0xE7, 0xFF, 0xF0, 0x3F, 0xE7, 0xFF, 0x81,
|
||||
0xFF, 0x87, 0xFC, 0x0F, 0xFC, 0x0F, 0xF0, 0x3F, 0xF0, 0x3F, 0xE1, 0xFF, 0x81, 0xFF, 0xE7, 0xFC, 0x0F, 0xFF, 0xE7,
|
||||
0xE0, 0x7F, 0xFF, 0xF3, 0x83, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x1F, 0xE0, 0x00, 0x00, 0x07, 0xE7, 0xFF, 0xFF, 0xE7,
|
||||
0xE7, 0xFF, 0xFF, 0xE7, 0xE7, 0xFF, 0xFF, 0xE7, 0xE7, 0xFF, 0xFF, 0xE7, 0xE0, 0x00, 0x00, 0x07, 0xE0, 0x00, 0x00,
|
||||
0x07, 0xE7, 0xFF, 0xFF, 0xE7, 0xE7, 0xFF, 0xFF, 0xE7, 0xE7, 0xFF, 0xFF, 0xE7, 0xE0, 0x00, 0x00, 0x07, 0xF0, 0x00,
|
||||
0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
|
||||
12
src/components/icons/recent.h
Normal file
12
src/components/icons/recent.h
Normal file
@@ -0,0 +1,12 @@
|
||||
#pragma once
|
||||
#include <cstdint>
|
||||
|
||||
// size: 32x32
|
||||
static const uint8_t RecentIcon[] = {
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00,
|
||||
0x07, 0xC0, 0x00, 0x00, 0x03, 0xCF, 0xFF, 0xF8, 0xF3, 0xCF, 0xFF, 0xFC, 0xF3, 0xCF, 0xFF, 0xFC, 0xF3, 0xCF, 0xFF,
|
||||
0xFC, 0xF3, 0xC0, 0x03, 0xFC, 0xF3, 0xC0, 0x03, 0xFC, 0xF3, 0xCF, 0xC7, 0xFC, 0xF3, 0xCF, 0x8F, 0xFC, 0xF3, 0xCF,
|
||||
0x1F, 0xFC, 0xF3, 0xCF, 0x8F, 0xFC, 0xF3, 0xCF, 0x87, 0xFC, 0xF3, 0xCF, 0xC3, 0xFC, 0xF3, 0xC0, 0x03, 0xFC, 0xF3,
|
||||
0xC0, 0x03, 0xFC, 0xF3, 0xCF, 0xFF, 0xFC, 0xF3, 0xCF, 0xFF, 0xFC, 0xF3, 0xCF, 0xFF, 0xFC, 0xF3, 0xCF, 0xFF, 0xFC,
|
||||
0xF3, 0xCF, 0xFF, 0xFC, 0xF3, 0xC3, 0xFF, 0xFC, 0x23, 0xE0, 0x00, 0x00, 0x07, 0xF8, 0x00, 0x00, 0x1F, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
|
||||
12
src/components/icons/settings.h
Normal file
12
src/components/icons/settings.h
Normal file
@@ -0,0 +1,12 @@
|
||||
#pragma once
|
||||
#include <cstdint>
|
||||
|
||||
// size: 32x32
|
||||
static const uint8_t SettingsIcon[] = {
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x87, 0xE1, 0xFF, 0xFF, 0x03, 0xC0,
|
||||
0xFF, 0xFE, 0x30, 0x8C, 0x7F, 0xFE, 0x78, 0x1E, 0x7F, 0xFE, 0x7C, 0x7E, 0x7F, 0xFE, 0x7F, 0xFE, 0x7F, 0xFE, 0x7F,
|
||||
0xFE, 0x7F, 0xFE, 0x7F, 0xFE, 0x7F, 0xFC, 0x7C, 0x3E, 0x3F, 0xF0, 0xF0, 0x0F, 0x07, 0xC1, 0xF3, 0xCF, 0x83, 0xC7,
|
||||
0xE7, 0xE7, 0xE3, 0xCF, 0xE7, 0xE7, 0xF3, 0xCF, 0xE7, 0xE7, 0xF3, 0xC7, 0xE7, 0xE7, 0xE3, 0xC1, 0xF3, 0xCF, 0x83,
|
||||
0xE0, 0xF0, 0x0F, 0x0F, 0xFC, 0x7C, 0x3E, 0x3F, 0xFE, 0x7F, 0xFE, 0x7F, 0xFE, 0x7F, 0xFE, 0x7F, 0xFE, 0x7F, 0xFE,
|
||||
0x7F, 0xFE, 0x7E, 0x3E, 0x7F, 0xFE, 0x78, 0x1E, 0x7F, 0xFE, 0x31, 0x0C, 0x7F, 0xFF, 0x03, 0xC0, 0xFF, 0xFF, 0x87,
|
||||
0xE1, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
|
||||
12
src/components/icons/settings2.h
Normal file
12
src/components/icons/settings2.h
Normal file
@@ -0,0 +1,12 @@
|
||||
#pragma once
|
||||
#include <cstdint>
|
||||
|
||||
// size: 32x32
|
||||
static const uint8_t Settings2Icon[] = {
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8,
|
||||
0xFF, 0xFF, 0xFF, 0xE0, 0x3F, 0xFF, 0x3F, 0xE3, 0x1F, 0xFF, 0x3F, 0xCF, 0x9F, 0xFF, 0x3F, 0xCF, 0xCF, 0xFF, 0x3F,
|
||||
0xCF, 0xCF, 0xFF, 0x3F, 0xCF, 0x8F, 0xFF, 0x3F, 0xC7, 0x9F, 0xFF, 0x3F, 0xE0, 0x1F, 0xFF, 0x3F, 0xF0, 0x7F, 0xFF,
|
||||
0x3F, 0xFC, 0xFF, 0xFF, 0x3F, 0xFC, 0xFF, 0xFF, 0x3F, 0xFC, 0xFF, 0xFF, 0x3F, 0xFC, 0xFF, 0xFE, 0x0F, 0xFC, 0xFF,
|
||||
0xF8, 0x07, 0xFC, 0xFF, 0xF9, 0xE3, 0xFC, 0xFF, 0xF1, 0xF3, 0xFC, 0xFF, 0xF3, 0xF3, 0xFC, 0xFF, 0xF3, 0xF3, 0xFC,
|
||||
0xFF, 0xF9, 0xF3, 0xFC, 0xFF, 0xF8, 0xC7, 0xFC, 0xFF, 0xFC, 0x07, 0xFF, 0xFF, 0xFF, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
|
||||
9
src/components/icons/text24.h
Normal file
9
src/components/icons/text24.h
Normal file
@@ -0,0 +1,9 @@
|
||||
#pragma once
|
||||
#include <cstdint>
|
||||
|
||||
// size: 24x24
|
||||
static const uint8_t Text24Icon[] = {
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x07, 0xF8, 0x00, 0x03, 0xF0, 0x7F, 0xF9,
|
||||
0xE2, 0x7F, 0xF9, 0xC6, 0x73, 0x39, 0xCE, 0x73, 0x39, 0x80, 0x73, 0x39, 0x80, 0xF3, 0x39, 0x9F, 0xF3, 0x39,
|
||||
0x9F, 0xF3, 0x39, 0x9F, 0x33, 0x39, 0x9F, 0x33, 0x39, 0x9F, 0x33, 0x39, 0x9F, 0x33, 0x39, 0x9F, 0xFF, 0xF9,
|
||||
0x9F, 0xFF, 0xF9, 0xC0, 0x00, 0x03, 0xE0, 0x00, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
|
||||
12
src/components/icons/transfer.h
Normal file
12
src/components/icons/transfer.h
Normal file
@@ -0,0 +1,12 @@
|
||||
#pragma once
|
||||
#include <cstdint>
|
||||
|
||||
// size: 32x32
|
||||
static const uint8_t TransferIcon[] = {
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x3F, 0xFF, 0xFF, 0xFC, 0x3F, 0xFF, 0xFF, 0xF8, 0x3F,
|
||||
0xFF, 0xFF, 0xF8, 0x1F, 0xFF, 0xFF, 0xF0, 0x1F, 0xFF, 0xFF, 0xF0, 0x4F, 0xFF, 0xFF, 0xE2, 0x4F, 0xFF, 0xFF, 0xE2,
|
||||
0x47, 0xFF, 0xFF, 0xC6, 0x67, 0xFF, 0xFF, 0xC6, 0x63, 0xFF, 0xFF, 0xCE, 0x73, 0xFF, 0xFF, 0x8E, 0x71, 0xFF, 0xFF,
|
||||
0x9E, 0x79, 0xFF, 0xFF, 0x1E, 0x78, 0xFF, 0xFF, 0x3E, 0x7C, 0xFF, 0xFE, 0x3E, 0x7C, 0x7F, 0xFE, 0x3E, 0x7E, 0x7F,
|
||||
0xFC, 0x7E, 0x7E, 0x3F, 0xFC, 0x7E, 0x7F, 0x3F, 0xF8, 0xFE, 0x7F, 0x3F, 0xF8, 0xFE, 0x7F, 0x9F, 0xF1, 0xFC, 0x1F,
|
||||
0x9F, 0xF1, 0xE0, 0x07, 0xCF, 0xE3, 0x83, 0x80, 0xCF, 0xE0, 0x0F, 0xF0, 0x07, 0xE0, 0x7F, 0xFC, 0x07, 0xF3, 0xFF,
|
||||
0xFF, 0x8F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
|
||||
12
src/components/icons/wifi.h
Normal file
12
src/components/icons/wifi.h
Normal file
@@ -0,0 +1,12 @@
|
||||
#pragma once
|
||||
#include <cstdint>
|
||||
|
||||
// size: 32x32
|
||||
static const uint8_t WifiIcon[] = {
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC7, 0xFF, 0xFF, 0xFF, 0xC7, 0xFF, 0xFF, 0xFF, 0x8F, 0xFF,
|
||||
0xFF, 0xFF, 0x1F, 0xFF, 0xFF, 0xFF, 0x1F, 0x3F, 0xFF, 0xFE, 0x3E, 0x3F, 0xFF, 0xFE, 0x3C, 0x7F, 0xFF, 0xFE, 0x7C,
|
||||
0x7F, 0xFF, 0xFC, 0x78, 0xFD, 0xFF, 0xFC, 0x78, 0xF1, 0xFF, 0xFC, 0xF9, 0xF1, 0xFF, 0xFC, 0xF1, 0xE3, 0xFF, 0xFC,
|
||||
0xF1, 0xE3, 0xFF, 0xFC, 0xF1, 0xE7, 0xDF, 0xFC, 0xF3, 0xE7, 0xDF, 0xFC, 0xF1, 0xE7, 0xFF, 0xFC, 0xF9, 0xE3, 0xFF,
|
||||
0xFC, 0xF9, 0xF3, 0xFF, 0xFC, 0xF9, 0xF1, 0xFF, 0xFC, 0x7C, 0xFB, 0xFF, 0xFE, 0x7C, 0xFF, 0xFF, 0xFE, 0x7C, 0x7F,
|
||||
0xFF, 0xFF, 0x3E, 0x3F, 0xFF, 0xFF, 0x3F, 0x3F, 0xFF, 0xFF, 0x1F, 0xFF, 0xFF, 0xFF, 0x8F, 0xFF, 0xFF, 0xFF, 0xCF,
|
||||
0xFF, 0xFF, 0xFF, 0xE7, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
|
||||
@@ -186,7 +186,7 @@ void BaseTheme::drawSideButtonHints(const GfxRenderer& renderer, const char* top
|
||||
void BaseTheme::drawList(const GfxRenderer& renderer, Rect rect, int itemCount, int selectedIndex,
|
||||
const std::function<std::string(int index)>& rowTitle,
|
||||
const std::function<std::string(int index)>& rowSubtitle,
|
||||
const std::function<std::string(int index)>& rowIcon,
|
||||
const std::function<UIIcon(int index)>& rowIcon,
|
||||
const std::function<std::string(int index)>& rowValue, bool highlightValue) const {
|
||||
int rowHeight =
|
||||
(rowSubtitle != nullptr) ? BaseMetrics::values.listWithSubtitleRowHeight : BaseMetrics::values.listRowHeight;
|
||||
@@ -635,7 +635,7 @@ void BaseTheme::drawRecentBookCover(GfxRenderer& renderer, Rect rect, const std:
|
||||
|
||||
void BaseTheme::drawButtonMenu(GfxRenderer& renderer, Rect rect, int buttonCount, int selectedIndex,
|
||||
const std::function<std::string(int index)>& buttonLabel,
|
||||
const std::function<std::string(int index)>& rowIcon) const {
|
||||
const std::function<UIIcon(int index)>& rowIcon) const {
|
||||
for (int i = 0; i < buttonCount; ++i) {
|
||||
const int tileY = BaseMetrics::values.verticalSpacing + rect.y +
|
||||
static_cast<int>(i) * (BaseMetrics::values.menuRowHeight + BaseMetrics::values.menuSpacing);
|
||||
@@ -727,4 +727,4 @@ void BaseTheme::drawKeyboardKey(const GfxRenderer& renderer, Rect rect, const ch
|
||||
renderer.drawText(UI_10_FONT_ID, textX + itemWidth, rect.y, "]");
|
||||
}
|
||||
renderer.drawText(UI_10_FONT_ID, textX, rect.y, label);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,6 +61,8 @@ struct ThemeMetrics {
|
||||
bool keyboardCenteredText;
|
||||
};
|
||||
|
||||
enum UIIcon { Folder, Text, Image, Book, File, Recent, Settings, Transfer, Library, Wifi, Hotspot };
|
||||
|
||||
// Default theme implementation (Classic Theme)
|
||||
// Additional themes can inherit from this and override methods as needed
|
||||
|
||||
@@ -111,7 +113,7 @@ class BaseTheme {
|
||||
virtual void drawList(const GfxRenderer& renderer, Rect rect, int itemCount, int selectedIndex,
|
||||
const std::function<std::string(int index)>& rowTitle,
|
||||
const std::function<std::string(int index)>& rowSubtitle = nullptr,
|
||||
const std::function<std::string(int index)>& rowIcon = nullptr,
|
||||
const std::function<UIIcon(int index)>& rowIcon = nullptr,
|
||||
const std::function<std::string(int index)>& rowValue = nullptr,
|
||||
bool highlightValue = false) const;
|
||||
virtual void drawHeader(const GfxRenderer& renderer, Rect rect, const char* title,
|
||||
@@ -125,11 +127,11 @@ class BaseTheme {
|
||||
bool& bufferRestored, std::function<bool()> storeCoverBuffer) const;
|
||||
virtual void drawButtonMenu(GfxRenderer& renderer, Rect rect, int buttonCount, int selectedIndex,
|
||||
const std::function<std::string(int index)>& buttonLabel,
|
||||
const std::function<std::string(int index)>& rowIcon) const;
|
||||
const std::function<UIIcon(int index)>& rowIcon) const;
|
||||
virtual Rect drawPopup(const GfxRenderer& renderer, const char* message) const;
|
||||
virtual void fillPopupProgress(const GfxRenderer& renderer, const Rect& layout, const int progress) const;
|
||||
virtual void drawReadingProgressBar(const GfxRenderer& renderer, const size_t bookProgress) 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;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -6,11 +6,10 @@
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
|
||||
#include "Battery.h"
|
||||
#include "RecentBooksStore.h"
|
||||
#include "components/UITheme.h"
|
||||
#include "components/icons/cover.h"
|
||||
#include "fontIds.h"
|
||||
#include "util/StringUtils.h"
|
||||
|
||||
// Internal constants
|
||||
namespace {
|
||||
@@ -67,8 +66,14 @@ void Lyra3CoversTheme::drawRecentBookCover(GfxRenderer& renderer, Rect rect, con
|
||||
}
|
||||
|
||||
if (!hasCover) {
|
||||
// Render empty cover
|
||||
renderer.drawRect(tileX + hPaddingInSelection, tileY + hPaddingInSelection,
|
||||
tileWidth - 2 * hPaddingInSelection, Lyra3CoversMetrics::values.homeCoverHeight);
|
||||
tileWidth - 2 * hPaddingInSelection, Lyra3CoversMetrics::values.homeCoverHeight, true);
|
||||
renderer.fillRect(tileX + hPaddingInSelection,
|
||||
tileY + hPaddingInSelection + (Lyra3CoversMetrics::values.homeCoverHeight / 3),
|
||||
tileWidth - 2 * hPaddingInSelection, 2 * Lyra3CoversMetrics::values.homeCoverHeight / 3,
|
||||
true);
|
||||
renderer.drawIcon(CoverIcon, tileX + hPaddingInSelection + 24, tileY + hPaddingInSelection + 24, 32, 32);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -101,4 +106,4 @@ void Lyra3CoversTheme::drawRecentBookCover(GfxRenderer& renderer, Rect rect, con
|
||||
} else {
|
||||
drawEmptyRecents(renderer, rect);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,8 +10,21 @@
|
||||
#include "Battery.h"
|
||||
#include "RecentBooksStore.h"
|
||||
#include "components/UITheme.h"
|
||||
#include "components/icons/book.h"
|
||||
#include "components/icons/book24.h"
|
||||
#include "components/icons/cover.h"
|
||||
#include "components/icons/file24.h"
|
||||
#include "components/icons/folder.h"
|
||||
#include "components/icons/folder24.h"
|
||||
#include "components/icons/hotspot.h"
|
||||
#include "components/icons/image24.h"
|
||||
#include "components/icons/library.h"
|
||||
#include "components/icons/recent.h"
|
||||
#include "components/icons/settings2.h"
|
||||
#include "components/icons/text24.h"
|
||||
#include "components/icons/transfer.h"
|
||||
#include "components/icons/wifi.h"
|
||||
#include "fontIds.h"
|
||||
#include "util/StringUtils.h"
|
||||
|
||||
// Internal constants
|
||||
namespace {
|
||||
@@ -23,7 +36,51 @@ constexpr int popupMarginX = 16;
|
||||
constexpr int popupMarginY = 12;
|
||||
constexpr int maxSubtitleWidth = 100;
|
||||
constexpr int maxListValueWidth = 200;
|
||||
constexpr int mainMenuIconSize = 32;
|
||||
constexpr int listIconSize = 24;
|
||||
constexpr int mainMenuColumns = 2;
|
||||
int coverWidth = 0;
|
||||
|
||||
const uint8_t* iconForName(UIIcon icon, int size) {
|
||||
if (size == 24) {
|
||||
switch (icon) {
|
||||
case UIIcon::Folder:
|
||||
return Folder24Icon;
|
||||
case UIIcon::Text:
|
||||
return Text24Icon;
|
||||
case UIIcon::Image:
|
||||
return Image24Icon;
|
||||
case UIIcon::Book:
|
||||
return Book24Icon;
|
||||
case UIIcon::File:
|
||||
return File24Icon;
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
} else if (size == 32) {
|
||||
switch (icon) {
|
||||
case UIIcon::Folder:
|
||||
return FolderIcon;
|
||||
case UIIcon::Book:
|
||||
return BookIcon;
|
||||
case UIIcon::Recent:
|
||||
return RecentIcon;
|
||||
case UIIcon::Settings:
|
||||
return Settings2Icon;
|
||||
case UIIcon::Transfer:
|
||||
return TransferIcon;
|
||||
case UIIcon::Library:
|
||||
return LibraryIcon;
|
||||
case UIIcon::Wifi:
|
||||
return WifiIcon;
|
||||
case UIIcon::Hotspot:
|
||||
return HotspotIcon;
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
void LyraTheme::drawBatteryLeft(const GfxRenderer& renderer, Rect rect, const bool showPercentage) const {
|
||||
@@ -124,7 +181,7 @@ void LyraTheme::drawHeader(const GfxRenderer& renderer, Rect rect, const char* t
|
||||
renderer.drawText(UI_12_FONT_ID, rect.x + LyraMetrics::values.contentSidePadding,
|
||||
rect.y + LyraMetrics::values.batteryBarHeight + 3, truncatedTitle.c_str(), true,
|
||||
EpdFontFamily::BOLD);
|
||||
renderer.drawLine(rect.x, rect.y + rect.height - 3, rect.x + rect.width, rect.y + rect.height - 3, 3, true);
|
||||
renderer.drawLine(rect.x, rect.y + rect.height - 3, rect.x + rect.width - 1, rect.y + rect.height - 3, 3, true);
|
||||
}
|
||||
|
||||
if (subtitle) {
|
||||
@@ -152,7 +209,7 @@ void LyraTheme::drawSubHeader(const GfxRenderer& renderer, Rect rect, const char
|
||||
UI_10_FONT_ID, label, rect.width - LyraMetrics::values.contentSidePadding - rightSpace, EpdFontFamily::REGULAR);
|
||||
renderer.drawText(UI_10_FONT_ID, currentX, rect.y + 6, truncatedLabel.c_str(), true, EpdFontFamily::REGULAR);
|
||||
|
||||
renderer.drawLine(rect.x, rect.y + rect.height - 1, rect.x + rect.width, rect.y + rect.height - 1, true);
|
||||
renderer.drawLine(rect.x, rect.y + rect.height - 1, rect.x + rect.width - 1, rect.y + rect.height - 1, true);
|
||||
}
|
||||
|
||||
void LyraTheme::drawTabBar(const GfxRenderer& renderer, Rect rect, const std::vector<TabInfo>& tabs,
|
||||
@@ -184,13 +241,13 @@ void LyraTheme::drawTabBar(const GfxRenderer& renderer, Rect rect, const std::ve
|
||||
currentX += textWidth + LyraMetrics::values.tabSpacing + 2 * hPaddingInSelection;
|
||||
}
|
||||
|
||||
renderer.drawLine(rect.x, rect.y + rect.height - 1, rect.x + rect.width, rect.y + rect.height - 1, true);
|
||||
renderer.drawLine(rect.x, rect.y + rect.height - 1, rect.x + rect.width - 1, rect.y + rect.height - 1, true);
|
||||
}
|
||||
|
||||
void LyraTheme::drawList(const GfxRenderer& renderer, Rect rect, int itemCount, int selectedIndex,
|
||||
const std::function<std::string(int index)>& rowTitle,
|
||||
const std::function<std::string(int index)>& rowSubtitle,
|
||||
const std::function<std::string(int index)>& rowIcon,
|
||||
const std::function<UIIcon(int index)>& rowIcon,
|
||||
const std::function<std::string(int index)>& rowValue, bool highlightValue) const {
|
||||
int rowHeight =
|
||||
(rowSubtitle != nullptr) ? LyraMetrics::values.listWithSubtitleRowHeight : LyraMetrics::values.listRowHeight;
|
||||
@@ -220,10 +277,21 @@ void LyraTheme::drawList(const GfxRenderer& renderer, Rect rect, int itemCount,
|
||||
Color::LightGray);
|
||||
}
|
||||
|
||||
int textX = rect.x + LyraMetrics::values.contentSidePadding + hPaddingInSelection;
|
||||
int textWidth = contentWidth - LyraMetrics::values.contentSidePadding * 2 - hPaddingInSelection * 2;
|
||||
int iconSize;
|
||||
if (rowIcon != nullptr) {
|
||||
iconSize = (rowSubtitle != nullptr) ? mainMenuIconSize : listIconSize;
|
||||
textX += iconSize + hPaddingInSelection;
|
||||
textWidth -= iconSize + hPaddingInSelection;
|
||||
}
|
||||
|
||||
// Draw all items
|
||||
const auto pageStartIndex = selectedIndex / pageItems * pageItems;
|
||||
int iconY = (rowSubtitle != nullptr) ? 16 : 10;
|
||||
for (int i = pageStartIndex; i < itemCount && i < pageStartIndex + pageItems; i++) {
|
||||
const int itemY = rect.y + (i % pageItems) * rowHeight;
|
||||
int rowTextWidth = textWidth;
|
||||
|
||||
// Draw name
|
||||
int valueWidth = 0;
|
||||
@@ -232,19 +300,27 @@ void LyraTheme::drawList(const GfxRenderer& renderer, Rect rect, int itemCount,
|
||||
valueText = rowValue(i);
|
||||
valueText = renderer.truncatedText(UI_10_FONT_ID, valueText.c_str(), maxListValueWidth);
|
||||
valueWidth = renderer.getTextWidth(UI_10_FONT_ID, valueText.c_str()) + hPaddingInSelection;
|
||||
rowTextWidth -= valueWidth;
|
||||
}
|
||||
int textWidth = contentWidth - LyraMetrics::values.contentSidePadding * 2 - hPaddingInSelection * 2 - valueWidth;
|
||||
|
||||
auto itemName = rowTitle(i);
|
||||
auto item = renderer.truncatedText(UI_10_FONT_ID, itemName.c_str(), textWidth);
|
||||
renderer.drawText(UI_10_FONT_ID, rect.x + LyraMetrics::values.contentSidePadding + hPaddingInSelection * 2,
|
||||
itemY + 6, item.c_str(), true);
|
||||
auto item = renderer.truncatedText(UI_10_FONT_ID, itemName.c_str(), rowTextWidth);
|
||||
renderer.drawText(UI_10_FONT_ID, textX, itemY + 7, item.c_str(), true);
|
||||
|
||||
if (rowIcon != nullptr) {
|
||||
UIIcon icon = rowIcon(i);
|
||||
const uint8_t* iconBitmap = iconForName(icon, iconSize);
|
||||
if (iconBitmap != nullptr) {
|
||||
renderer.drawIcon(iconBitmap, rect.x + LyraMetrics::values.contentSidePadding + hPaddingInSelection,
|
||||
itemY + iconY, iconSize, iconSize);
|
||||
}
|
||||
}
|
||||
|
||||
if (rowSubtitle != nullptr) {
|
||||
// Draw subtitle
|
||||
std::string subtitleText = rowSubtitle(i);
|
||||
auto subtitle = renderer.truncatedText(SMALL_FONT_ID, subtitleText.c_str(), textWidth);
|
||||
renderer.drawText(SMALL_FONT_ID, rect.x + LyraMetrics::values.contentSidePadding + hPaddingInSelection * 2,
|
||||
itemY + 30, subtitle.c_str(), true);
|
||||
auto subtitle = renderer.truncatedText(SMALL_FONT_ID, subtitleText.c_str(), rowTextWidth);
|
||||
renderer.drawText(SMALL_FONT_ID, textX, itemY + 30, subtitle.c_str(), true);
|
||||
}
|
||||
|
||||
// Draw value
|
||||
@@ -373,8 +449,13 @@ void LyraTheme::drawRecentBookCover(GfxRenderer& renderer, Rect rect, const std:
|
||||
}
|
||||
|
||||
if (!hasCover) {
|
||||
// Render empty cover
|
||||
renderer.drawRect(tileX + hPaddingInSelection, tileY + hPaddingInSelection, coverWidth,
|
||||
LyraMetrics::values.homeCoverHeight);
|
||||
LyraMetrics::values.homeCoverHeight, true);
|
||||
renderer.fillRect(tileX + hPaddingInSelection,
|
||||
tileY + hPaddingInSelection + (LyraMetrics::values.homeCoverHeight / 3), coverWidth,
|
||||
2 * LyraMetrics::values.homeCoverHeight / 3, true);
|
||||
renderer.drawIcon(CoverIcon, tileX + hPaddingInSelection + 24, tileY + hPaddingInSelection + 24, 32, 32);
|
||||
}
|
||||
|
||||
coverBufferStored = storeCoverBuffer();
|
||||
@@ -421,7 +502,7 @@ void LyraTheme::drawEmptyRecents(const GfxRenderer& renderer, const Rect rect) c
|
||||
|
||||
void LyraTheme::drawButtonMenu(GfxRenderer& renderer, Rect rect, int buttonCount, int selectedIndex,
|
||||
const std::function<std::string(int index)>& buttonLabel,
|
||||
const std::function<std::string(int index)>& rowIcon) const {
|
||||
const std::function<UIIcon(int index)>& rowIcon) const {
|
||||
for (int i = 0; i < buttonCount; ++i) {
|
||||
int tileWidth = rect.width - LyraMetrics::values.contentSidePadding * 2;
|
||||
Rect tileRect = Rect{rect.x + LyraMetrics::values.contentSidePadding,
|
||||
@@ -436,11 +517,19 @@ void LyraTheme::drawButtonMenu(GfxRenderer& renderer, Rect rect, int buttonCount
|
||||
|
||||
std::string labelStr = buttonLabel(i);
|
||||
const char* label = labelStr.c_str();
|
||||
const int textX = tileRect.x + 16;
|
||||
int textX = tileRect.x + 16;
|
||||
const int lineHeight = renderer.getLineHeight(UI_12_FONT_ID);
|
||||
const int textY = tileRect.y + (LyraMetrics::values.menuRowHeight - lineHeight) / 2;
|
||||
|
||||
// Invert text when the tile is selected, to contrast with the filled background
|
||||
if (rowIcon != nullptr) {
|
||||
UIIcon icon = rowIcon(i);
|
||||
const uint8_t* iconBitmap = iconForName(icon, mainMenuIconSize);
|
||||
if (iconBitmap != nullptr) {
|
||||
renderer.drawIcon(iconBitmap, textX, textY + 3, mainMenuIconSize, mainMenuIconSize);
|
||||
textX += mainMenuIconSize + hPaddingInSelection + 2;
|
||||
}
|
||||
}
|
||||
|
||||
renderer.drawText(UI_12_FONT_ID, textX, textY, label, true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,14 +50,14 @@ class LyraTheme : public BaseTheme {
|
||||
void drawList(const GfxRenderer& renderer, Rect rect, int itemCount, int selectedIndex,
|
||||
const std::function<std::string(int index)>& rowTitle,
|
||||
const std::function<std::string(int index)>& rowSubtitle,
|
||||
const std::function<std::string(int index)>& rowIcon,
|
||||
const std::function<std::string(int index)>& rowValue, bool highlightValue) const override;
|
||||
const std::function<UIIcon(int index)>& rowIcon, const std::function<std::string(int index)>& rowValue,
|
||||
bool highlightValue) const override;
|
||||
void drawButtonHints(GfxRenderer& renderer, const char* btn1, const char* btn2, const char* btn3,
|
||||
const char* btn4) const override;
|
||||
void drawSideButtonHints(const GfxRenderer& renderer, const char* topBtn, const char* bottomBtn) const override;
|
||||
void drawButtonMenu(GfxRenderer& renderer, Rect rect, int buttonCount, int selectedIndex,
|
||||
const std::function<std::string(int index)>& buttonLabel,
|
||||
const std::function<std::string(int index)>& rowIcon) const override;
|
||||
const std::function<UIIcon(int index)>& rowIcon) const override;
|
||||
void drawRecentBookCover(GfxRenderer& renderer, Rect rect, const std::vector<RecentBook>& recentBooks,
|
||||
const int selectorIndex, bool& coverRendered, bool& coverBufferStored, bool& bufferRestored,
|
||||
std::function<bool()> storeCoverBuffer) const override;
|
||||
|
||||
Reference in New Issue
Block a user