Skip to content
Merged
Show file tree
Hide file tree
Changes from 53 commits
Commits
Show all changes
54 commits
Select commit Hold shift + click to select a range
d1617b1
reversed and hidden work now
gold-silver-copper Feb 22, 2026
64bae30
dimming works now
gold-silver-copper Feb 22, 2026
45c7464
blinking works now
gold-silver-copper Feb 22, 2026
769756f
blinking cursor works
gold-silver-copper Feb 22, 2026
472fd3c
typos lol
gold-silver-copper Feb 22, 2026
c4dab80
Update main.rs
gold-silver-copper Feb 22, 2026
2944165
Update colors.rs
gold-silver-copper Feb 22, 2026
1d977a1
better frame count semantics
gold-silver-copper Feb 22, 2026
6d1b4a5
Update backend.rs
gold-silver-copper Feb 22, 2026
54e2b84
blinking enum, cleaned blink toggle code
gold-silver-copper Feb 22, 2026
424c9cd
Update backend.rs
gold-silver-copper Feb 22, 2026
aaa11d9
inverse cursor, heapbuffer get_pixel
gold-silver-copper Feb 22, 2026
dd08fba
Added CursorStyle,CursorConfig,BlinkConfig
gold-silver-copper Feb 23, 2026
a823c50
Moved blink state to config
gold-silver-copper Feb 23, 2026
4769fe5
Inverse as default
gold-silver-copper Feb 23, 2026
aee110d
Japanese style cursor
gold-silver-copper Feb 23, 2026
e59c5e8
fmt
gold-silver-copper Feb 23, 2026
be9e55c
clippy
gold-silver-copper Feb 23, 2026
7dff734
better japanese cursor style
gold-silver-copper Feb 23, 2026
76aea8a
Merge branch 'ratatui:main' into main
gold-silver-copper Feb 23, 2026
23a5be9
feature flag blink, u16 frame count, removed floats, breaking changes md
gold-silver-copper Feb 25, 2026
94c6a02
wat?
gold-silver-copper Feb 25, 2026
e638536
feature gate blink in cursor config, consolidate cfg flagged code
gold-silver-copper Feb 25, 2026
115661b
md fmt
gold-silver-copper Feb 25, 2026
34c4a32
md fmt2
gold-silver-copper Feb 25, 2026
410cab6
one less cast in get_pixel
gold-silver-copper Feb 25, 2026
6693e0b
make dim a bit more bright
gold-silver-copper Feb 25, 2026
ea88a92
fmt
gold-silver-copper Feb 25, 2026
49d034d
Export all new configuration structs and enums, build docs with all-f…
gold-silver-copper Feb 25, 2026
ff55f0c
fmt
gold-silver-copper Feb 25, 2026
3ec593f
add readme section, removed unnecessary cursor option and fn
gold-silver-copper Feb 25, 2026
bc00434
Update README.md
gold-silver-copper Feb 25, 2026
8d8c7e1
ignore in the doc comments @_@
gold-silver-copper Feb 25, 2026
87bb6a7
Update README.md
gold-silver-copper Feb 25, 2026
857d94d
finale
gold-silver-copper Feb 25, 2026
9de18b6
Update mousefood/src/backend.rs
gold-silver-copper Feb 26, 2026
04d4e73
Update mousefood/src/backend.rs
gold-silver-copper Feb 26, 2026
09e4d1b
Update mousefood/src/colors.rs
gold-silver-copper Feb 26, 2026
ec4ee8e
Update mousefood/src/colors.rs
gold-silver-copper Feb 26, 2026
5a4c669
Update mousefood/src/backend.rs
gold-silver-copper Feb 26, 2026
4f5ca06
Update mousefood/src/backend.rs
gold-silver-copper Feb 26, 2026
3b90b06
Update mousefood/src/backend.rs
gold-silver-copper Feb 26, 2026
1f9b1a4
cursor module, pub type Result
gold-silver-copper Feb 26, 2026
a966992
Update colors.rs
gold-silver-copper Feb 26, 2026
f06c008
Apply suggestion from @orhun
gold-silver-copper Feb 26, 2026
ad099f0
Apply suggestion from @orhun
gold-silver-copper Feb 26, 2026
ad34db7
Apply suggestion from @orhun
gold-silver-copper Feb 26, 2026
2576b83
fmt
gold-silver-copper Feb 26, 2026
c487523
Merge branch 'main' into main
gold-silver-copper Feb 26, 2026
827642f
clean up
gold-silver-copper Mar 6, 2026
c7047ff
Replaced simulator image with blink demo gif
gold-silver-copper Mar 6, 2026
4e5073a
added modifiers demo, added modifiers gif to readme
gold-silver-copper Mar 6, 2026
573252d
Update stuff
gold-silver-copper Mar 9, 2026
f7024b5
Update BREAKING-CHANGES.md
gold-silver-copper Mar 11, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions BREAKING-CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,32 @@ If you use per-cell underline colors, enable the feature explicitly:

If you don't use underline colors, no changes are needed.

### New fields on `EmbeddedBackendConfig` ([#172])

