tuigui 0.23.0

An easy-to-use, highly extensible, and speedy TUI library.
Documentation
use std::rc::Rc;

use crate::Position;

#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub enum MouseButton {
    Left,
    Middle,
    Right,
}

#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct EventStateFrame {
    /// Mouse
    pub mouse: MouseStateFrame,
    /// Terminal
    pub terminal: TerminalStateFrame,
}

#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct EventState {
    /// Mouse
    pub mouse: MouseState,
    /// Terminal
    pub terminal: TerminalState,
}

impl EventState {
    pub fn new() -> Self {
        Self {
            mouse: MouseState::new(),
            terminal: TerminalState::new(),
        }
    }

    #[inline(always)]
    pub fn calculate_frame(&self, prev: Self) -> EventStateFrame {
        return EventStateFrame {
            mouse: self.mouse.calculate_frame(prev.mouse),
            terminal: self.terminal.calculate_frame(prev.terminal),
        };
    }
}

#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub enum Focus {
    /// Has been focused
    Focused,
    /// Has been unfocused
    Unfocused,
    /// Just gained focus
    JustNowFocused,
    /// Just lost focus
    JustNowUnfocused,
}

impl Focus {
    #[inline(always)]
    pub fn calculate(current: bool, prev: bool) -> Self {
        return match (current, prev) {
            (true, true) => Focus::Focused,
            (false, false) => Focus::Unfocused,
            (true, false) => Focus::JustNowFocused,
            (false, true) => Focus::JustNowUnfocused,
        };
    }
}

#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct TerminalStateFrame {
    /// Focused or not
    pub focused: Focus,
    /// Pasted text
    pub paste: Option<Rc<String>>,
}

#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct TerminalState {
    /// Focused or not
    pub focused: bool,
    /// Pasted text
    pub paste: Option<Rc<String>>,
}

impl TerminalState {
    pub fn new() -> Self {
        Self {
            focused: true,
            paste: None,
        }
    }

    #[inline(always)]
    pub fn calculate_frame(&self, prev: Self) -> TerminalStateFrame {
        return TerminalStateFrame {
            focused: Focus::calculate(self.focused, prev.focused),
            paste: self.paste.clone(),
        };
    }
}

#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct MouseStateFrame {
    /// Mouse buttons
    pub buttons: MouseButtonsStateFrame,
    /// Mouse position for things like click events
    pub position: Position,
    /// Mouse scroll difference
    pub scroll: Position,
}

#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct MouseState {
    /// Mouse buttons
    pub buttons: MouseButtonsState,
    /// Mouse position
    pub position: Position,
    /// Mouse scroll
    pub scroll: MouseScrollState,
}

impl MouseState {
    pub fn new() -> Self {
        Self {
            buttons: MouseButtonsState::new(),
            position: Position::zero(),
            scroll: MouseScrollState::new(),
        }
    }

    #[inline(always)]
    pub fn calculate_frame(&self, prev: Self) -> MouseStateFrame {
        return MouseStateFrame {
            buttons: self.buttons.calculate_frame(prev.buttons),
            position: self.position,
            scroll: self.scroll.scroll_diff(prev.scroll),
        };
    }
}

#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct MouseScrollState {
    /// Left and right
    pub cols: i64,
    /// Up and down
    pub rows: i64,
}

impl MouseScrollState {
    pub fn new() -> Self {
        Self {
            cols: 0,
            rows: 0,
        }
    }

    #[inline(always)]
    /// Returns offset between current and previous scroll states
    pub fn scroll_diff(&self, prev: Self) -> Position {
        // Yeah, some assumptions are happening here...
        return Position::new(
            (self.cols - prev.cols) as i16,
            (self.rows - prev.rows) as i16,
        );
    }

    #[inline(always)]
    /// Scroll up
    pub fn go_up(&mut self, amount: i16) {
        self.rows -= amount as i64;
    }

    #[inline(always)]
    /// Scroll up
    pub fn go_down(&mut self, amount: i16) {
        self.rows += amount as i64;
    }

    #[inline(always)]
    /// Scroll up
    pub fn go_left(&mut self, amount: i16) {
        self.cols -= amount as i64;
    }

    #[inline(always)]
    /// Scroll up
    pub fn go_right(&mut self, amount: i16) {
        self.cols += amount as i64;
    }
}

#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct MouseButtonsState {
    /// Left button
    pub left: bool,
    /// Middle button (scroll wheel button)
    pub middle: bool,
    /// Right button
    pub right: bool,
}

impl MouseButtonsState {
    pub fn new() -> Self {
        Self {
            left: false,
            middle: false,
            right: false,
        }
    }

    #[inline(always)]
    pub fn is_down(&self, button: MouseButton) -> bool {
        return match button {
            MouseButton::Left => self.left,
            MouseButton::Middle => self.middle,
            MouseButton::Right => self.right,
        };
    }

    #[inline(always)]
    pub fn calculate_frame(&self, prev: Self) -> MouseButtonsStateFrame {
        return MouseButtonsStateFrame {
            left: MouseButtonFrame::calculate(self.left, prev.left),
            middle: MouseButtonFrame::calculate(self.middle, prev.middle),
            right: MouseButtonFrame::calculate(self.right, prev.right),
        };
    }
}

#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub enum MouseButtonFrame {
    /// The mouse button is up and has been up
    Up,
    /// The mouse button is down and has been down
    Down,
    /// The mouse button has just been pressed
    Pressed,
    /// The mouse button has just been released
    Released,
}

impl MouseButtonFrame {
    #[inline(always)]
    pub fn calculate(current: bool, prev: bool) -> Self {
        return match (current, prev) {
            (false, false) => MouseButtonFrame::Up,
            (true, true) => MouseButtonFrame::Down,
            (true, false) => MouseButtonFrame::Pressed,
            (false, true) => MouseButtonFrame::Released,
        };
    }
}

#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct MouseButtonsStateFrame {
    /// Left button
    pub left: MouseButtonFrame,
    /// Middle button (scroll wheel button)
    pub middle: MouseButtonFrame,
    /// Right button
    pub right: MouseButtonFrame,
}