Skip to content

Mousefood display trait#100

Closed
deadbaed wants to merge 4 commits intoratatui:mainfrom
deadbaed:mousefood-display-trait
Closed

Mousefood display trait#100
deadbaed wants to merge 4 commits intoratatui:mainfrom
deadbaed:mousefood-display-trait

Conversation

@deadbaed
Copy link
Copy Markdown
Contributor

@deadbaed deadbaed commented Jun 24, 2025

This is the main pull request of #66, introducing a trait for display backends to implement to work with mousefood. This will also remove the flush_callback function, and removes the requirement of using a framebuffer.

The esp32-test will be removed, it was just for the test. I'll also rebase from main

@j-g00da
Copy link
Copy Markdown
Member

j-g00da commented Jun 24, 2025

Thanks, I will take a look later today, can you update the branch?

@deadbaed deadbaed force-pushed the mousefood-display-trait branch from 83092d5 to b5449b9 Compare June 24, 2025 06:30
@deadbaed
Copy link
Copy Markdown
Contributor Author

Done! Those changes build and run fine on the simulator and my ssd1306 display.

I just bought a ST7789, I'll be able to test with it as soon as it arrives.

Copy link
Copy Markdown
Member

@j-g00da j-g00da left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please run fmt and clippy and then fix clippy warnings.
Also the framebuffer tests are panicking after changes.
I will take a deeper look later.

@deadbaed
Copy link
Copy Markdown
Contributor Author

The git log is messy, but I wanted to do everything I wanted functionality wise before requesting review. I'll rebase and re-make the commits later, make other PRs if needed.

  • Renamed the trait to DisplayTarget, moved it to its own module display
  • removed as many trait parameters as possible (maybe more could be removed?)
  • refactored usage of TermColor(Color::Reset, TermColorType::Background)
  • started to add minimal documentation to make clippy happy, but they will need to be improved -- to be frank I am really not the best at those kind of things, I want to improve though.

I will start to look into proc macros and derive macros, to see what's possible.

@deadbaed
Copy link
Copy Markdown
Contributor Author

When writing documentation, I stumbled upon https://docs.rs/embedded-graphics-core/latest/embedded_graphics_core/draw_target/trait.DrawTarget.html, and by reading the documentation, it is very familiar with what we are doing here, and I wanted to share that with you if you did not know about it!

Something about implementing DrawTarget for future Mousefood Displays: since some displays may have hardware acceleration, we would need to implement all functions of DrawTarget, in order to keep the potential acceleration.

C: PixelColor,
{
/// Callback fired after each buffer flush.
pub flush_callback: Box<dyn FnMut(&mut D)>,
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a note: Removing flush_callback makes this a breaking change

) -> EmbeddedBackend<'display, D, C> {
display: &'display mut M,
config: EmbeddedBackendConfig,
) -> Result<EmbeddedBackend<'display, D, C, M>> {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is also a breaking change which must be documented

///
/// If the display driver requires additional operations, this is the place to make them
fn flush(&mut self) -> Result<()>;
}
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One more thing, we should think about is making the integration crates able to define custom color conversions. E.g. Weact integration has it's own colors which ideally should be moved out of the main crate.
Let me know if you have some ideas for it.

Copy link
Copy Markdown
Contributor Author

@deadbaed deadbaed Jun 25, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think integration crates should be able to define custom color conversions (the Weact case confirms us that).

Is taking anything implementing embedded_graphics::PixelColor enough? Maybe it's time for another trait 😄

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Discovered DrawTargetExt from embedded_graphics, with a function to convert colors, would this interest you? https://docs.rs/embedded-graphics/latest/embedded_graphics/draw_target/trait.DrawTargetExt.html#tymethod.color_converted

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry for late response, I'm not sure if this can be helpful here but you can experiment with this a bit.

@j-g00da
Copy link
Copy Markdown
Member

j-g00da commented Jun 24, 2025

