use papergrid::{
records::{Records, RecordsMut, Resizable},
width::CfgWidthFunction,
Position,
};
use crate::{width::wrap_text, Table, TableOption};
#[derive(Debug)]
pub struct Panel;
impl Panel {
pub fn vertical(column: usize) -> VerticalPanel<&'static str> {
VerticalPanel {
pos: (0, column),
text: "",
text_width: 0,
}
}
pub fn horizontal(row: usize) -> HorizontalPanel<&'static str> {
HorizontalPanel {
text: "",
pos: (row, 0),
}
}
pub fn header<S>(text: S) -> Header<S> {
Header(text)
}
pub fn footer<S>(text: S) -> Footer<S> {
Footer(text)
}
}
#[derive(Debug)]
pub struct VerticalPanel<S> {
text: S,
pos: Position,
text_width: usize,
}
impl<S> VerticalPanel<S> {
pub fn text<T>(self, text: T) -> VerticalPanel<T>
where
T: AsRef<str> + Clone,
{
VerticalPanel {
pos: self.pos,
text_width: self.text_width,
text,
}
}
pub fn row(mut self, row: usize) -> Self {
self.pos.0 = row;
self
}
pub fn text_width(mut self, width: usize) -> Self {
self.text_width = width;
self
}
fn get_text(&self) -> String
where
S: AsRef<str>,
{
let text = if self.text_width > 0 {
wrap_text(self.text.as_ref(), self.text_width, false)
} else {
self.text.as_ref().to_owned()
};
text
}
}
impl<S, R> TableOption<R> for VerticalPanel<S>
where
S: AsRef<str> + Clone,
R: Records + RecordsMut<String> + Resizable,
{
fn change(&mut self, table: &mut Table<R>) {
let (count_rows, count_cols) = table.shape();
if self.pos.1 > count_cols || self.pos.0 > count_rows {
return;
}
move_columns_aside(table, self.pos.1);
move_column_spans(table, self.pos.1);
let text = self.get_text();
set_text(table, self.pos, text);
let length = count_rows.checked_sub(self.pos.0).unwrap_or(1);
table.get_config_mut().set_row_span(self.pos, length);
table.destroy_width_cache();
table.destroy_height_cache();
}
}
#[derive(Debug)]
pub struct HorizontalPanel<S> {
text: S,
pos: Position,
}
impl<S> HorizontalPanel<S> {
pub fn text<T>(self, text: T) -> HorizontalPanel<T>
where
T: AsRef<str> + Clone,
{
HorizontalPanel {
pos: self.pos,
text,
}
}
pub fn column(mut self, column: usize) -> Self {
self.pos.1 = column;
self
}
}
impl<S, R> TableOption<R> for HorizontalPanel<S>
where
S: AsRef<str> + Clone,
R: Records + RecordsMut<String> + Resizable,
{
fn change(&mut self, table: &mut Table<R>) {
let (count_rows, count_cols) = table.shape();
if self.pos.0 > count_rows {
return;
}
move_rows_aside(table, self.pos.0);
move_row_spans(table, self.pos.0);
set_text(table, self.pos, self.text.as_ref().to_owned());
let length = count_cols.checked_sub(self.pos.1).unwrap_or(1);
table.get_config_mut().set_column_span(self.pos, length);
table.destroy_width_cache();
table.destroy_height_cache();
}
}
#[derive(Debug)]
pub struct Header<S>(S);
impl<S, R> TableOption<R> for Header<S>
where
S: AsRef<str>,
R: Records + RecordsMut<String> + Resizable,
{
fn change(&mut self, table: &mut Table<R>) {
HorizontalPanel {
pos: (0, 0),
text: self.0.as_ref(),
}
.change(table);
}
}
#[derive(Debug)]
pub struct Footer<S>(S);
impl<S, R> TableOption<R> for Footer<S>
where
S: AsRef<str> + Clone,
R: Records + RecordsMut<String> + Resizable,
{
fn change(&mut self, table: &mut Table<R>) {
HorizontalPanel {
pos: (table.shape().0, 0),
text: self.0.as_ref(),
}
.change(table);
}
}
fn move_rows_aside<R>(table: &mut Table<R>, row: usize)
where
R: Records + Resizable,
{
table.get_records_mut().push_row();
let count_rows = table.get_records().count_rows();
let shift_count = count_rows - row;
for i in 0..shift_count {
let row = count_rows - i;
table.get_records_mut().swap_row(row, row - 1);
}
}
fn move_columns_aside<R>(table: &mut Table<R>, column: usize)
where
R: Records + Resizable,
{
table.get_records_mut().push_column();
let count_columns = table.get_records().count_columns();
let shift_count = count_columns - column;
for i in 0..shift_count {
let col = count_columns - i;
table.get_records_mut().swap_column(col, col - 1);
}
}
fn move_row_spans<R>(table: &mut Table<R>, target_row: usize)
where
R: Records,
{
let spans = table
.get_config()
.iter_column_spans(table.shape())
.collect::<Vec<_>>();
for ((row, col), span) in spans {
if row >= target_row {
table.get_config_mut().set_column_span((row, col), 1);
table.get_config_mut().set_column_span((row + 1, col), span);
}
}
let spans = table
.get_config()
.iter_row_spans(table.shape())
.collect::<Vec<_>>();
for ((row, col), span) in spans {
if row >= target_row {
table.get_config_mut().set_row_span((row, col), 1);
table.get_config_mut().set_row_span((row + 1, col), span);
} else {
}
}
}
fn move_column_spans<R>(table: &mut Table<R>, target_column: usize)
where
R: Records,
{
let spans = table
.get_config()
.iter_column_spans(table.shape())
.collect::<Vec<_>>();
for ((row, col), span) in spans {
if col >= target_column {
table.get_config_mut().set_column_span((row, col), 1);
table.get_config_mut().set_column_span((row, col + 1), span);
} else {
}
}
let spans = table
.get_config()
.iter_row_spans(table.shape())
.collect::<Vec<_>>();
for ((row, col), span) in spans {
if col >= target_column {
table.get_config_mut().set_row_span((row, col), 1);
table.get_config_mut().set_row_span((row, col + 1), span);
}
}
}
fn set_text<R>(table: &mut Table<R>, pos: Position, text: String)
where
R: RecordsMut<String>,
{
let ctrl = CfgWidthFunction::from_cfg(table.get_config());
table.get_records_mut().set(pos, text, ctrl);
}