bracket-state-machine 0.2.0

State management library for bracket-lib terminal
Documentation
use std::{fmt::format, time::Duration};

use bracket_lib::prelude::*;
use bracket_state_machine::prelude::*;

pub type TransitionResult = (StateTransition<Game, ModeResult>, TransitionControl);

#[derive(Default)]
struct TitleState;
struct PausedState;

#[derive(Clone)]
pub enum TitleResult {
    Quit,
}

#[derive(Clone)]
pub enum ModeResult {
    TitleResult(TitleResult),
    PausedResult(PausedResult),
}

impl State for TitleState {
    type State = Game;
    type StateResult = ModeResult;

    fn update(
        &mut self,
        term: &mut BTerm,
        state: &mut Self::State,
        _pop_result: &Option<Self::StateResult>,
        dt: Duration,
    ) -> TransitionResult {
        if let Some(key) = term.key {
            match key {
                VirtualKeyCode::Escape => {
                    return (StateTransition::Terminate, TransitionControl::Update);
                }
                VirtualKeyCode::Space => {
                    return (
                        StateTransition::Push(Box::new(PausedState)),
                        TransitionControl::Update,
                    );
                }
                VirtualKeyCode::Up => {
                    state.num += 1;
                }
                VirtualKeyCode::Down => {
                    state.num -= 1;
                }
                _ => {}
            }

            if key == VirtualKeyCode::Space {
                return (
                    Transition::Push(Box::new(PausedState)),
                    TransitionControl::Update,
                );
            }
        }

        (Transition::Stay, TransitionControl::Update)
    }

    fn render(&self, term: &mut BTerm, state: &Self::State, active: bool) {
        term.print(
            1,
            2,
            "Press [UP] to increment counter and [DOWN] to decrement counter.",
        );
        term.print(1, 4, "Press [ESC] to close & [SPACE] to transition");
        term.print(1, 6, format!("State: {:?}", state));
    }

    fn clear(&self, _state: &Self::State, _term: &mut BTerm) {
        BACKEND_INTERNAL
            .lock()
            .consoles
            .iter_mut()
            .for_each(|c| c.console.cls());
    }

    fn is_transparent(&self) -> bool {
        true
    }
}

#[derive(Clone)]
pub enum PausedResult {
    Resume,
    Quit,
}

impl State for PausedState {
    type State = Game;
    type StateResult = ModeResult;

    fn update(
        &mut self,
        term: &mut BTerm,
        state: &mut Self::State,
        _pop_result: &Option<ModeResult>,
        _dt: Duration,
    ) -> TransitionResult {
        if let Some(key) = term.key {
            if key == VirtualKeyCode::Space {
                return (
                    Transition::Pop(ModeResult::PausedResult(PausedResult::Resume)),
                    TransitionControl::Update,
                );
            }
        }

        (Transition::Stay, TransitionControl::Update)
    }

    fn render(&self, term: &mut BTerm, state: &Self::State, active: bool) {
        term.print_centered(0, format!("PAUSED {:?}", state));
    }
}

#[derive(Debug)]
pub struct Game {
    pub num: i32,
}

fn main() -> BError {
    let context = BTermBuilder::simple80x50()
        .with_title("State Machine Sample")
        .with_dimensions(100, 70)
        .with_fps_cap(24.0)
        .build()
        .expect("failed to build a BTerm");

    let machine = StateMachine::new(Game { num: 0 }, TitleState::default());
    main_loop(context, machine)
}