gooey-rs 0.12.1

Tile-based UI library with audio support
Documentation
use derive_more::{From, TryInto};

use crate::interface::view::{dimensions, position, Border, Color, Coordinates};
use super::impl_kind;

#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Canvas {
  pub coordinates : Coordinates,
  pub clear_color : ClearColor,
  pub border      : Option <Border>
}
impl_kind!(Canvas);

/// Indicates to the `Presentation` backend how the `Canvas` should be cleared.
///
/// Default is `Appearance`, meaning the `Presentation` backend will clear the
/// `Canvas` if the current `Appearance` has a `Style` bg `Color`.
#[derive(Clone, Debug, Default, Eq, PartialEq, From, TryInto)]
pub enum ClearColor {
  /// Use the `Style` bg `Color` of the current `Appearance`.
  ///
  /// If the current `Appearance` does not have a `Style`, then the clear color is
  /// unspecified and the `Presentation` backend may not clear the `Canvas`.
  #[default]
  Appearance,
  /// Always clear with the given `Color`.
  ///
  /// If 'None', then the Presentation backend may not clear the `Canvas`.
  Fixed (Option <Color>)
}

impl Canvas {
  pub fn default_tile() -> Self {
    Canvas {
      coordinates: (position::Tile::default(), dimensions::Tile::default()).into(),
      clear_color: ClearColor::default(),
      border:      None
    }
  }
  pub fn default_pixel() -> Self {
    Canvas {
      coordinates: (position::Pixel::default(), dimensions::Pixel::default()).into(),
      clear_color: ClearColor::default(),
      border:      None
    }
  }
  pub fn body_wh (&self) -> (u32, u32) {
    self.border.as_ref().map_or_else (||
      ( self.coordinates.dimensions().horizontal(),
        self.coordinates.dimensions().vertical() ),
      |border|{
        let (border_width, border_height) = border.total_wh();
        let width  = self.coordinates.dimensions_horizontal();
        let height = self.coordinates.dimensions_vertical();
        ( width.saturating_sub  (border_width  as u32),
          height.saturating_sub (border_height as u32)
        )
      })
  }
  /// Computes the coordinates (position, dimensions) of the inner body area (inside the
  /// border)
  pub fn body_coordinates (&self) -> Coordinates {
    let border_left = self.border.as_ref().map_or (0, |border| border.thickness_left);
    match self.coordinates {
      Coordinates::Tile  (position, _) => {
        let border_top = self.border.as_ref().map_or (0, |border| border.thickness_top);
        let (columns, rows) = self.body_wh();
        let row    = position.row()    + border_top  as i32;
        let column = position.column() + border_left as i32;
        ( position::Tile::new_rc (row, column),
          dimensions::Tile::new_rc (rows, columns)
        ).into()
      }
      Coordinates::Pixel (position, _) => {
        let border_bottom = self.border.as_ref()
          .map_or (0, |border| border.thickness_bottom);
        let (width, height) = self.body_wh();
        let x = position.0.x + border_left   as i32;
        let y = position.0.y + border_bottom as i32;
        ( position::Pixel::new_xy (x, y),
          dimensions::Pixel::new_wh (width, height)
        ).into()
      }
    }
  }
}