fp_tui 0.2.2

A very basic tui library
Documentation
use std::rc::Rc;
use std::cell::RefCell;

use crate::Widget;
use crate::common::{BoundingBox, Dimensions, Position};

/// #### Description
/// A widget for drawing on a 2d canvas
/// 
/// Currently there is minimal functionality for this, it might be expanded upon
/// in the future
/// 
pub struct CanvasWidget {
    /// #### Description
    /// The bounds of the canvas
    /// 
    bounding_box: BoundingBox,

    /// #### Description
    /// A buffer of characters to draw to
    /// 
    buffer: Box<[Box<[char]>]>
}

impl CanvasWidget {
    /// #### Description
    /// Creates a new canvas widget
    /// 
    /// #### Arguments
    /// * `x`: [i32] - The x position of the widget
    /// * `y`: [i32] - The y position of the widget
    /// * `width`: [u32] - The width of the widget
    /// * `height`: [u32] - The height of the widget
    /// 
    pub fn new(x: i32, y: i32, width: u32, height: u32) -> Rc<RefCell<Self>> {
        let bounding_box = BoundingBox::new(
            Position::new(x, y),
            Dimensions::new(width, height)
        );

        let mut buffer_vec = vec![];
        let row_vec = vec![' '; width as usize];

        for _ in 0..height {
            buffer_vec.push(
                row_vec.clone().into_boxed_slice()
            );
        }

        return Rc::new(RefCell::new(Self {
            bounding_box,
            buffer: buffer_vec.into_boxed_slice()
        }));
    }

    /// #### Description
    /// Retrieves the width of the canvas
    ///
    /// #### Returns
    /// [u32] - The width of the canvas
    ///
    pub fn get_width(&self) -> u32 {
        return self.get_bounding_box().get_width();
    }

    /// #### Description
    /// Retrieves the height of the display buffer
    ///
    /// #### Returns
    /// [u32] - The height of the display buffer
    ///
    pub fn get_height(&self) -> u32 {
        return self.get_bounding_box().get_height();
    }

    /// #### Description
    /// Draws a character to the canvas
    ///
    /// If the coordinates are out of the bounds of the canvas it ignores the 
    /// write
    ///
    /// #### Arguments
    /// * `c`: [char] - The character to insert
    /// * `x`: [u32] - The x position to write to
    /// * `y`: [u32] - The y position to write to
    ///
    pub fn set_char(&mut self, c: char, x: i32, y: i32) {
        // Guard for detecting if the coordinates are in bounds
        if self.get_bounding_box().get_width() <= x as u32 || 
           self.get_bounding_box().get_height() <= y as u32 ||
           x < 0 ||
           y < 0
        {
            return;
        }
        else {
            self.buffer[y as usize][x as usize] = c;
        }
    }

    /// #### Description
    /// Clears the canvas to a specified character
    ///
    /// #### Arguments
    /// * `c`: [char] - The character to clear with
    ///
    pub fn clear(&mut self, c: char) {
        for y in 0..self.get_bounding_box().get_height() {
            for x in 0..self.get_bounding_box().get_width() {
                self.buffer[y as usize][x as usize] = c;
            }
        }
    }
}

impl Widget for CanvasWidget {
    fn draw(
            &mut self,
            positioning_algorithm: &Box<dyn crate::PositioningAlgorithm>,
            display_buffer: &mut crate::DisplayBuffer
        ) {
        let abs_pos = positioning_algorithm.calculate_position(
            self.bounding_box.get_position()
        );

        for y in 0..self.get_bounding_box().get_height() {
            for x in 0..self.get_bounding_box().get_width() {
                display_buffer.set_char(
                    self.buffer[y as usize][x as usize],
                    x as i32 + abs_pos.get_x(),
                    y as i32 + abs_pos.get_y()
                );
            }
        }
    }

    fn get_bounding_box(&self) -> crate::common::BoundingBox {
        return self.bounding_box;
    }
}