[#172]: https://github.com/ratatui/mousefood/pull/172

`EmbeddedBackendConfig` has two new fields: `cursor` (`CursorConfig`) and `blink` (`BlinkConfig`,
behind the `blink` feature flag). Since the struct is exhaustive, this is a breaking change for
anyone constructing it directly. The `blink` feature is disabled by default due to performance overhead.

#### Migration guide

```diff
let config = EmbeddedBackendConfig {
flush_callback: Box::new(|_| {}),
font_regular: default_font,
font_bold: None,
font_italic: None,
vertical_alignment: TerminalAlignment::Start,
horizontal_alignment: TerminalAlignment::Start,
color_theme: ColorTheme::default(),
+ cursor: CursorConfig::default(),
+ blink: BlinkConfig::default(),
};
```

If you use `..Default::default()`, no changes are needed.

## [v0.4.0](https://github.com/ratatui/mousefood/releases/tag/0.4.0)

### `framebuffer` module is no longer part of the public API ([#149])
Expand Down
47 changes: 46 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -135,12 +135,57 @@ Mousefood includes popular color themes that can be used directly:
- `ColorTheme::ansi()` - Standard ANSI colors (default)
- `ColorTheme::tokyo_night()` - Tokyo Night dark theme with blue/purple tones

### Cursor and blink

Mousefood supports configurable cursor styles and text blinking.

The cursor style can be set to `Inverse` (default), `Underline`, `Outline`, or `Japanese`.
Inverse mode requires the `framebuffer` feature and falls back to underline without it.

```rust,ignore
let config = EmbeddedBackendConfig {
cursor: CursorConfig {
style: CursorStyle::Japanese,
blink: true,
color: Rgb888::WHITE,

},
..Default::default()
};
```

Text blink modifiers (`SLOW_BLINK`, `RAPID_BLINK`) and cursor blinking are
behind the `blink` feature flag to avoid unnecessary computation and memory
usage when not needed:

```toml
[dependencies]
mousefood = { version = "*", features = ["blink"] }
```

Blink timing is configurable:

```rust,ignore
let config = EmbeddedBackendConfig {
#[cfg(feature = "blink")]
blink: BlinkConfig {
fps: 30,
slow: BlinkTiming { blinks_per_sec: 1, duty_percent: 15 },
fast: BlinkTiming { blinks_per_sec: 3, duty_percent: 50 },
},
..Default::default()
};
```

Without the `blink` feature, blink modifiers are silently ignored and the
cursor is always visible.

### Simulator

Mousefood can be run in a simulator using
[embedded-graphics-simulator](https://crates.io/crates/embedded-graphics-simulator) crate.

![Screenshot of a window running the simulator with a mousefood application](https://github.com/ratatui/mousefood/blob/66d4010deed18f755cc3148a7f682f4119b7f664/assets/simulator.png?raw=true)
![GIF of a window running the simulator with a mousefood application](assets/blink.gif)

Run simulator example:

Expand Down
Binary file added assets/blink.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
11 changes: 10 additions & 1 deletion examples/simulator/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,17 @@ name = "simulator"
edition.workspace = true
license.workspace = true
publish = false
default-run = "minimal"

[dependencies]
mousefood = { path = "../../mousefood/" }
mousefood = { path = "../../mousefood/" , features = ["blink"]}
embedded-graphics-simulator.workspace = true
ratatui.workspace = true

[[bin]]
name = "minimal"
path = "src/minimal.rs"

[[bin]]
name = "modifiers"
path = "src/modifiers.rs"
8 changes: 7 additions & 1 deletion examples/simulator/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,18 @@ before running the application.

## Run

To start this demo, simply run:
To start the minimal demo, simply run:

```shell
cargo run -p simulator
```

For the modifiers demo, run:

```shell
cargo run -p simulator --bin modifiers
```

A window will open with the simulator running.

<!-- cargo-rdme end -->
File renamed without changes.
166 changes: 166 additions & 0 deletions examples/simulator/src/modifiers.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
//! # Simulator
//!
//! Run mousefood apps on your computer inside a simulator! Uses [embedded-graphics-simulator](https://crates.io/crates/embedded-graphics-simulator).
//!
//! ## Requirements
//!
//! This app requires [SDL2](https://wiki.libsdl.org/SDL2/Installation) to be installed.
//!
//! If you use [nix](https://nixos.org) you can run `nix-shell -p SDL2`
//! before running the application.
//!
//! ## Run
//!
//! To start this demo, simply run:
//!
//! ```shell
//! cargo run -p simulator --bin modifiers
//! ```
//!
//! A window will open with the simulator running.
//! Use arrow keys or WASD to move the cursor.

use embedded_graphics_simulator::{
OutputSettings, SimulatorDisplay, SimulatorEvent, Window, sdl2::Keycode,
};
use mousefood::embedded_graphics::geometry;
use mousefood::error::Error;
use mousefood::prelude::*;
use ratatui::backend::Backend;
use ratatui::widgets::{Block, Paragraph, Wrap};
use ratatui::{Frame, Terminal, style::*};
use std::cell::RefCell;
use std::rc::Rc;

fn main() -> Result<(), Error> {
let mut simulator_window = Window::new(
"mousefood simulator",
&OutputSettings {
scale: 4,
..Default::default()
},
);
simulator_window.set_max_fps(30);

let mut display = SimulatorDisplay::<Bgr565>::new(geometry::Size::new(128, 64));

let events: Rc<RefCell<Vec<SimulatorEvent>>> = Rc::new(RefCell::new(Vec::new()));
let events_cb = events.clone();

let backend_config = EmbeddedBackendConfig {
flush_callback: Box::new(move |display| {
simulator_window.update(display);
let mut ev = events_cb.borrow_mut();
ev.clear();
ev.extend(simulator_window.events());
}),
color_theme: ColorTheme::tokyo_night(),
..Default::default()
};
let backend: EmbeddedBackend<SimulatorDisplay<_>, _> =
EmbeddedBackend::new(&mut display, backend_config);

let mut terminal = Terminal::new(backend)?;
let mut cursor_x: u16 = 1;
let mut cursor_y: u16 = 1;

loop {
terminal.draw(|frame| draw(frame, cursor_x, cursor_y))?;

for event in events.borrow().iter() {
match event {
SimulatorEvent::KeyDown { keycode, .. } => match *keycode {
Keycode::Up | Keycode::W => {
cursor_y = cursor_y.saturating_sub(1);
}
Keycode::Down | Keycode::S => {
cursor_y = cursor_y.saturating_add(1);
}
Keycode::Left | Keycode::A => {
cursor_x = cursor_x.saturating_sub(1);
}
Keycode::Right | Keycode::D => {
cursor_x = cursor_x.saturating_add(1);
}
_ => {}
},
SimulatorEvent::Quit => return Ok(()),
_ => {}
}
}

if let Ok(size) = terminal.backend_mut().size() {
cursor_x = cursor_x.min(size.width.saturating_sub(1));
cursor_y = cursor_y.min(size.height.saturating_sub(1));
}
}
}

fn draw(frame: &mut Frame, cursor_x: u16, cursor_y: u16) {
use ratatui::style::Modifier;
use ratatui::text::{Line, Span};

let line = Line::from(vec![
Span::styled(format!("F:{} ", frame.count()), Style::new().yellow()),
Span::styled("RED ", Style::new().fg(Color::Red)),
Span::styled(
"DIM ",
Style::new().fg(Color::Red).add_modifier(Modifier::DIM),
),
Span::styled("UNDR ", Style::new().add_modifier(Modifier::UNDERLINED)),
Span::styled("SLOW ", Style::new().add_modifier(Modifier::SLOW_BLINK)),
Span::styled("FAST ", Style::new().add_modifier(Modifier::RAPID_BLINK)),
Span::styled("REV ", Style::new().add_modifier(Modifier::REVERSED)),
Span::styled("HIDE ", Style::new().add_modifier(Modifier::HIDDEN)),
Span::styled("XOUT ", Style::new().add_modifier(Modifier::CROSSED_OUT)),
Span::styled(
"D+U ",
Style::new().add_modifier(Modifier::DIM | Modifier::UNDERLINED),
),
// combos
Span::styled(
"GHOST ",
Style::new()
.fg(Color::DarkGray)
.add_modifier(Modifier::DIM | Modifier::ITALIC),
),
Span::styled(
"ALARM ",
Style::new()
.fg(Color::Red)
.add_modifier(Modifier::RAPID_BLINK | Modifier::REVERSED),
),
Span::styled(
"DEAD ",
Style::new()
.fg(Color::Gray)
.add_modifier(Modifier::CROSSED_OUT | Modifier::DIM),
),
Span::styled(
"SHOUT ",
Style::new()
.fg(Color::Yellow)
.add_modifier(Modifier::BOLD | Modifier::UNDERLINED),
),
Span::styled(
"HAUNT ",
Style::new()
.fg(Color::Magenta)
.add_modifier(Modifier::SLOW_BLINK | Modifier::DIM),
),
Span::styled(
"CRIT",
Style::new()
.fg(Color::White)
.bg(Color::Red)
.add_modifier(Modifier::BOLD | Modifier::RAPID_BLINK),
),
]);

let paragraph = Paragraph::new(vec![line]).wrap(Wrap { trim: true });
let bordered_block = Block::bordered()
.border_style(Style::new().yellow())
.title("Mods");
frame.render_widget(paragraph.block(bordered_block), frame.area());
frame.set_cursor_position((cursor_x, cursor_y));
}
5 changes: 5 additions & 0 deletions mousefood/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,12 @@ fonts = ["dep:embedded-graphics-unicodefonts"]
epd-weact = ["dep:weact-studio-epd"]
epd-waveshare = ["dep:epd-waveshare"]
framebuffer = []
blink = []
underline-color = ["ratatui-core/underline-color"]

[lints]
workspace = true

[package.metadata.docs.rs]
all-features = true
rustdoc-args = ["--cfg", "docsrs"]
Loading