Something about implementing DrawTarget for future Mousefood Displays: since some displays may have hardware acceleration, we would need to implement all functions of DrawTarget, in order to keep the potential acceleration.

But we are calling it directly on underlying display using .draw_target() anyway, so it shouldn't matter. We shouldn't need to implement DrawTarget at all.

@deadbaed
Copy link
Copy Markdown
Contributor Author

But we are calling it directly on underlying display using .draw_target() anyway, so it shouldn't matter. We shouldn't need to implement DrawTarget at all.

Yup! Just figured that out now, sorry for the confusion (I think it confused myself)

@j-g00da
Copy link
Copy Markdown
Member

j-g00da commented Jun 24, 2025

Understandable ;D

@deadbaed
Copy link
Copy Markdown
Contributor Author

For the 2 breaking changes, do you want one commit per breaking change, or having both changes in the same commit is fine?

@j-g00da
Copy link
Copy Markdown
Member

j-g00da commented Jun 25, 2025

One is fine

Comment on lines +12 to +14
/// Flushing to the display failed.
#[error("flushing to DrawTarget failed")]
Flush,
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am debating whether this should be a standalone structure, because currently the only usage of Error::Flush is outside of mousefood, which is a bit weird imo.

I will make a new structure FlushError, export it, and have a From<FlushError> for Error to be able to use our Result type.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about doing Flush(String), so one can give more implementation specific details about what exactly went wrong?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, good idea! I added anything implementing core::error::Error, which includes strings!

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll revert to just taking a string, it will be simpler, and it's a good starting point.

@deadbaed deadbaed force-pushed the mousefood-display-trait branch from f43e0b8 to 81c286b Compare June 25, 2025 22:42
@deadbaed deadbaed marked this pull request as draft June 25, 2025 22:43
@deadbaed deadbaed force-pushed the mousefood-display-trait branch from 81c286b to f0a412a Compare June 26, 2025 18:13
@deadbaed deadbaed marked this pull request as ready for review June 26, 2025 18:40
@deadbaed
Copy link
Copy Markdown
Contributor Author

Ready for review! The only thing missing is good documentation, if you have any ideas I'm all ears!

B: BufferedDisplay<D, C>,
D: DrawTarget<Color = C> + 'display,
C: PixelColor + 'display,
C: PixelColor + 'display + From<TermColor>,
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: lifetimes after traits

Suggested change
C: PixelColor + 'display + From<TermColor>,
C: PixelColor + From<TermColor> + 'display,

@j-g00da
Copy link
Copy Markdown
Member

j-g00da commented Jun 26, 2025

Thanks! Let's move out these two to new PRs and merge these first.

@deadbaed deadbaed force-pushed the mousefood-display-trait branch from 52c4135 to b40d7de Compare June 26, 2025 22:13
deadbaed added 3 commits July 5, 2025 00:00
BREAKING CHANGE: removed `flush_callback` from struct `EmbeddedBackendConfig`
BREAKING CHANGE: `EmbeddedBackend::init()` returns a Result
@deadbaed deadbaed force-pushed the mousefood-display-trait branch from b40d7de to ec01faf Compare July 4, 2025 22:01
@j-g00da
Copy link
Copy Markdown
Member

j-g00da commented Jul 12, 2025

I think we should implement crates for simulator and weact drivers in this PR already.

@deadbaed
Copy link
Copy Markdown
Contributor Author

What do you think about merging this PR onto a staging branch, and make PRs to implement drivers targeting that staging branch?

If we implement drivers in this PR I'll become the bus factor, and I do not want to slow you down because of that.

@j-g00da
Copy link
Copy Markdown
Member

j-g00da commented Jul 13, 2025

Let's use this branch as staging, just don't rebase anymore so we can safely work on this together.

@j-g00da
Copy link
Copy Markdown
Member

j-g00da commented Jul 13, 2025

So I experimented a bit with what has to be done to be able to define custom color conversions without issues.
First we have to remove From<TermColor> bounds from C type params.
Then to make it work we can create a static method in BufferedDisplay like this (similar to what DrawTargetExt provides):

