use crate::buffer::fragment_buffer::FragmentSpan;
use crate::fragment::CellText;
use crate::Merge;
use crate::Settings;
use crate::{
buffer::{fragment_buffer::FragmentTree, Fragment, StringBuffer},
util::parser,
};
pub use cell::{Cell, CellGrid};
pub use contacts::Contacts;
pub use endorse::Endorse;
use itertools::Itertools;
use sauron::{
html,
html::{attributes::*, *},
svg::{attributes::*, *},
Node,
};
pub use span::Span;
use std::{
collections::BTreeMap,
fmt,
ops::{Deref, DerefMut},
};
use unicode_width::UnicodeWidthStr;
mod cell;
mod contacts;
mod endorse;
mod span;
/// The simplest buffer.
/// This is maps which char belong to which cell skipping the whitespaces
#[derive(Debug, Default, Clone)]
pub struct CellBuffer {
map: BTreeMap<Cell, char>,
/// class, <style>
/// assemble into
///
/// ```css
/// .class { styles }
/// ```
css_styles: Vec<(String, String)>,
escaped_text: Vec<(Cell, String)>,
}
impl Deref for CellBuffer {
type Target = BTreeMap<Cell, char>;
fn deref(&self) -> &Self::Target {
&self.map
}
}
impl DerefMut for CellBuffer {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.map
}
}
impl CellBuffer {
pub fn new() -> Self {
Self::default()
}
pub fn add_css_styles(&mut self, css_styles: Vec<(String, String)>) {
self.css_styles.extend(css_styles);
}
pub fn bounds(&self) -> Option<(Cell, Cell)> {
let xlimits =
self.iter().map(|(cell, _)| cell.x).minmax().into_option();
let ylimits =
self.iter().map(|(cell, _)| cell.y).minmax().into_option();
match (xlimits, ylimits) {
(Some((min_x, max_x)), Some((min_y, max_y))) => {
Some((Cell::new(min_x, min_y), Cell::new(max_x, max_y)))
}
_ => None,
}
}
/// get the svg node of this cell buffer, using the default settings for the sizes
pub fn get_node<MSG>(self) -> Node<MSG> {
let (node, _w, _h) = self.get_node_with_size(&Settings::default());
node
}
/// calculate the appropriate size (w,h) in pixels for the whole cell buffer to fit
/// appropriately
pub(crate) fn get_size(&self, settings: &Settings) -> (f32, f32) {
let (_top_left, bottom_right) =
self.bounds().unwrap_or((Cell::new(0, 0), Cell::new(0, 0)));
let w = settings.scale * (bottom_right.x + 2) as f32 * Cell::width();
let h = settings.scale * (bottom_right.y + 2) as f32 * Cell::height();
(w, h)
}
/// get all nodes of this cell buffer
pub fn get_node_with_size<MSG>(
self,
settings: &Settings,
) -> (Node<MSG>, f32, f32) {
let (w, h) = self.get_size(settings);
let legend_css = self.legend_css();
let (group_nodes, fragments) = self.group_nodes_and_fragments(settings);
let svg_node =
Self::fragments_to_node(fragments, legend_css, settings, w, h)
.add_children(group_nodes);
(svg_node, w, h)
}
/// get all nodes and use the size supplied
pub fn get_node_override_size<MSG>(
self,
settings: &Settings,
w: f32,
h: f32,
) -> Node<MSG> {
let legend_css = self.legend_css();
let (group_nodes, fragments) = self.group_nodes_and_fragments(settings);
let svg_node =
Self::fragments_to_node(fragments, legend_css, settings, w, h)
.add_children(group_nodes);
svg_node
}
/// return the fragments that are (close objects, touching grouped fragments)
pub fn get_fragment_spans(
self,
) -> (Vec<FragmentSpan>, Vec<Vec<FragmentSpan>>) {
let escaped_text = self.escaped_text_nodes();
let Endorse {
mut accepted,
rejects,
} = self.endorse_to_fragment_spans();
accepted.extend(escaped_text);
(accepted, rejects)
}
/// return fragments that are Rect, Circle,
pub(crate) fn into_shapes_fragment(self) -> Vec<FragmentSpan> {
let endorse = self.endorse_to_fragment_spans();
println!("endorsed: {:#?}", endorse);
endorse
.accepted
.into_iter()
.filter(|frag| frag.fragment.is_rect() || frag.fragment.is_circle())
.collect