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(" ".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; 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; 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 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 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 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 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 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 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 }
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 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