fn convert_color(color: TermColor) -> C;

And use it in Backend like this:

let mut style_builder = MonoTextStyleBuilder::new()
    .font(&self.font_regular)
    .text_color(B::convert_color(TermColor(cell.fg, TermColorType::Foreground)))
    .background_color(B::convert_color(TermColor(cell.bg, TermColorType::Background)));

(this can be simplified, but that's the general idea)

Finally we can implement conversions inside integration crates (example for epd-waveshare):

impl<SPI, BUSY, DC, RST, DELAY> BufferedDisplay<Display4in2, epd_waveshare::color::Color>
for WaveshareEpd4in2<SPI, BUSY, DC, RST, DELAY>
where
    SPI: SpiDevice,
    BUSY: InputPin,
    DC: OutputPin,
    RST: OutputPin,
    DELAY: DelayNs,
{
    // (...)
    fn convert_color(color: TermColor) -> epd_waveshare::color::Color {
        // TermColor -> BinaryColor (implemented in mousefood)
        let binary_color: BinaryColor = color.into();
        // BinaryColor -> Color (from epd_waveshare)
        binary_color.into()
    }
}

Let me know what you think @deadbaed

@deadbaed
Copy link
Copy Markdown
Contributor Author

Okay, let's use this branch. I've locked it through GitHub, so if I did everything well the only way to push code is by making PRs.

I think that is super nice to have fn convert_color(color: TermColor) -> C; inside the trait! The api is nice, users will be free to do anything with that function once implemented.

I am wondering what the code will be for display backends not requiring color correction, like the simulator.

@j-g00da
Copy link
Copy Markdown
Member

j-g00da commented Jul 14, 2025

Just color.into(), as we already implement From<TermColor> for all built-in embedded-graphics color types.

@deadbaed
Copy link
Copy Markdown
Contributor Author

Awesome, just what I thought. I'd love to test your changes on my ssd1306, if you have something you're happy with, feel free to make a PR!

I did some shopping and bought a ILI9341 display (thinking I was buying a ST7789 like you have), and a WeAct red/black/white display. When I'll have more time I'll get them up running with mousefood, and use them as test targets for integration crates.

@orhun
Copy link
Copy Markdown
Member

orhun commented Jan 23, 2026

🏓

What is the status on this one? @deadbaed @j-g00da 👀

@j-g00da
Copy link
Copy Markdown
Member

j-g00da commented Jan 24, 2026

I'm not sure if it's still the right way to go, for sure not in the next release as this requires a lot of work outside of this PR too @orhun, this one is worth a read: #66

@deadbaed
Copy link
Copy Markdown
Contributor Author

This PR has completely stalled, this summer I tried to get my ILI9341 working on my esp32 but I failed (due to some memory allocation iirc), and I kinda gave up.

This PR is also outdated with all the recent changes on main (it's awesome to see mousefood go under ratatui's organization!), and I think there were too many changes required to do what I had in mind in #66, and I lacked knowledge to properly implement this.

I would like to take the time to tackle it again when 0.3 will be out, I'd like to know your opinion on #66 if it is worth the time and energy (I still think it is worth it in the long run). I'm happy to discuss about it on discord if you want, maybe let's create a mousefood channel? It might attract new contributors as well.

Closing this, thank you for taking the time to reviews PRs!

@deadbaed deadbaed closed this Jan 25, 2026
@orhun
Copy link
Copy Markdown
Member

orhun commented Jan 27, 2026

Yup, I'll take a look at the discussion in that issue whenever I can.

I'm happy to discuss about it on discord if you want, maybe let's create a mousefood channel? It might attract new contributors as well.

Currently there isn't much discussion happening around Mousefood but it might get more active after we create the new release. I think then we could create a new channel. Currently we could use the #community and #development channels :)

Could you maybe drop me a message there?

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.

3 participants