Co-authored-by: Uri Tauber <uritaube@gmail.com> Co-authored-by: Julia Nguyen <julia@uxj.io>
255 lines
12 KiB
C++
255 lines
12 KiB
C++
#pragma once
|
|
|
|
#include <cstddef>
|
|
#include <cstdint>
|
|
#include <functional>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
class GfxRenderer;
|
|
struct RecentBook;
|
|
|
|
struct Rect {
|
|
int x;
|
|
int y;
|
|
int width;
|
|
int height;
|
|
|
|
explicit Rect(int x = 0, int y = 0, int width = 0, int height = 0) : x(x), y(y), width(width), height(height) {}
|
|
};
|
|
|
|
struct TabInfo {
|
|
const char* label;
|
|
bool selected;
|
|
};
|
|
|
|
struct ThemeMetrics {
|
|
int batteryWidth;
|
|
int batteryHeight;
|
|
|
|
int topPadding;
|
|
int batteryBarHeight;
|
|
int headerHeight;
|
|
int verticalSpacing;
|
|
|
|
int previewPadding;
|
|
int previewHeightPercent;
|
|
|
|
int contentSidePadding;
|
|
int listRowHeight;
|
|
int listWithSubtitleRowHeight;
|
|
int menuRowHeight;
|
|
int menuSpacing;
|
|
|
|
int tabSpacing;
|
|
int tabBarHeight;
|
|
|
|
int scrollBarWidth;
|
|
int scrollBarRightOffset;
|
|
|
|
int homeTopPadding;
|
|
int homeCoverHeight;
|
|
int homeCoverTileHeight;
|
|
int homeRecentBooksCount;
|
|
bool homeContinueReadingInMenu;
|
|
int homeMenuTopOffset;
|
|
|
|
int buttonHintsHeight;
|
|
int sideButtonHintsWidth;
|
|
|
|
int progressBarHeight;
|
|
int progressBarMarginTop;
|
|
int statusBarHorizontalMargin;
|
|
int statusBarVerticalMargin;
|
|
|
|
int keyboardKeyWidth;
|
|
int keyboardKeyHeight;
|
|
int keyboardKeySpacing;
|
|
int keyboardBottomKeyHeight;
|
|
int keyboardBottomKeySpacing;
|
|
bool keyboardBottomAligned;
|
|
bool keyboardCenteredText;
|
|
int keyboardVerticalOffset;
|
|
int keyboardTextFieldWidthPercent;
|
|
int keyboardWidthPercent;
|
|
int keyboardKeyCornerRadius;
|
|
bool keyboardFillUnselected;
|
|
bool keyboardOutlineAllUnselected;
|
|
bool keyboardDrawSpecialOutlineWhenUnselected;
|
|
int keyboardSecondaryLabelRightPadding;
|
|
int keyboardSecondaryLabelTopPadding;
|
|
int keyboardMinArrowHeadSize;
|
|
|
|
float popupTopOffsetRatio;
|
|
int popupMarginX;
|
|
int popupMarginY;
|
|
int popupFrameThickness;
|
|
int popupCornerRadius;
|
|
bool popupTextBold;
|
|
bool popupTextInverted;
|
|
int popupTextBaselineOffsetY;
|
|
int popupProgressBarHeight;
|
|
bool popupProgressDrawOutline;
|
|
bool popupProgressClampPercent;
|
|
bool popupProgressFillInverted;
|
|
bool popupProgressOutlineInverted;
|
|
|
|
int optionPopupItemSpacing;
|
|
int optionPopupInnerPadding;
|
|
int optionPopupSelectionHPadding;
|
|
int optionPopupSelectionVPadding;
|
|
int optionPopupTitleGap;
|
|
bool optionPopupUseSmallFont;
|
|
bool optionPopupOptionFontBold;
|
|
int optionPopupSelectionRadius;
|
|
bool optionPopupSelectionLight;
|
|
bool optionPopupDrawAllRows;
|
|
int optionPopupDialogSideMargin;
|
|
bool optionPopupTitleSeparator;
|
|
|
|
int textFieldHorizontalPadding;
|
|
int textFieldNormalThickness;
|
|
int textFieldCursorThickness;
|
|
int textFieldLineEndOffset;
|
|
};
|
|
|
|
enum UIIcon { None = 0, Folder, Text, Image, Book, File, Recent, Settings, Transfer, Library, Wifi, Hotspot, Bookmark };
|
|
|
|
enum class KeyboardKeyType { Normal, Shift, Mode, Space, Del, Ok, Disabled };
|
|
|
|
// Default theme implementation (Classic Theme)
|
|
// Additional themes can inherit from this and override methods as needed
|
|
|
|
namespace BaseMetrics {
|
|
constexpr ThemeMetrics values = {.batteryWidth = 15,
|
|
.batteryHeight = 12,
|
|
.topPadding = 5,
|
|
.batteryBarHeight = 20,
|
|
.headerHeight = 45,
|
|
.verticalSpacing = 10,
|
|
.previewPadding = 12,
|
|
.previewHeightPercent = 30,
|
|
.contentSidePadding = 20,
|
|
.listRowHeight = 30,
|
|
.listWithSubtitleRowHeight = 50,
|
|
.menuRowHeight = 45,
|
|
.menuSpacing = 8,
|
|
.tabSpacing = 10,
|
|
.tabBarHeight = 50,
|
|
.scrollBarWidth = 4,
|
|
.scrollBarRightOffset = 5,
|
|
.homeTopPadding = 40,
|
|
.homeCoverHeight = 400,
|
|
.homeCoverTileHeight = 400,
|
|
.homeRecentBooksCount = 1,
|
|
.homeContinueReadingInMenu = false,
|
|
.homeMenuTopOffset = 10,
|
|
.buttonHintsHeight = 40,
|
|
.sideButtonHintsWidth = 30,
|
|
.progressBarHeight = 16,
|
|
.progressBarMarginTop = 1,
|
|
.statusBarHorizontalMargin = 5,
|
|
.statusBarVerticalMargin = 19,
|
|
.keyboardKeyWidth = 22,
|
|
.keyboardKeyHeight = 40,
|
|
.keyboardKeySpacing = 0,
|
|
.keyboardBottomKeyHeight = 35,
|
|
.keyboardBottomKeySpacing = 5,
|
|
.keyboardBottomAligned = true,
|
|
.keyboardCenteredText = false,
|
|
.keyboardVerticalOffset = -13,
|
|
.keyboardTextFieldWidthPercent = 85,
|
|
.keyboardWidthPercent = 90,
|
|
.keyboardKeyCornerRadius = 0,
|
|
.keyboardFillUnselected = false,
|
|
.keyboardOutlineAllUnselected = false,
|
|
.keyboardDrawSpecialOutlineWhenUnselected = true,
|
|
.keyboardSecondaryLabelRightPadding = 1,
|
|
.keyboardSecondaryLabelTopPadding = 0,
|
|
.keyboardMinArrowHeadSize = 0,
|
|
.popupTopOffsetRatio = 0.075f,
|
|
.popupMarginX = 15,
|
|
.popupMarginY = 15,
|
|
.popupFrameThickness = 2,
|
|
.popupCornerRadius = 0,
|
|
.popupTextBold = true,
|
|
.popupTextInverted = true,
|
|
.popupTextBaselineOffsetY = -2,
|
|
.popupProgressBarHeight = 4,
|
|
.popupProgressDrawOutline = false,
|
|
.popupProgressClampPercent = false,
|
|
.popupProgressFillInverted = true,
|
|
.popupProgressOutlineInverted = true,
|
|
.optionPopupItemSpacing = 6,
|
|
.optionPopupInnerPadding = 16,
|
|
.optionPopupSelectionHPadding = 8,
|
|
.optionPopupSelectionVPadding = 4,
|
|
.optionPopupTitleGap = 10,
|
|
.optionPopupUseSmallFont = true,
|
|
.optionPopupOptionFontBold = true,
|
|
.optionPopupSelectionRadius = 0,
|
|
.optionPopupSelectionLight = false,
|
|
.optionPopupDrawAllRows = false,
|
|
.optionPopupDialogSideMargin = 20,
|
|
.optionPopupTitleSeparator = true,
|
|
.textFieldHorizontalPadding = 6,
|
|
.textFieldNormalThickness = 1,
|
|
.textFieldCursorThickness = 3,
|
|
.textFieldLineEndOffset = 0};
|
|
}
|
|
|
|
class BaseTheme {
|
|
public:
|
|
virtual ~BaseTheme() = default;
|
|
|
|
// Component drawing methods
|
|
void drawProgressBar(const GfxRenderer& renderer, Rect rect, size_t current, size_t total) const;
|
|
void drawBatteryLeft(const GfxRenderer& renderer, Rect rect,
|
|
bool showPercentage = true) const; // Left aligned (reader mode)
|
|
void drawBatteryRight(const GfxRenderer& renderer, Rect rect,
|
|
bool showPercentage = true) const; // Right aligned (UI headers)
|
|
virtual void fillBatteryIcon(const GfxRenderer& renderer, Rect rect, uint16_t percentage) const;
|
|
virtual void drawButtonHints(GfxRenderer& renderer, const char* btn1, const char* btn2, const char* btn3,
|
|
const char* btn4) const;
|
|
virtual void drawSideButtonHints(const GfxRenderer& renderer, const char* topBtn, const char* bottomBtn) const;
|
|
virtual int getListPageItems(int contentHeight, bool hasSubtitle) const;
|
|
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<UIIcon(int index)>& rowIcon = nullptr,
|
|
const std::function<std::string(int index)>& rowValue = nullptr, bool highlightValue = false,
|
|
const std::function<bool(int index)>& rowDimmed = nullptr) const;
|
|
virtual void drawHeader(const GfxRenderer& renderer, Rect rect, const char* title,
|
|
const char* subtitle = nullptr) const;
|
|
virtual void drawSubHeader(const GfxRenderer& renderer, Rect rect, const char* label,
|
|
const char* rightLabel = nullptr) const;
|
|
virtual void drawTabBar(const GfxRenderer& renderer, Rect rect, const std::vector<TabInfo>& tabs,
|
|
bool selected) const;
|
|
virtual 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;
|
|
virtual void drawButtonMenu(GfxRenderer& renderer, Rect rect, int buttonCount, int selectedIndex,
|
|
const std::function<std::string(int index)>& buttonLabel,
|
|
const std::function<UIIcon(int index)>& rowIcon) const;
|
|
virtual Rect drawPopup(const GfxRenderer& renderer, const char* message) const;
|
|
virtual void drawOptionPopup(const GfxRenderer& renderer, const char* title, const std::vector<std::string>& options,
|
|
int selectedIndex) const;
|
|
virtual void fillPopupProgress(const GfxRenderer& renderer, const Rect& layout, const int progress) const;
|
|
void drawStatusBar(GfxRenderer& renderer, const float bookProgress, const int currentPage, const int pageCount,
|
|
std::string title, const int paddingBottom = 0, const int textYOffset = 0,
|
|
const bool fillMargin = true, const bool isPageBookmarked = false,
|
|
const bool pageCountEstimated = false) const;
|
|
void drawHelpText(const GfxRenderer& renderer, Rect rect, const char* label) const;
|
|
virtual void drawTextField(const GfxRenderer& renderer, Rect rect, const int textWidth, bool cursorMode = false,
|
|
int contentStartX = 0, int contentWidth = 0) const;
|
|
virtual void drawKeyboardKey(const GfxRenderer& renderer, Rect rect, const char* label, const bool isSelected,
|
|
const char* secondaryLabel = nullptr, KeyboardKeyType keyType = KeyboardKeyType::Normal,
|
|
bool inactiveSelection = false) const;
|
|
virtual bool showsFileIcons() const { return false; }
|
|
|
|
// Shared constants and helpers for battery drawing (used by all themes)
|
|
static constexpr int batteryPercentSpacing = 4;
|
|
static void drawBatteryOutline(const GfxRenderer& renderer, int x, int y, int battWidth, int rectHeight);
|
|
static void drawBatteryLightningBolt(const GfxRenderer& renderer, int boltX, int boltY);
|
|
};
|