Skip to content

feat: UI Theme engine#548

Closed
Brackyt wants to merge 28 commits intocrosspoint-reader:masterfrom
Brackyt:theme-engine
Closed

feat: UI Theme engine#548
Brackyt wants to merge 28 commits intocrosspoint-reader:masterfrom
Brackyt:theme-engine

Conversation

@Brackyt
Copy link

@Brackyt Brackyt commented Jan 25, 2026

Summary

  • What is the goal of this PR?
    Implementing a theme engine to Crosspoint that is easy to use.

  • What changes are included?

Core Architectural Changes

  • Declarative UI System (lib/ThemeEngine):

    • Introduced a component-based architecture where every UI element (Labels, Bitmaps, Icons, Badges) inherits from a common UIElement base class.
    • Implemented a hierarchical layout engine supporting Stacks (HStack, VStack), Containers, and Grids.
    • Added a sophisticated INI Parser that allows defining entire screens through text configuration files, supporting responsive dimensions (percentages) and structural nesting.
  • Dynamic Data Binding (ThemeContext):

    • Created a context system that allows UI elements to react to live data (e.g., {BatteryPercent}, {RecentBooks.0.Title}).
    • Implemented inline expression evaluation, allowing for conditional styling directly in the theme file (e.g., BgColor = {Item.Selected ? "0xD9" : "white"}).

Graphics & Performance Overhaul

  • Advanced Rendering Primitives (GfxRenderer):

    • Added high-level drawing functions for rounded rectangles and border radiuses on both shapes and bitmaps.
    • Implemented transparency and alpha channel support, ensuring modern icons and overlays blend correctly.
    • Added E-Ink optimized dithering for background fills and selection states.
  • Rendering & Asset Optimization:

    • Processed Asset Cache: Implemented a caching system for bitmaps that stores dithered 1-bit versions of images in RAM. This bypasses the expensive dithering process on subsequent renders, specifically benefiting list scrolling and repeated icon usage.
    • Streaming Support: Large images (like book covers) can now be streamed directly from the SD card when RAM is tight, preventing memory exhaustion while still allowing for high-quality previews.

New User Features

  • Lyra Theme: A new, modern community theme that showcases the engine's power with a 3-book recent grid, icon-based 2-column menu, and "glassmorphic" dithered effects.
  • Runtime Theme Selection:
    • Added a new Theme Selection Activity in Settings that scans the /themes folder on the SD card.
    • Users can now switch themes and preview them without re-flashing firmware (requires a quick automated reboot to apply).
  • Responsive Lists: The library's lists now support Horizontal scrolling, Multi-column Grids, and Automatic Word Wrapping for text.

Key Refinements

  • Navigation Logic: Standardized input handling to work with dynamic book slots (defined by the theme), fixing cases where navigation would skip items.
  • Typography: Enhanced Label support with MaxLines, Alignment (Left/Center/Right), and automatic Ellipsis truncation.

Additional Context

This PR introduces a theme engine system for Crosspoint. It loads .ini files for theme configuration from the SD Card.
This allows people to create/edit/use themes really easily with their device. With new firmware updates, the themes don’t need updating (except if the theme engine is changed obviously).

You can simply make a .ini file that you place in /themes/{theme_name}/theme.ini.
You can also place .bmp icon files to use icons in your theme.

It can support multiple themes that you can switch to by simply going to the device settings (Display -> Theme).

This is still a work in progress but I decided to get the PR going to get feedback. It currently only can edit the home page. Future updates will obviously allow editing every screen of Crosspoint.

I have currently started implementing the Lyra theme which you can try out.

I invite people to try making themes, this is allow to see if there are any issues currently that can be fixed before it is fully implemented on every screen.


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? YES I made this with the help of AI tools


I am also including a zip file containing the Lyra theme (at least what it is for now). Just decompress this at the root of the sd card.
themes.zip

IMG_2263

@Brackyt
Copy link
Author

Brackyt commented Jan 25, 2026

This still needs to be implemented for all screens. May need some cleanup. 1 or 2 bug fixes. And maybe more editable features as I go and implement more screens

@Brackyt
Copy link
Author

Brackyt commented Jan 25, 2026

I should also add that I didn't polish the Lyra theme (yet, but you can if you want). It would need correctly sized icons to look good, colors and sizing changes and it would be almost perfect

@Eloren1
Copy link
Contributor

Eloren1 commented Jan 26, 2026

Why do book covers shapes look like this? ( ]

@jonasdiemer
Copy link
Contributor

We should aim for regular options not needing abbreviations (e.g. "Calibre Li..." should be fixed)

@Brackyt
Copy link
Author

Brackyt commented Jan 26, 2026

Why do book covers shapes look like this? ( ]

It's an issue currently only happening with the theme I made. It can be fixed.

We should aim for regular options not needing abbreviations (e.g. "Calibre Li..." should be fixed)

It's just with the example theme, the text doesn't have enough space to fit entirely but this can be changed easily. I'll update the example theme when I have implemented more screens with the theme engine but currently you can already do what you want with the home by making your own .ini file

@Uri-Tauber
Copy link
Contributor

