use crate::grid::config::{GridConfig, RowConfig};
#[derive(Debug)]
pub struct ZoneModel {
pub rows: Vec<RowZone>,
total_row_ratio: u32,
}
#[derive(Debug)]
pub struct RowZone {
pub name: String,
pub ratio: u32,
pub kind: RowKind,
}
#[derive(Debug)]
pub enum RowKind {
Fixed { element: String },
Columns(Vec<ColumnZone>),
Empty,
}
#[derive(Debug)]
pub struct ColumnZone {
pub name: String,
pub ratio: u32,
pub module: Option<String>,
}
impl ZoneModel {
pub fn from_config(config: &GridConfig) -> Self {
let total_row_ratio = config.rows.iter().map(|r| r.ratio).sum();
let rows = config.rows.iter().map(RowZone::from_config).collect();
Self {
rows,
total_row_ratio,
}
}
pub fn total_row_ratio(&self) -> u32 {
self.total_row_ratio
}
pub fn row(&self, name: &str) -> Option<&RowZone> {
self.rows.iter().find(|r| r.name == name)
}
pub fn column(&self, row_name: &str, col_name: &str) -> Option<&ColumnZone> {
self.row(row_name).and_then(|r| match &r.kind {
RowKind::Columns(cols) => cols.iter().find(|c| c.name == col_name),
_ => None,
})
}
pub fn set_module(&mut self, row_name: &str, col_name: &str, module: &str) {
if let Some(row) = self.rows.iter_mut().find(|r| r.name == row_name) {
row.set_column_module(col_name, module);
}
}
}
impl RowZone {
fn set_column_module(&mut self, col_name: &str, module: &str) {
if let RowKind::Columns(cols) = &mut self.kind {
if let Some(col) = cols.iter_mut().find(|c| c.name == col_name) {
col.module = Some(module.to_string());
}
}
}
fn from_config(config: &RowConfig) -> Self {
let kind = if let Some(fixed) = &config.fixed {
RowKind::Fixed {
element: fixed.to_owned(),
}
} else if !config.columns.is_empty() {
RowKind::Columns(
config
.columns
.iter()
.map(|c| ColumnZone {
name: c.name.clone(),
ratio: c.ratio,
module: None,
})
.collect(),
)
} else {
RowKind::Empty
};
Self {
name: config.name.clone(),
ratio: config.ratio,
kind,
}
}
pub fn total_column_ratio(&self) -> u32 {
match &self.kind {
RowKind::Columns(cols) => cols.iter().map(|c| c.ratio).sum(),
_ => 0,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::grid::config::TargetConfig;
use std::path::Path;
#[test]
fn zone_model_from_desktop_config() {
let config = TargetConfig::load(Path::new("config/desktop.toml")).unwrap();
let zones = ZoneModel::from_config(&config.grid);
assert_eq!(zones.rows.len(), 3);
assert_eq!(zones.total_row_ratio(), 12);
let top = zones.row("top").unwrap();
assert!(matches!(&top.kind, RowKind::Fixed { element } if element == "nav-bar"));
let main = zones.row("main").unwrap();
assert_eq!(main.total_column_ratio(), 10);
let bottom = zones.row("bottom").unwrap();
assert!(matches!(&bottom.kind, RowKind::Fixed { element } if element == "status-bar"));
}
#[test]
fn set_module_in_zone() {
let config = TargetConfig::load(Path::new("config/desktop.toml")).unwrap();
let mut zones = ZoneModel::from_config(&config.grid);
zones.set_module("main", "left", "file-tree");
zones.set_module("main", "center", "code-editor");
let left = zones.column("main", "left").unwrap();
assert_eq!(left.module.as_deref(), Some("file-tree"));
let center = zones.column("main", "center").unwrap();
assert_eq!(center.module.as_deref(), Some("code-editor"));
let right = zones.column("main", "right").unwrap();
assert!(right.module.is_none());
}
}