1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
use crate::log::tools;

/// Represents a user action
#[derive(Clone, Copy)]
pub struct Action {
  grid_id: usize,
  grid: tools::Grid,
  tool: tools::Tool,

  /// The <i>log</i> grid's coordinates and the <i>user interface</i> grid's
  /// coordinates are different. In <i>log</i> grid's coordinates starts
  /// to 0, but in the the <i>user interface</i>, it depends of the terminal
  /// size and where the grid area is supposed to be on the <i>user
  /// interface</i>. The <i>log</i> have to modify it's own grid's coordinates
  /// system to fit with the grid's coordinates system. The <i>checked</i>
  /// member allows to know if the <i>log</i> fitted its grid's coordinates
  /// system for the tested action. The <i>checked</i> member only matters for
  /// cells setter tools.
  checked: bool,
}

impl PartialEq for Action {
  fn eq(&self, other: &Self) -> bool {
    (self.grid_id == other.grid_id) && (self.grid == other.grid) &&
    (self.tool == other.tool)
  }
}

impl Action {
  pub fn new((grid, grid_id): (tools::Grid, usize), tool: tools::Tool)
    -> Action {
      Action {
        grid_id: grid_id,
        grid: grid,
        tool: tool,
        checked: false,
      }
  }

  pub fn get_grid_id(&self) -> usize {
    self.grid_id
  }

  pub fn get_grid(&self) -> tools::Grid {
    self.grid
  }

  pub fn get_tool(&self) -> tools::Tool {
    self.tool
  }

  pub fn is_checked(&self) -> bool {
    self.checked
  }

  /// Creates a new Action object with fitted grid's coordinates to the
  /// <i>user interface</i> system.
  pub fn corrected(&self, left: Option<u16>, top: Option<u16>) -> Action {
    if !self.is_checked() {
      Action {
        grid_id: self.grid_id,
        grid: self.grid,
        tool: match self.tool {
                tools::Tool::WorkspaceSetter(_) => self.tool,
                tools::Tool::GridSetter(_) => self.tool,
                tools::Tool::CellSetter(cell_tool) => {
                  match cell_tool {
                    tools::CellTool::PixelBrush(pixel, x, y) =>
                      tools::Tool::CellSetter(tools::CellTool::PixelBrush(
                        pixel, x - left.unwrap(), y - top.unwrap())),
                    tools::CellTool::PixelEraser(x, y) =>
                      tools::Tool::CellSetter(tools::CellTool::PixelEraser(
                        x - left.unwrap(), y - top.unwrap())),
                  }
                },
              },
        checked: true,
      }
    } else {
      *self
    }
  }
}

#[cfg(test)]
mod tests {

  use super::*;
  use crate::utils::FullPixel;

  #[test]
  fn it_corrects_a_brush_action() {
    let (left_correction, top_correction) = (Some(5), Some(2));
    let (brush_x, brush_y) = (8, 8);
    let mut action = Action::new((tools::Grid::Generation, 0),
      tools::Tool::CellSetter(tools::CellTool::PixelBrush(
        FullPixel::Body, brush_x, brush_y)));
    let not_checked = action.checked;
    action = action.corrected(left_correction, top_correction);
    if let tools::Tool::CellSetter(cell_tool) = action.get_tool() {
      if let tools::CellTool::PixelBrush(_pixel, x, y) = cell_tool {
        assert!(!not_checked && action.checked &&
          (x == brush_x - left_correction.unwrap()) &&
          (y == brush_y - top_correction.unwrap()));
      }
    }
  }

  #[test]
  fn it_corrects_an_eraser_action() {
    let (left_correction, top_correction) = (Some(2), Some(5));
    let (eraser_x, eraser_y) = (3, 18);
    let mut action = Action::new((tools::Grid::Generation, 0),
      tools::Tool::CellSetter(tools::CellTool::PixelEraser(
        eraser_x, eraser_y)));
    let not_checked = action.checked;
    action = action.corrected(left_correction, top_correction);
    if let tools::Tool::CellSetter(cell_tool) = action.get_tool() {
      if let tools::CellTool::PixelEraser(x, y) = cell_tool {
        assert!(!not_checked && action.checked &&
          (x == eraser_x - left_correction.unwrap()) &&
          (y == eraser_y - top_correction.unwrap()));
      }
    }
  }

  #[test]
  fn it_does_not_correct_a_checked_action() {
    let (left_correction, top_correction) = (Some(2), Some(5));
    let (eraser_x, eraser_y) = (3, 18);
    let mut action = Action::new((tools::Grid::Generation, 0),
      tools::Tool::CellSetter(tools::CellTool::PixelEraser(
        eraser_x, eraser_y)));
    action.checked = true;
    let checked = action.checked;
    action = action.corrected(left_correction, top_correction);
    if let tools::Tool::CellSetter(cell_tool) = action.get_tool() {
      if let tools::CellTool::PixelEraser(x, y) = cell_tool {
        assert!(checked && action.checked && (x == eraser_x) &&
          (y == eraser_y));
      }
    }
  }
}