gooey/interface/view/component/
canvas.rs

1use derive_more::{From, TryInto};
2
3use crate::interface::view::{dimensions, position, Border, Color, Coordinates};
4use super::impl_kind;
5
6#[derive(Clone, Debug, Eq, PartialEq)]
7pub struct Canvas {
8  pub coordinates : Coordinates,
9  pub clear_color : ClearColor,
10  pub border      : Option <Border>
11}
12impl_kind!(Canvas);
13
14/// Indicates to the Presentation backend how the Canvas should be cleared.
15///
16/// Default is `Appearance`, meaning the Presentation backend will clear the
17/// Canvas if the current Appearance has a Style bg Color.
18#[derive(Clone, Debug, Eq, PartialEq, From, TryInto)]
19pub enum ClearColor {
20  /// Use the Style bg Color of the current Appearance.
21  ///
22  /// If the current Appearance does not have a Style, then the clear color is
23  /// unspecified and the Presentation backend may not clear the Canvas.
24  Appearance,
25  /// Always clear with the given Color.
26  ///
27  /// If 'None', then the Presentation backend may not clear the Canvas.
28  Fixed (Option <Color>)
29}
30
31impl Canvas {
32  pub fn default_tile() -> Self {
33    Canvas {
34      coordinates: (position::Tile::default(), dimensions::Tile::default())
35        .into(),
36      clear_color: ClearColor::default(),
37      border:      None
38    }
39  }
40  pub fn default_pixel() -> Self {
41    Canvas {
42      coordinates: (position::Pixel::default(), dimensions::Pixel::default())
43        .into(),
44      clear_color: ClearColor::default(),
45      border:      None
46    }
47  }
48  pub fn body_wh (&self) -> (u32, u32) {
49    self.border.as_ref().map (|border|{
50      let (border_width, border_height) = border.total_wh();
51      let width  = self.coordinates.dimensions_horizontal();
52      let height = self.coordinates.dimensions_vertical();
53      ( width.saturating_sub  (border_width  as u32),
54        height.saturating_sub (border_height as u32)
55      )
56    }).unwrap_or_else (||(
57      self.coordinates.dimensions().horizontal() as u32,
58      self.coordinates.dimensions().vertical()   as u32))
59  }
60  /// Computes the coordinates (position, dimensions) of the inner body area
61  /// (inside the border)
62  pub fn body_coordinates (&self) -> Coordinates {
63    let border_left = self.border.as_ref().map (|border| border.thickness_left)
64      .unwrap_or (0);
65    match self.coordinates {
66      Coordinates::Tile  (position, _) => {
67        let border_top = self.border.as_ref().map (|border| border.thickness_top)
68          .unwrap_or (0);
69        let (columns, rows) = self.body_wh();
70        let row    = position.row()    + border_top  as i32;
71        let column = position.column() + border_left as i32;
72        ( position::Tile::new_rc (row, column),
73          dimensions::Tile::new_rc (rows, columns)
74        ).into()
75      }
76      Coordinates::Pixel (position, _) => {
77        let border_bottom = self.border.as_ref()
78          .map (|border| border.thickness_bottom).unwrap_or (0);
79        let (width, height) = self.body_wh();
80        let x = position.0.x + border_left   as i32;
81        let y = position.0.y + border_bottom as i32;
82        ( position::Pixel::new_xy (x, y),
83          dimensions::Pixel::new_wh (width, height)
84        ).into()
85      }
86    }
87  }
88}
89
90impl Default for ClearColor {
91  fn default() -> Self {
92    ClearColor::Appearance
93  }
94}