use crate::{
buffer::{
fragment_buffer::{FragmentSpan, FragmentTree},
Fragment, StringBuffer,
},
fragment::CellText,
util::parser,
Merge, Settings,
};
pub use cell::{Cell, CellGrid};
pub use contacts::Contacts;
pub use endorse::Endorse;
use itertools::Itertools;
use sauron::{
html,
html::attributes::{class, id},
html::*,
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)
.with_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)
.with_children(group_nodes);
svg_node
}
/// return the fragments that are (close objects, touching grouped fragments)
pub fn get_fragment_spans(self) -> (Vec<FragmentSpan>, Vec<Span>) {
let escaped_text = self.escaped_text_nodes();
let group_adjacents: Vec<Span> = self.into();
let (endorsed_fragments, vec_spans): (
Vec<Vec<FragmentSpan>>,
Vec<Vec<Span>>,
) = group_adjacents
.into_iter()
.map(|span| span.endorse())
.map(|endorse| (endorse.accepted, endorse.rejects))
.unzip();
let mut accepted: Vec<FragmentSpan> =
endorsed_fragments.into_iter().flatten().collect();
let rejects: Vec<Span> = vec_spans.into_iter().flatten