tech_ui/
table.rs

1use std::collections::BTreeSet;
2
3#[derive(Debug,Clone,Copy,Ord,PartialOrd,Eq,PartialEq)]
4pub struct RowRef {
5    table_idx: usize,
6    row_idx: usize,
7}
8
9#[derive(Debug,Clone,Copy)]
10pub struct TableRef {
11    table_idx: usize,
12}
13
14#[derive(Debug)]
15struct Row {
16    styles: String,
17    divs: Vec<String>,
18    args: Option<Vec<usize>>,
19}
20
21#[derive(Debug)]
22pub enum TableError {
23    EmptySoft(String),
24    FixedOnSoft(TableRef),
25    SoftOnFixed(TableRef),
26    MustBeOneSoftColumn(String),
27    UnknownTable(TableRef),
28    UnknownRow(RowRef),
29    FixedRowTooLong {
30        table: String,
31        width: usize,
32        pads: usize,
33        asked: usize,
34        unknown: usize,
35    },
36    SoftRowTooLong {
37        table: String,
38        min_width: usize,
39    }
40}
41
42#[derive(Debug,Default)]
43pub struct TableDrawer {
44    row_set: BTreeSet<RowRef>
45}
46
47#[derive(Debug,Clone,Copy)]
48enum TableType {
49    Fixed(usize),
50    Soft(usize),
51}
52
53#[derive(Debug)]
54struct TableConf {
55    index: usize,
56    uid: String,
57    tp: TableType,
58    half_padding: usize,
59    rows: Vec<Row>,
60}
61
62#[derive(Debug)]
63pub struct TableBuilder {
64    tables: Vec<TableConf>,
65}
66impl TableBuilder {
67    pub fn new() -> TableBuilder {
68        TableBuilder {
69            tables: Vec::new(),
70        }
71    }
72    pub fn table_fixed<S: ToString>(&mut self, uid: S, width: usize) -> TableRef {
73        let res = TableRef { table_idx: self.tables.len() };
74        self.tables.push(TableConf {
75            index: res.table_idx,
76            uid: uid.to_string(),
77            tp: TableType::Fixed(width),
78            half_padding: 2,
79            rows: Vec::new(),
80        });
81        res
82    }
83    pub fn table_soft<S: ToString>(&mut self, uid: S, min_width: usize) -> TableRef {
84        let res = TableRef { table_idx: self.tables.len() };
85        self.tables.push(TableConf {
86            index: res.table_idx,
87            uid: uid.to_string(),
88            tp: TableType::Soft(min_width),
89            half_padding: 2,
90            rows: Vec::new(),
91        });
92        res
93    }
94    pub fn with_half_padding(&mut self, table: TableRef, hp: usize) -> Result<(),TableError> {
95        if self.tables.len() <= table.table_idx { return Err(TableError::UnknownTable(table)); }
96        self.tables[table.table_idx].half_padding = hp;
97        Ok(())
98    }
99
100    pub fn create_row_fixed(&mut self, table_ref: TableRef, columns: &[Option<usize>]) -> Result<RowRef,TableError> {
101        if self.tables.len() <= table_ref.table_idx { return Err(TableError::UnknownTable(table_ref)); }
102        let table_idx = table_ref.table_idx;
103        
104        match self.tables[table_idx].tp {
105            TableType::Fixed(width) => create_fixed(&mut self.tables[table_idx],width,columns),
106            TableType::Soft(_) => Err(TableError::FixedOnSoft(table_ref)),
107        }
108    }
109
110    pub fn create_row_soft(&mut self, table_ref: TableRef, columns: Vec<SoftColumn>) -> Result<RowRef,TableError> {
111        if self.tables.len() <= table_ref.table_idx { return Err(TableError::UnknownTable(table_ref)); }
112        let table_idx = table_ref.table_idx;
113        
114        match self.tables[table_idx].tp {
115            TableType::Fixed(_) => Err(TableError::SoftOnFixed(table_ref)),
116            TableType::Soft(min_width) => create_soft(&mut self.tables[table_idx],min_width,columns),
117        }
118    }
119
120    pub fn row(&self, row_ref: RowRef, class: &str, mut values: Vec<String>, drawer: &mut TableDrawer) -> Result<String,TableError> {
121        if self.tables.len() <= row_ref.table_idx { return Err(TableError::UnknownRow(row_ref)); }
122        if self.tables[row_ref.table_idx].rows.len() <= row_ref.row_idx { return Err(TableError::UnknownRow(row_ref)); }
123        let row = &self.tables[row_ref.table_idx].rows[row_ref.row_idx];
124        drawer.row_set.insert(row_ref);
125        if row.divs.len() == 0 { return Ok(String::new()); }
126        let cnt = row.divs.len() - 1;
127        if cnt > values.len() {
128            let i = values.len();
129            for _ in  i .. cnt {
130                values.push("&nbsp;".to_string());
131            }
132        }
133        let mut res = format!("<div class='{}'>\n",class);
134        for (i,d) in row.divs.iter().enumerate() {
135            res += d;
136            if i < values.len() {
137                match &row.args {
138                    None => res += &values[i],
139                    Some(args) => if (i < args.len()) && (args[i] < values.len()) {
140                        res += &values[args[i]];
141                    },
142                }
143            }
144        }
145        res += "</div>";
146        Ok(res)
147    }
148
149    pub fn styles(&self, drawer: &TableDrawer) -> String {
150        let mut res = String::new();
151        for rr in &drawer.row_set {
152            if self.tables.len() <= rr.table_idx { continue; }
153            if self.tables[rr.table_idx].rows.len() <= rr.row_idx { continue; }
154            res += &self.tables[rr.table_idx].rows[rr.row_idx].styles;
155        }
156        res
157    }
158}
159
160
161pub struct SoftColumn {
162    pub percentage: Option<usize>,
163    pub subcolumns: Vec<Option<usize>>,
164}
165
166#[derive(Debug)]
167struct RealFixed {
168    padding_left: usize,
169    padding_right: usize,
170    width: usize,
171}
172impl RealFixed {
173    fn size(&self) -> usize {
174        self.padding_left + self.padding_right + self.width
175    }
176}
177#[derive(Debug)]
178enum DivFixed {
179    One(RealFixed),
180    Vec(Vec<RealFixed>),
181}
182impl DivFixed {
183    fn size(&self) -> usize {
184        match self {
185            DivFixed::One(d) => d.size(),
186            DivFixed::Vec(v) => v.iter().fold(0,|acc,x| acc + x.size()),
187        }
188    }
189    fn count(&self) -> usize {
190        match self {
191            DivFixed::One(_) => 1,
192            DivFixed::Vec(v) => v.len(),
193        }
194    }
195    fn divs(&self, styles: &mut String, pads: &mut Vec<String>, divs: &mut Vec<String>, args: &mut Vec<usize>, arg_offset: usize, arg_length: usize, cls_prefix: String, float: &str) {
196        match self {
197            DivFixed::One(RealFixed { padding_left, padding_right, width }) => {              
198                *styles += &format!(".{} {{ padding-left: {}px; padding-right: {}px; width: {}px; float: {}; overflow: hidden; }}\n",cls_prefix,padding_left, padding_right, width, float);
199                divs.push(format!("<div class='{}'>",cls_prefix));
200                divs.push("</div>\n".to_string());
201                pads.push(cls_prefix);
202            },
203            DivFixed::Vec(vf) => {
204                let mut v = Vec::new();
205                for (i,r) in vf.iter().enumerate() {
206                    let RealFixed { padding_left, padding_right, width } = r;
207                    let cls = format!("{}_c{}",cls_prefix,i);                    
208                    *styles += &format!(".{} {{ padding-left: {}px; padding-right: {}px; width: {}px; overflow: hidden; float: left; }}\n",cls,padding_left, padding_right, width);
209                    divs.push(format!("<div class='{}'>",cls));
210                    divs.push("</div>\n".to_string());
211                    pads.push(cls);
212                }
213                *styles += &format!(".{} {{ width: {}px; float: {}; overflow: hidden; }}\n",cls_prefix,vf.iter().fold(0,|acc,x| acc + x.size()),float);
214                add_div(&cls_prefix,&mut v);
215                divs.extend(v);
216            },
217        }
218        for arg in 0 .. arg_length {
219            args.push(arg_offset + arg);
220        }
221    }
222}
223#[derive(Debug)]
224enum Fixed {
225    None,
226    Left(DivFixed),
227    Right(DivFixed),
228}
229impl Fixed {
230    fn right(right: Vec<usize>, most_right: bool, table: &mut TableConf) -> Fixed {
231        Fixed::Right(match right.len() {
232            1 => DivFixed::One(RealFixed {
233                padding_left: table.half_padding,
234                padding_right: match most_right { true => 2, false => 1 } * table.half_padding,
235                width: right[0],
236            }),
237            _ => DivFixed::Vec({
238                let mut v = Vec::new();
239                let last = right.len() - 1;
240                for (i,r) in right.into_iter().enumerate() {
241                    v.push(RealFixed {
242                        padding_left: table.half_padding,
243                        padding_right: match (i == last) && most_right { true => 2, false => 1 } * table.half_padding,
244                        width: r,
245                    });
246                }
247                v
248            }),
249        })
250    }
251    fn left(left: Vec<usize>, most_left: bool, table: &mut TableConf) -> Fixed {
252        Fixed::Left(match left.len() {
253            1 => DivFixed::One(RealFixed {
254                padding_left: match most_left { true => 2, false => 1 } * table.half_padding,
255                padding_right: table.half_padding,
256                width: left[0],
257            }),
258            _ => DivFixed::Vec({
259                let mut v = Vec::new();
260                for (i,r) in left.into_iter().enumerate() {
261                    v.push(RealFixed {
262                        padding_left: match (i == 0) && most_left{ true => 2, false => 1 } * table.half_padding,
263                        padding_right: table.half_padding,
264                        width: r,
265                    });
266                }
267                v
268            }),
269        })
270    }
271    fn size(&self) -> usize {
272        match self {
273            Fixed::None => 0,
274            Fixed::Left(d) |
275            Fixed::Right(d) => d.size(),
276        }
277    }
278    fn count(&self) -> usize {
279        match self {
280            Fixed::None => 0,
281            Fixed::Left(d) |
282            Fixed::Right(d) => d.count(),
283        }
284    }
285}
286#[derive(Debug)]
287struct DivSoftReal {
288    padding_left: usize,
289    padding_right: usize,
290    min_width: usize,
291    margin: Option<usize>,
292}
293impl DivSoftReal {
294    fn divs(&self, styles: &mut String, pads: &mut Vec<String>, divs: &mut Vec<String>, args: &mut Vec<usize>, arg_offset: usize, arg_length: usize, cls_prefix: String, float: &str) {  
295        *styles += &format!(".{} {{ padding-left: {}px; padding-right: {}px; min-width: {}px; margin-{}: {}px; overflow: hidden; }}\n",cls_prefix,self.padding_left, self.padding_right, self.min_width, float, match self.margin { Some(m) => m, None => 0 });
296        divs.push(format!("<div class='{}'>",cls_prefix));
297        divs.push("</div>\n".to_string());
298        pads.push(cls_prefix);
299        for arg in 0 .. arg_length {
300            args.push(arg_offset + arg);
301        }
302    }
303}
304#[derive(Debug)]
305enum DivSoft {
306    Phantom {
307        min_width: usize,
308        fixed: Fixed,
309        soft: DivSoftReal,
310        margin: Option<usize>,
311    },
312    Real(DivSoftReal),
313}
314impl DivSoft {
315    fn count(&self) -> usize {
316        match self {
317            DivSoft::Phantom{ fixed, .. } => fixed.count() + 1,
318            DivSoft::Real(..) => 1,
319        }
320    }
321    fn divs(&self, styles: &mut String, pads: &mut Vec<String>, divs: &mut Vec<String>, args: &mut Vec<usize>, arg_offset: usize, arg_length: usize, cls_prefix: String, float: &str) {
322        match &self {
323            DivSoft::Phantom { fixed, soft, min_width, margin } => match fixed {
324                Fixed::None => soft.divs(styles,pads,divs,args,arg_offset,arg_length,cls_prefix,float),
325                Fixed::Left(left) => {
326                    let l_cnt = left.count();
327                    let r_cnt = 1; // soft.count();                    
328                    let cls = format!("{}_l",cls_prefix);
329                    let mut tmp_l = Vec::new();
330                    left.divs(styles,pads,&mut tmp_l,args,arg_offset,l_cnt,cls,"left");                    
331                    let cls = format!("{}_r",cls_prefix);
332                    let mut tmp_r = Vec::new();
333                    soft.divs(styles,pads,&mut tmp_r,args,arg_offset+l_cnt,r_cnt,cls,"left");
334                    concat_divs(&mut tmp_l,tmp_r);
335                    *styles += &format!(".{} {{ min-width: {}px; margin-{}: {}px; overflow: hidden; }}\n",cls_prefix,min_width, float, match margin { Some(m) => *m, None => 0 });
336                    add_div("row",&mut tmp_l);
337                    add_div(&cls_prefix,&mut tmp_l);
338                    divs.extend(tmp_l);
339                },
340                Fixed::Right(right) => {
341                    let r_cnt = right.count();
342                    let l_cnt = 1; //soft.count();                    
343                    let cls = format!("{}_r",cls_prefix);
344                    let mut tmp_r = Vec::new();
345                    right.divs(styles,pads,&mut tmp_r,args,arg_offset+l_cnt,r_cnt,cls,"right");
346                    let cls = format!("{}_l",cls_prefix);
347                    let mut tmp_l = Vec::new();
348                    soft.divs(styles,pads,&mut tmp_l,args,arg_offset,l_cnt,cls,"right");
349                    concat_divs(&mut tmp_r,tmp_l);
350                    *styles += &format!(".{} {{ min-width: {}px; margin-{}: {}px; overflow: hidden; }}\n",cls_prefix,min_width, float, match margin { Some(m) => *m, None => 0 });
351                    add_div("row",&mut tmp_r);
352                    add_div(&cls_prefix,&mut tmp_r);
353                    divs.extend(tmp_r);
354                },
355            },
356            DivSoft::Real(r) => r.divs(styles,pads,divs,args,arg_offset,arg_length,cls_prefix,float),
357        }
358    }
359}
360
361#[derive(Debug)]
362struct Phantom {
363    //percentage: usize,
364    //min_width: usize,
365    fixed: Fixed,
366    soft: DivSoft,
367}
368impl Phantom {
369    fn count(&self) -> usize {
370        self.fixed.count() + self.soft.count()
371    }
372    fn from_column(c: SoftColumn, min_width: usize, _percentage: usize, most_left: bool, most_right: bool, table: &mut TableConf) -> Result<Phantom,TableError> {
373        let mut left = Vec::new();
374        let mut right = Vec::new();
375        let mut unk = 0;
376        for col in c.subcolumns {
377            match col {
378                Some(w) if unk == 0 => left.push(w),
379                Some(w) => right.push(w),
380                None => unk += 1,
381            }
382        }
383        if unk != 1 { return Err(TableError::MustBeOneSoftColumn(table.uid.clone())); }
384        if left.len() == 0 {
385            if right.len() == 0 {
386                Ok(Phantom{
387                    //percentage, min_width,
388                    fixed: Fixed::None, soft: DivSoft::Real(DivSoftReal {
389                        min_width: min_width - (match most_right { true => 2, false => 1 } + match most_left { true => 2, false => 1 }) * table.half_padding,
390                        padding_left: match most_left { true => 2, false => 1 } * table.half_padding,
391                        padding_right: match most_right { true => 2, false => 1 } * table.half_padding,
392                        margin: None,
393                    }),
394                })
395            } else {
396                let fixed = Fixed::right(right,most_right,table);
397                let margin_right = fixed.size();
398                if min_width <= margin_right {
399                    return Err(TableError::SoftRowTooLong { table: table.uid.clone(), min_width });
400                }
401                Ok(Phantom{
402                    //percentage, min_width,
403                    fixed,
404                    soft: DivSoft::Real(DivSoftReal {
405                        min_width: min_width - margin_right - match most_left { true => 3, false => 2 } * table.half_padding,
406                        margin: Some(margin_right),
407                        padding_left: match most_left { true => 2, false => 1 } * table.half_padding,
408                        padding_right: table.half_padding,
409                    }),                    
410                })
411            }
412        } else {
413            if right.len() == 0 {
414                let fixed = Fixed::left(left,most_left,table);
415                let margin_left = fixed.size();
416                if min_width <= margin_left {
417                    return Err(TableError::SoftRowTooLong { table: table.uid.clone(), min_width });
418                }
419                Ok(Phantom{
420                    //percentage, min_width,
421                    fixed,
422                    soft: DivSoft::Real(DivSoftReal {
423                        min_width: min_width - margin_left - match most_left { true => 3, false => 2 } * table.half_padding,
424                        margin: Some(margin_left),
425                        padding_left: table.half_padding,
426                        padding_right: match most_left { true => 2, false => 1 } * table.half_padding,
427                    }),                    
428                })                    
429            } else {
430                let fixed_left = Fixed::left(left,most_left,table);
431                let fixed_right = Fixed::right(right,most_right,table);
432                let margin_left = fixed_left.size();
433                let margin_right = fixed_right.size();
434                if min_width <= (margin_right + margin_left) {
435                    return Err(TableError::SoftRowTooLong { table: table.uid.clone(), min_width });
436                }
437                Ok(Phantom{
438                    //percentage, min_width,
439                    fixed: fixed_left,
440                    soft: DivSoft::Phantom {
441                        min_width: min_width - margin_left,
442                        margin: Some(margin_left),
443                        fixed: fixed_right,
444                        soft: DivSoftReal {
445                            min_width: min_width - margin_left - margin_right - table.half_padding * 2,
446                            margin: Some(margin_right),
447                            padding_left: table.half_padding,
448                            padding_right: table.half_padding,
449                        },                     
450                    },
451                })
452            }
453        }
454    }
455    fn divs(&self, styles: &mut String, pads: &mut Vec<String>, divs: &mut Vec<String>, args: &mut Vec<usize>, arg_offset: usize, arg_length: usize, cls_prefix: String) {
456        // self.fixed self.soft
457        match &self.fixed {
458            Fixed::None => self.soft.divs(styles,pads,divs,args,arg_offset,arg_length,cls_prefix,"left"),
459            Fixed::Left(left) => {
460                let l_cnt = left.count();
461                let r_cnt = self.soft.count();
462                let cls = format!("{}_l",cls_prefix);
463                let mut tmp_l = Vec::new();
464                left.divs(styles,pads,&mut tmp_l,args,arg_offset,l_cnt,cls,"left");                
465                let cls = format!("{}_r",cls_prefix);
466                let mut tmp_r = Vec::new();
467                self.soft.divs(styles,pads,&mut tmp_r,args,arg_offset+l_cnt,r_cnt,cls,"left");
468                concat_divs(&mut tmp_l,tmp_r);
469                divs.extend(tmp_l);
470            },
471            Fixed::Right(right) => {
472                let r_cnt = right.count();
473                let l_cnt = self.soft.count();                    
474                let cls = format!("{}_r",cls_prefix);
475                let mut tmp_r = Vec::new();
476                right.divs(styles,pads,&mut tmp_r,args,arg_offset+l_cnt,r_cnt,cls,"right");
477                let cls = format!("{}_l",cls_prefix);
478                let mut tmp_l = Vec::new();
479                self.soft.divs(styles,pads,&mut tmp_l,args,arg_offset,l_cnt,cls,"right");
480                concat_divs(&mut tmp_r,tmp_l);
481                divs.extend(tmp_r);
482            },
483        }
484    }
485}
486#[derive(Debug)]
487enum Div {
488    One(Phantom),
489    //Vec(Vec<Phantom>),
490}
491
492fn add_div(cls: &str, divs: &mut Vec<String>) {
493    let ln = divs.len();
494    if ln > 0 {
495        divs[0] = format!("<div class='{}'>\n{}",cls,divs[0]);
496        divs[ln-1] = format!("{}</div>\n",divs[ln-1]);
497    }
498}
499
500fn concat_divs(l: &mut Vec<String>, mut r: Vec<String>) {
501    match l.pop() {
502        None => l.extend(r),
503        Some(last_l) => {
504            match r.len() > 0 { 
505                true => r[0] = format!("{}{}",last_l,r[0]),
506                false => r.push(last_l),
507            }
508            l.extend(r);
509        },
510    }
511}
512
513fn create_soft(table: &mut TableConf, min_width: usize, mut columns: Vec<SoftColumn>) -> Result<RowRef,TableError> {
514    let div = match columns.len() {
515        0 | 1 => match columns.pop() {
516            None => return Err(TableError::EmptySoft(table.uid.clone())),
517            Some(col) => Div::One(Phantom::from_column(col,min_width,100,true,true,table)?),
518        },
519        _ => {
520            /*let mut v = Vec::new();
521            for c in columns {
522                v.push(Phantom::from_column(c,??,??)?);
523            }
524            Div::Vec(v)*/
525            todo!()
526        },
527    };
528    let row_idx = table.rows.len();
529    let mut styles = String::new();
530    let mut divs = Vec::new();
531    let mut args = Vec::new();
532    let mut pads = Vec::new();
533    match div {
534        Div::One(ph) => {
535            let cnt = ph.count();
536            ph.divs(&mut styles,&mut pads,&mut divs,&mut args,0,cnt,format!("{}",table.uid))
537        },
538    }
539    let mut first = true;
540    for cls in &pads {
541        if !first { styles += ", "; }
542        styles += ".";
543        styles += cls;                        
544        first = false;
545    }
546    styles += &format!("{{ padding-top: {}px; padding-bottom: {}px; }}\n", table.half_padding * 2, table.half_padding * 2);
547
548    table.rows.push(Row{ styles, divs, args: Some(args) });
549    Ok(RowRef{ table_idx: table.index, row_idx })
550}
551
552fn create_fixed(table: &mut TableConf, width: usize, columns: &[Option<usize>]) -> Result<RowRef,TableError> {
553    let cnt = columns.len();
554    let pads = (cnt + 1) * 2 * table.half_padding;
555    let mut unk = 0;
556    let mut asked = 0;
557    for c in columns {
558        match c {
559            Some(w) => asked += w,
560            None => unk += 1,
561        }
562    }
563    if width >= (pads + asked + unk) {
564        let row_idx = table.rows.len();
565        let nw = width - pads - asked;
566        let uw = nw / unk;
567        let rw = nw % unk;
568        
569        let mut ctrl = 0;
570        let mut u_idx = 0;
571        let mut col_classes = Vec::new();
572        let mut st = String::new();
573        for (col_idx, c) in columns.iter().enumerate() {
574            let w = match c {
575                Some(w) => *w,
576                None => {
577                    let w = uw + match u_idx < rw { true => 1, false => 0 };
578                    u_idx += 1;
579                    w
580                }
581            };
582            ctrl += w;
583            let col_class = format!("{}_r{}_c{}",table.uid,row_idx,col_idx);
584            st += &format!(".{} {{ width: {}px; }}\n",col_class,w);
585            col_classes.push(col_class);
586        }
587        if (ctrl + pads) != width {
588            return Err(TableError::FixedRowTooLong {
589                table: table.uid.clone(), width, pads, asked, unknown: unk,
590            });
591        }
592        
593        let mut styles = String::new();
594        
595        let mut first = true;
596        for cls in &col_classes {
597            if !first { styles += ", "; }
598            styles += ".";
599            styles += cls;                        
600            first = false;
601        }
602        styles += &format!("{{ padding: {}px; float: left; }}\n", table.half_padding * 2);
603        
604        let mut first = true;
605        for cls in &col_classes[..(col_classes.len()-1)] {
606            if !first { styles += ", "; }
607            styles += ".";
608            styles += cls;                        
609            first = false;
610        }
611        styles += &format!("{{ padding-right: {}px; }}\n", table.half_padding);
612        
613        let mut first = true;
614        for cls in &col_classes[1..] {
615            if !first { styles += ", "; }
616            styles += ".";
617            styles += cls;                        
618            first = false;
619        }
620        styles += &format!("{{ padding-left: {}px; }}\n", table.half_padding);
621        styles += &st;
622        
623        let mut divs = col_classes.into_iter().enumerate().map(|(i,cls)| match i {
624            0 => format!("<div class='{}'>",cls),
625            _ => format!("</div>\n<div class='{}'>",cls),
626        }).collect::<Vec<_>>();
627        divs.push("</div>\n".to_string());
628        table.rows.push(Row{ styles, divs, args: None });
629        Ok(RowRef{ table_idx: table.index, row_idx })
630    } else {
631        Err(TableError::FixedRowTooLong {
632            table: table.uid.clone(), width, pads, asked, unknown: unk,
633        })
634    }
635}
636
637#[cfg(test)]
638mod tests {
639    use super::*;
640
641    #[test]
642    fn fixed_1() {
643        let mut tb = TableBuilder::new();
644        let table = tb.table_fixed("locs",250);
645        let row = tb.create_row_fixed(table,&[None,Some(44),Some(44)]).unwrap();
646        let mut drawer = TableDrawer::new();
647        let body = tb.row(row,"locs_r0",vec!["Row1".to_owned(),"1".to_owned(),"10".to_owned()],&mut drawer).unwrap();
648        let styles = tb.styles(&drawer);
649        println!("{}",styles);
650        println!("{}",body);
651        panic!("");
652    }
653
654    #[test]
655    fn soft_1() {
656        let mut tb = TableBuilder::new();
657        let table = tb.table_soft("pros",742);
658        let row = tb.create_row_soft(table,vec![
659            SoftColumn {
660                percentage: None,
661                subcolumns: vec![Some(150),None,Some(40)],
662            },
663        ]).unwrap();
664        let mut drawer = TableDrawer::new();
665        let body = tb.row(row,"pros_r0",vec!["Slot".to_owned(),"Data".to_owned(),"10".to_owned()],&mut drawer).unwrap();
666        let styles = tb.styles(&drawer);
667        println!("{}",styles);
668        println!("{}",body);
669        panic!("");
670    }
671
672     #[test]
673    fn soft_2() {
674        let mut tb = TableBuilder::new();
675        let table = tb.table_soft("pros",742);
676        let row = tb.create_row_soft(table,vec![
677            SoftColumn {
678                percentage: None,
679                subcolumns: vec![None],
680            },
681        ]).unwrap();
682        let mut drawer = TableDrawer::new();
683        let body = tb.row(row,"pros_rh",vec!["Header".to_owned()],&mut drawer).unwrap();
684        let styles = tb.styles(&drawer);
685        println!("{}",styles);
686        println!("{}",body);
687        panic!("");
688    }
689
690    
691}
692
693