ratatui/examples/concepts/state/src/bin/nested-mutable-widget.rs
Josh McKinney cfb65e64ba
docs: add examples for handling state (#1849)
Added comprehensive state management examples covering both immutable
and mutable patterns and documentation to help developers choose the
right approach for their applications.
2025-06-26 13:04:42 -07:00

97 lines
3.2 KiB
Rust

//! # Nested Mutable Widget Pattern
//!
//! This example demonstrates nesting widgets that both need mutable access to their state.
//! This pattern is useful when you have a parent-child widget relationship where both widgets
//! need to maintain and mutate their own state during rendering.
//!
//! This example runs with the Ratatui library code in the branch that you are currently
//! reading. See the [`latest`] branch for the code which works with the most recent Ratatui
//! release.
//!
//! [`latest`]: https://github.com/ratatui/ratatui/tree/latest
//!
//! ## When to Use This Pattern
//!
//! - You have hierarchical widget relationships (parent-child)
//! - Each widget needs to maintain its own distinct state
//! - You prefer the mutable widget pattern over StatefulWidget
//! - Widgets have clear ownership of their state
//!
//! ## Trade-offs
//!
//! **Pros:**
//! - Clear hierarchical organization
//! - Each widget encapsulates its own state
//! - Intuitive parent-child relationships
//! - State ownership is explicit
//!
//! **Cons:**
//! - Complex borrowing scenarios can arise
//! - Requires careful lifetime management
//! - May lead to borrow checker issues in complex hierarchies
//! - Less flexible than StatefulWidget for state sharing
//!
//! ## Example Usage
//!
//! The parent `App` widget contains a child `Counter` widget. Both implement `Widget` for
//! `&mut Self`, allowing them to mutate their respective states during rendering. The parent
//! delegates rendering to the child while maintaining its own state structure.
use ratatui::DefaultTerminal;
use ratatui::buffer::Buffer;
use ratatui::layout::Rect;
use ratatui::widgets::Widget;
use ratatui_state_examples::is_exit_key_pressed;
/// Demonstrates the nested mutable widget pattern for mutable state management.
///
/// Creates a parent-child widget hierarchy using mutable widgets and runs the application loop,
/// updating the counter on each render cycle until the user exits.
fn main() -> color_eyre::Result<()> {
color_eyre::install()?;
let app = App::default();
ratatui::run(|terminal| app.run(terminal))
}
/// The main application widget that contains and manages child widgets.
///
/// Demonstrates the parent widget in a nested mutable widget hierarchy.
#[derive(Default)]
struct App {
counter: Counter,
}
impl App {
/// Run the application with the given terminal.
fn run(mut self, terminal: &mut DefaultTerminal) -> color_eyre::Result<()> {
loop {
terminal.draw(|frame| frame.render_widget(&mut self, frame.area()))?;
if is_exit_key_pressed()? {
break Ok(());
}
}
}
}
impl Widget for &mut App {
fn render(self, area: Rect, buf: &mut Buffer) {
self.counter.render(area, buf);
}
}
/// A counter widget that maintains its own state within a nested hierarchy.
///
/// Can be used standalone or as a child within other widgets, demonstrating
/// how mutable widgets can be composed together.
#[derive(Default)]
struct Counter {
count: usize,
}
impl Widget for &mut Counter {
fn render(self, area: Rect, buf: &mut Buffer) {
self.count += 1;
format!("Counter: {count}", count = self.count).render(area, buf);
}
}