use std::slice::{Iter, IterMut};
#[derive(Default)]
pub struct RowBuilder {
height: RowHeight,
min_height: f64,
max_height: f64,
}
impl RowBuilder {
pub fn new() -> Self {
RowBuilder::default()
}
pub fn height(mut self, height: RowHeight) -> Self {
self.height = height;
self
}
pub fn min_height(mut self, min_height: f64) -> Self {
self.min_height = min_height;
self
}
pub fn max_height(mut self, max_height: f64) -> Self {
self.max_height = max_height;
self
}
pub fn build(self) -> Row {
Row {
height: self.height,
min_height: self.min_height,
max_height: self.max_height,
current_height: 0.0,
}
}
}
#[derive(Copy, Clone, PartialEq, Default, Debug)]
pub struct Row {
pub height: RowHeight,
pub min_height: f64,
pub max_height: f64,
current_height: f64,
}
impl Row {
#[inline]
pub fn create() -> RowBuilder {
RowBuilder::new()
}
pub fn height(&self) -> RowHeight {
self.height
}
pub fn current_height(&self) -> f64 {
self.current_height
}
pub fn set_current_height(&mut self, height: f64) {
self.current_height = if self.min_height == 0.0 && self.max_height == 0.0 && height > 0.0 {
height
} else if height < self.min_height && self.min_height > 0.0 {
self.min_height
} else if height > self.max_height && self.max_height > 0.0 {
self.max_height
} else {
height
};
}
}
impl From<&str> for Row {
fn from(t: &str) -> Self {
match t {
"Auto" | "auto" => Row::create().height(RowHeight::Auto).build(),
_ => Row::create().height(RowHeight::Stretch).build(),
}
}
}
impl From<f64> for Row {
fn from(t: f64) -> Self {
Row::create().height(RowHeight::Height(t)).build()
}
}
impl From<i32> for Row {
fn from(t: i32) -> Self {
Row::create().height(RowHeight::Height(t.into())).build()
}
}
#[derive(Copy, Clone, PartialEq, Debug)]
pub enum RowHeight {
Auto,
Stretch,
Height(f64),
}
impl Default for RowHeight {
fn default() -> Self {
RowHeight::Stretch
}
}
#[derive(Default)]
pub struct RowsBuilder {
row_definitions: Vec<Row>,
}
impl RowsBuilder {
pub fn new() -> Self {
RowsBuilder::default()
}
pub fn push<R: Into<Row>>(mut self, row: R) -> Self {
self.row_definitions.push(row.into());
self
}
#[inline]
#[deprecated = "Use push instead"]
pub fn row<R: Into<Row>>(self, row: R) -> Self {
self.push(row)
}
pub fn rows<R: Into<Row> + Clone>(mut self, rows: &[R]) -> Self {
for row in rows.to_vec() {
self.row_definitions.push(row.into());
}
self
}
pub fn repeat<R: Into<Row> + Copy>(mut self, row: R, count: usize) -> Self {
for _ in 0..count {
self.row_definitions.push(row.into())
}
self
}
pub fn build(self) -> Rows {
Rows(self.row_definitions)
}
}
impl From<RowsBuilder> for Rows {
fn from(builder: RowsBuilder) -> Self {
builder.build()
}
}
#[derive(Debug, Clone, PartialEq, Default)]
pub struct Rows(Vec<Row>);
impl Rows {
#[inline]
pub fn create() -> RowsBuilder {
RowsBuilder::new()
}
pub fn len(&self) -> usize {
self.0.len()
}
pub fn is_empty(&self) -> bool {
self.0.is_empty()
}
pub fn get(&self, row: usize) -> Option<&Row> {
self.0.get(row)
}
pub fn get_mut(&mut self, row: usize) -> Option<&mut Row> {
self.0.get_mut(row)
}
pub fn iter(&self) -> Iter<Row> {
self.0.iter()
}
pub fn iter_mut(&mut self) -> IterMut<Row> {
self.0.iter_mut()
}
}
#[cfg(test)]
mod tests {
use super::*;
const ERROR: f64 = f64::EPSILON;
#[test]
fn test_height() {
let height = RowHeight::Height(64.0);
let builder = RowBuilder::new();
let row = builder.height(height).build();
assert_eq!(row.height, height);
}
#[test]
fn test_min_height() {
let min_height = 64.0;
let builder = RowBuilder::new();
let row = builder.min_height(min_height).build();
assert!((row.min_height - min_height).abs() < ERROR);
}
#[test]
fn test_max_height() {
let max_height = 64.0;
let builder = RowBuilder::new();
let row = builder.max_height(max_height).build();
assert!((row.max_height - max_height).abs() < ERROR);
}
#[test]
fn test_set_current_height() {
let out_one_height = 10.0;
let out_two_height = 66.0;
let in_height = 33.0;
let min_height = 14.0;
let max_height = 64.0;
let builder = RowBuilder::new();
let mut row = builder
.min_height(min_height)
.max_height(max_height)
.build();
row.set_current_height(out_one_height);
assert!((row.current_height() - min_height).abs() < ERROR);
row.set_current_height(out_two_height);
assert!((row.current_height() - max_height).abs() < ERROR);
row.set_current_height(in_height);
assert!((row.current_height() - min_height).abs() < ERROR);
}
#[test]
fn test_row() {
let builder = RowsBuilder::new();
let rows = builder.build();
assert_eq!(rows.len(), 0);
let builder = RowsBuilder::new();
let rows = builder
.push(Row::create().build())
.push(Row::create().build())
.build();
assert_eq!(rows.len(), 2);
}
#[test]
fn test_row_height_into() {
let row: Row = "Auto".into();
assert_eq!(row.height(), RowHeight::Auto);
let row: Row = "auto".into();
assert_eq!(row.height(), RowHeight::Auto);
let row: Row = "Stretch".into();
assert_eq!(row.height(), RowHeight::Stretch);
let row: Row = "stretch".into();
assert_eq!(row.height(), RowHeight::Stretch);
let row: Row = "*".into();
assert_eq!(row.height(), RowHeight::Stretch);
let row: Row = "other".into();
assert_eq!(row.height(), RowHeight::Stretch);
let row: Row = 64.0.into();
assert_eq!(row.height(), RowHeight::Height(64.0));
}
}