Impressive work, @Brackyt! That said, I’m wondering whether we really need such a large amount of additional code in the firmware. Since the user selects a theme once and that’s it, it might make more sense to ship the firmware with two (or maybe three) built-in themes, rather than maintaining fairly complex INI parsing logic.

You might also want to take a look at #528, which seems to address the same goal but in a way that’s better suited to the limited flash memory available.

@CaptainFrito
Copy link
Contributor

I inspected your code and tested the build on device.

I agree that user-editable theme config files are a good idea to extend customization options to the user and not just to developers, but the flaw I see in this implementation is that we have a 300+ line text file to customize one screen. This is parsed and loaded into memory and stays there permanently. Once all Crosspoint screens are themed, the file will grow significantly and will have a large memory footprint, and its parsing step will burden the boot process.

Remember that we are dealing with a very memory-constrained device, for which we have been relentlessly optimizing core features and draw code, so we might not be able to afford an overly complex frontend architecture.

@Brackyt
Copy link
Author

Brackyt commented Jan 26, 2026

Impressive work, @Brackyt! That said, I’m wondering whether we really need such a large amount of additional code in the firmware. Since the user selects a theme once and that’s it, it might make more sense to ship the firmware with two (or maybe three) built-in themes, rather than maintaining fairly complex INI parsing logic.

You might also want to take a look at #528, which seems to address the same goal but in a way that’s better suited to the limited flash memory available.

Thanks!
To address your concern. My idea here was to allow people to create themes and share them, not lock in the users to some themes. I imagine many people creating themes and sharing them in the future, and being able to change them for their own use if they wanted.

@Brackyt
Copy link
Author

Brackyt commented Jan 26, 2026

I inspected your code and tested the build on device.

I agree that user-editable theme config files are a good idea to extend customization options to the user and not just to developers, but the flaw I see in this implementation is that we have a 300+ line text file to customize one screen. This is parsed and loaded into memory and stays there permanently. Once all Crosspoint screens are themed, the file will grow significantly and will have a large memory footprint, and its parsing step will burden the boot process.

Remember that we are dealing with a very memory-constrained device, for which we have been relentlessly optimizing core features and draw code, so we might not be able to afford an overly complex frontend architecture.

I will see what happens once I've integrated all screens. And I am sure there are solutions for the memory, for example we don't need to load a whole theme at once. This is still pretty much a prototype and I'll make it better along the way.
Might not be the right solution too, but we will see !

- Refactored Bitmap class to improve memory management and streamline methods.
- Introduced ThemeEngine with foundational classes for UI elements, layout management, and theme parsing.
- Added support for dynamic themes and improved rendering capabilities in the HomeActivity and settings screens.

This update lays the groundwork for a more flexible theming system, allowing for easier customization and management of UI elements across the application.
- text no showing if clipping out of screen
- inner child dimensions setting 0 for height
- navigation to home menus was skipping transfer
- background fill
- border radius
- container paddings
- fix navigation in home
- Remove unused HomeActivity::restoreCoverBuffer
- Use initialization lists in constructors
- Mark single-argument constructors as explicit
- Improve ThemeManager with Children property support and safe integer parsing.
- Refactor SettingsActivity to use new theme elements.
- Update BasicElements and LayoutElements for better rendering.
- fix double-free
- safe int/float parse
- grid division guard
- list string allocations
- label vector reserve
- skip second layout pass for hstack/vstack
- Add layout caching in UIElement to skip redundant layout passes
- Use binary search for text wrapping in Label (O(log n) vs O(n))
- Cache rendered bitmaps using captureRegion/restoreRegion
- Add RAM caching for BMP files to avoid SD card reads
- Cache book metadata in HomeActivity.onEnter() instead of every render
- Reuse recent books data to avoid duplicate ePub loads
- Update HomeActivity to use RecentBook struct instead of string
- Remove leftover conflict marker from SettingsActivity
@Brackyt
Copy link
Author

Brackyt commented Feb 1, 2026

@daveallie are you considering this PR ? If you are planning on integrating #528 I'll remove this PR and make my own fork. Many people want to create their own UI changes and this would allow that.

@daveallie
Copy link
Member

Hey @Brackyt apologies, I have been pretty behind on PRs and still playing a lot of catch up. At this point I'm favoring #528 and continuing to push for static themes. While I do think the idea of fully custom themes is interesting. A limited set of fully embedded themes suits my vision better as I personally believe that the lower complexity, and limited configurations will be better long-term for the firmware.

Apologies that I wasn't able to let you know this sooner, I am keen to watch how this develops but #528 will be the path forward for themes for the main repo.

@Brackyt
Copy link
Author

Brackyt commented Feb 1, 2026

Hey @Brackyt apologies, I have been pretty behind on PRs and still playing a lot of catch up. At this point I'm favoring #528 and continuing to push for static themes. While I do think the idea of fully custom themes is interesting. A limited set of fully embedded themes suits my vision better as I personally believe that the lower complexity, and limited configurations will be better long-term for the firmware.

Apologies that I wasn't able to let you know this sooner, I am keen to watch how this develops but #528 will be the path forward for themes for the main repo.

No issues! Thanks for the reply and good luck

@Uri-Tauber
Copy link
Contributor

Uri-Tauber commented Feb 5, 2026

Should be closed, now #528 was merged.

@daveallie daveallie closed this Feb 9, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants