Skip to main content

MenuSystem

Struct MenuSystem 

Source
pub struct MenuSystem<'prov, M: MenuProvider> {
    pub current_menu: M::MenuId,
    pub cursor: u8,
    pub scroll_offset: u8,
    /* private fields */
}
Expand description

Stateful menu controller that owns cursor position, scroll offset, and open/closed state.

MenuSystem is parameterised over the MenuProvider implementation, so it can call into the provider for data without any downcasting or dynamic dispatch overhead.

Fields§

§current_menu: M::MenuId

Which menu is currently active.

§cursor: u8

0-based index of the currently-highlighted option.

§scroll_offset: u8

Scroll offset (for scrollable menus). 0 = first visible option is at index 0 in the full option list.

Implementations§

Source§

impl<'prov, M: MenuProvider> MenuSystem<'prov, M>

Source

pub fn new(provider: &'prov M) -> Self

Create a new MenuSystem backed by provider. The menu starts closed; call open to activate it.

Examples found in repository?
examples/hello_dotzuki.rs (line 527)
524fn demo_menu() {
525    println!("\n╔══ MENU NAVIGATION ═════════════════════╗");
526    let provider = HelloConfig::new();
527    let mut menu = MenuSystem::new(&provider);
528    menu.open(MenuScreen::Main);
529
530    println!("║ Menu '{}' — 3 options", provider.title(MenuScreen::Main));
531    for (i, opt) in provider.main_menu_options.iter().enumerate() {
532        let marker = if i == menu.cursor as usize { ">" } else { " " };
533        println!("║  {} {}{}", marker, opt.label, if opt.enabled { "" } else { " (disabled)" });
534    }
535
536    // Navigate down × 2
537    menu.handle_input(&MenuInput { down: true, ..Default::default() });
538    menu.handle_input(&MenuInput { down: true, ..Default::default() });
539    println!("║ Cursor after 2× Down: {}", menu.cursor);
540
541    // Select
542    let action = menu.handle_input(&MenuInput { confirm: true, ..Default::default() });
543    println!("║ Confirm → {:?} ('{}')", action,
544        menu.selected_option().map(|o| o.label.as_str()).unwrap_or("?"));
545    println!("╚══════════════════════════════════════════╝");
546}
Source

pub fn open(&mut self, menu: M::MenuId)

Open a specific menu, resetting cursor and scroll to their defaults.

Examples found in repository?
examples/hello_dotzuki.rs (line 528)
524fn demo_menu() {
525    println!("\n╔══ MENU NAVIGATION ═════════════════════╗");
526    let provider = HelloConfig::new();
527    let mut menu = MenuSystem::new(&provider);
528    menu.open(MenuScreen::Main);
529
530    println!("║ Menu '{}' — 3 options", provider.title(MenuScreen::Main));
531    for (i, opt) in provider.main_menu_options.iter().enumerate() {
532        let marker = if i == menu.cursor as usize { ">" } else { " " };
533        println!("║  {} {}{}", marker, opt.label, if opt.enabled { "" } else { " (disabled)" });
534    }
535
536    // Navigate down × 2
537    menu.handle_input(&MenuInput { down: true, ..Default::default() });
538    menu.handle_input(&MenuInput { down: true, ..Default::default() });
539    println!("║ Cursor after 2× Down: {}", menu.cursor);
540
541    // Select
542    let action = menu.handle_input(&MenuInput { confirm: true, ..Default::default() });
543    println!("║ Confirm → {:?} ('{}')", action,
544        menu.selected_option().map(|o| o.label.as_str()).unwrap_or("?"));
545    println!("╚══════════════════════════════════════════╝");
546}
Source

pub fn close(&mut self)

Close the menu.

Source

pub fn is_open(&self) -> bool

Returns true if the menu is currently open.

Source

pub fn handle_input(&mut self, input: &MenuInput) -> MenuAction

Process one frame of abstract input and return a MenuAction.

The caller should call this once per frame with the aggregated directional / confirm / cancel state.

Examples found in repository?
examples/hello_dotzuki.rs (line 537)
524fn demo_menu() {
525    println!("\n╔══ MENU NAVIGATION ═════════════════════╗");
526    let provider = HelloConfig::new();
527    let mut menu = MenuSystem::new(&provider);
528    menu.open(MenuScreen::Main);
529
530    println!("║ Menu '{}' — 3 options", provider.title(MenuScreen::Main));
531    for (i, opt) in provider.main_menu_options.iter().enumerate() {
532        let marker = if i == menu.cursor as usize { ">" } else { " " };
533        println!("║  {} {}{}", marker, opt.label, if opt.enabled { "" } else { " (disabled)" });
534    }
535
536    // Navigate down × 2
537    menu.handle_input(&MenuInput { down: true, ..Default::default() });
538    menu.handle_input(&MenuInput { down: true, ..Default::default() });
539    println!("║ Cursor after 2× Down: {}", menu.cursor);
540
541    // Select
542    let action = menu.handle_input(&MenuInput { confirm: true, ..Default::default() });
543    println!("║ Confirm → {:?} ('{}')", action,
544        menu.selected_option().map(|o| o.label.as_str()).unwrap_or("?"));
545    println!("╚══════════════════════════════════════════╝");
546}
Source

pub fn selected_option(&self) -> Option<&MenuOption>

Return the currently-selected option, or None if the cursor is out of range or the menu is closed.

Examples found in repository?
examples/hello_dotzuki.rs (line 544)
524fn demo_menu() {
525    println!("\n╔══ MENU NAVIGATION ═════════════════════╗");
526    let provider = HelloConfig::new();
527    let mut menu = MenuSystem::new(&provider);
528    menu.open(MenuScreen::Main);
529
530    println!("║ Menu '{}' — 3 options", provider.title(MenuScreen::Main));
531    for (i, opt) in provider.main_menu_options.iter().enumerate() {
532        let marker = if i == menu.cursor as usize { ">" } else { " " };
533        println!("║  {} {}{}", marker, opt.label, if opt.enabled { "" } else { " (disabled)" });
534    }
535
536    // Navigate down × 2
537    menu.handle_input(&MenuInput { down: true, ..Default::default() });
538    menu.handle_input(&MenuInput { down: true, ..Default::default() });
539    println!("║ Cursor after 2× Down: {}", menu.cursor);
540
541    // Select
542    let action = menu.handle_input(&MenuInput { confirm: true, ..Default::default() });
543    println!("║ Confirm → {:?} ('{}')", action,
544        menu.selected_option().map(|o| o.label.as_str()).unwrap_or("?"));
545    println!("╚══════════════════════════════════════════╝");
546}
Source

pub fn render<P: Painter>(&self, painter: &mut P)

Render the menu onto painter using the Painter trait.

This draws the text box, title, options, and cursor indicator through the backend-agnostic Painter interface. TUI and pixel backends produce identical visual output (modulo resolution).

Auto Trait Implementations§

§

impl<'prov, M> Freeze for MenuSystem<'prov, M>
where <M as MenuProvider>::MenuId: Freeze,

§

impl<'prov, M> RefUnwindSafe for MenuSystem<'prov, M>

§

impl<'prov, M> Send for MenuSystem<'prov, M>
where <M as MenuProvider>::MenuId: Send, M: Sync,

§

impl<'prov, M> Sync for MenuSystem<'prov, M>
where <M as MenuProvider>::MenuId: Sync, M: Sync,

§

impl<'prov, M> Unpin for MenuSystem<'prov, M>
where <M as MenuProvider>::MenuId: Unpin,

§

impl<'prov, M> UnsafeUnpin for MenuSystem<'prov, M>

§

impl<'prov, M> UnwindSafe for MenuSystem<'prov, M>

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.