Empirical
Table.h
Go to the documentation of this file.
1 
27 #ifndef EMP_WEB_TABLE_H
28 #define EMP_WEB_TABLE_H
29 
30 #include "../base/vector.h"
31 
32 #include "Div.h"
33 #include "Widget.h"
34 #include "WidgetExtras.h"
35 
36 namespace emp {
37 namespace web {
38 
39  class TableWidget;
40  class Table;
41  class TableCell;
42  class TableRow;
43  class TableCol;
44  class TableRowGroup;
45  class TableColGroup;
46 
47  namespace internal {
48 
49  struct TableRowInfo;
50  class TableInfo;
51 
52  struct TableDataInfo {
53  size_t colspan=1;
54  size_t rowspan=1;
55  bool header=false;
56  bool masked=false;
58 
60 
62  bool OK(std::stringstream & ss, bool verbose=false, const std::string & prefix="") {
63  bool ok = true;
64  if (verbose) ss << prefix << "Scanning: emp::TableDataInfo" << std::endl;
65  if (masked) { ss << "Warning: Masked cell may have contents!" << std::endl; ok = false; }
66  return ok;
67  }
68  }; // END: TableDataInfo
69 
70 
71  struct TableRowInfo {
74 
76  template <typename SETTING_TYPE>
77  TableRowInfo & CellsCSS(const std::string & setting, SETTING_TYPE && value) {
78  for (auto & datum : data) datum.extras.style.Set(setting, value);
79  return *this;
80  }
81 
83  template <typename SETTING_TYPE>
84  TableRowInfo & CellCSS(size_t col_id, const std::string & setting, SETTING_TYPE && value) {
85  data[col_id].extras.style.Set(setting, value);
86  return *this;
87  }
88 
90  bool OK(std::stringstream & ss, bool verbose=false, const std::string & prefix="") {
91  bool ok = true;
92  if (verbose) { ss << prefix << "Scanning: emp::TableRowInfo" << std::endl; }
93  for (auto & cell : data) ok = ok && cell.OK(ss, verbose, prefix+" ");
94  return ok;
95  }
96  };
97 
98  struct TableColInfo { WidgetExtras extras; }; // Currently only need annotations.
99 
100  // Group of rows or columns...
101  struct TableGroupInfo : public WidgetExtras {
102  size_t span = 1;
103  bool masked = false;
105  };
106 
108  friend TableWidget; friend Table; friend TableCell; friend TableRow; friend TableCol;
109  friend TableRowGroup; friend TableColGroup;
110  protected:
111  size_t row_count;
112  size_t col_count;
117 
118  size_t append_row;
119  size_t append_col;
120 
121  TableInfo(const std::string & in_id="")
122  : internal::WidgetInfo(in_id), row_count(0), col_count(0), append_row(0), append_col(0) { ; }
123  TableInfo(const TableInfo &) = delete; // No copies of INFO allowed
124  TableInfo & operator=(const TableInfo &) = delete; // No copies of INFO allowed
125  virtual ~TableInfo() { ; }
126 
127  std::string TypeName() const override { return "TableInfo"; }
128  virtual bool IsTableInfo() const override { return true; }
129 
130  void Resize(size_t new_rows, size_t new_cols) {
131  // Resize preexisting rows if remaining
132  if (new_cols != col_count) {
133  for (size_t r = 0; r < rows.size() && r < new_rows; r++) {
134  rows[r].data.resize(new_cols);
135  for (size_t c = col_count; c < new_cols; c++) { AddChild(r, c, Text("")); }
136  }
137  col_count = new_cols; // Store the new column count
138 
139  // Resize extra column info, only if currently in use.
140  if (cols.size()) cols.resize(new_cols);
141  if (col_groups.size()) col_groups.resize(new_cols);
142  }
143 
144  // Resize number of rows.
145  if (new_rows != row_count) {
146  rows.resize(new_rows);
147  for (size_t r = row_count; r < new_rows; r++) {
148  rows[r].data.resize(col_count);
149  for (size_t c = 0; c < col_count; c++) { AddChild(r, c, Text("")); }
150  }
151  row_count = new_rows;
152 
153  // Resize extra row group info, only if needed.
154  if (row_groups.size()) row_groups.resize(new_rows);
155  }
156 
157  }
158 
159  void DoActivate(bool top_level=true) override {
160  // Activate all of the cell children.
161  for (size_t r = 0; r < row_count; r++) {
162  for (size_t c = 0; c < col_count; c++) {
163  for (auto & child : rows[r].data[c].children) child->DoActivate(false);
164  }
165  }
166 
167  // Activate this Table.
169  }
170 
171 
172  // Return a text element for appending into a specific cell (use existing one or build new)
173  web::Text & GetTextWidget(size_t r, size_t c) {
174  auto & cell_children = rows[r].data[c].children;
175  // If final element in this cell doesn't exists, isn't text, or can't append, but new Text!
176  if (cell_children.size() == 0
177  || cell_children.back().IsText() == false
178  || cell_children.back().AppendOK() == false) {
179  AddChild(Text());
180  }
181  return (Text &) cell_children.back();
182  }
183 
185  // Make sure the number of rows hasn't changed, making the current position illegal.
186  if (append_row >= row_count) append_row = 0;
187  if (append_col >= col_count) append_col = 0;
188 
189  return GetTextWidget(append_row, append_col);
190  }
191 
192  // Append into the current cell
193  Widget Append(Widget in) override { AddChild(in); return in; }
194  Widget Append(const std::string & text) override { return GetTextWidget() << text; }
195  Widget Append(const std::function<std::string()> & in_fun) override {
196  return GetTextWidget() << in_fun;
197  }
198 
199  // Add a widget to the specified cell in the current table.
200  void AddChild(size_t r, size_t c, Widget in) {
201  emp_assert(in->parent == nullptr && "Cannot insert widget if already has parent!", in->id);
202  emp_assert(in->state != Widget::ACTIVE && "Cannot insert a stand-alone active widget!");
203 
204  // Setup parent-child relationship in the specified cell.
205  rows[r].data[c].children.emplace_back(in);
206  in->parent = this;
207  Register(in);
208 
209  // If this element (as new parent) is active, anchor widget and activate it!
210  if (state == Widget::ACTIVE) {
211  // Create a span tag to anchor the new widget.
212  std::string cell_id = emp::to_string(id, '_', r, '_', c);
213  EM_ASM_ARGS({
214  parent_id = Pointer_stringify($0);
215  child_id = Pointer_stringify($1);
216  $('#' + parent_id).append('<span id="' + child_id + '"></span>');
217  }, cell_id.c_str(), in.GetID().c_str());
218 
219  // Now that the new widget has some place to hook in, activate it!
220  in->DoActivate();
221  }
222  }
223 
224  // If no cell is specified for AddChild, use the current cell.
225  void AddChild(Widget in) {
226  // Make sure the number of rows hasn't changed, making the current position illegal.
227  if (append_row >= row_count) append_row = 0;
228  if (append_col >= col_count) append_col = 0;
229 
230  AddChild(append_row, append_col, in);
231  }
232 
233 
234  // Tables need to facilitate recursive registrations
235 
236  void RegisterChildren(internal::DivInfo * regestrar) override {
237  for (size_t r = 0; r < row_count; r++) {
238  for (size_t c = 0; c < col_count; c++) {
239  for (Widget & child : rows[r].data[c].children) regestrar->Register(child);
240  }
241  }
242  }
243 
244  void UnregisterChildren(internal::DivInfo * regestrar) override {
245  for (size_t r = 0; r < row_count; r++) {
246  for (size_t c = 0; c < col_count; c++) {
247  for (Widget & child : rows[r].data[c].children) regestrar->Unregister(child);
248  }
249  }
250  }
251 
252  virtual void GetHTML(std::stringstream & HTML) override {
253  emp_assert(cols.size() == 0 || cols.size() == col_count);
254  emp_assert(col_groups.size() == 0 || col_groups.size() == col_count);
255 
256  HTML.str(""); // Clear the current text.
257  HTML << "<table id=\"" << id << "\">";
258 
259  // Include column/row details only as needed.
260  const bool use_colg = col_groups.size();
261  const bool use_cols = cols.size();
262  const bool use_rowg = row_groups.size();
263 
264  if (use_colg || use_cols) {
265  for (size_t c = 0; c < col_count; ++c) {
266  if (use_colg && col_groups[c].masked == false) {
267  HTML << "<colgroup";
268  if (col_groups[c].extras) HTML << " id=" << id << "_cg" << c;
269  HTML << ">";
270  }
271  HTML << "<col";
272  if (use_cols && cols[c].extras) HTML << " id=" << id << "_c" << c;
273  HTML << ">";
274  }
275  }
276 
277  // Loop through all of the rows in the table.
278  for (size_t r = 0; r < rows.size(); r++) {
279  if (use_rowg && row_groups[r].masked == false) {
280  HTML << "<tbody";
281  if (row_groups[r].extras) HTML << " id=" << id << "_rg" << r;
282  HTML << ">";
283  }
284 
285  auto & row = rows[r];
286  HTML << "<tr";
287  if (row.extras) HTML << " id=" << id << '_' << r;
288  HTML << ">";
289 
290  // Loop through each cell in this row.
291  for (size_t c = 0; c < row.data.size(); c++) {
292  auto & datum = row.data[c];
293  if (datum.masked) continue; // If this cell is masked by another, skip it!
294 
295  // Print opening tag.
296  HTML << (datum.header ? "<th" : "<td");
297 
298  // Include an id for this cell if we have one.
299  if (datum.extras) HTML << " id=" << id << '_' << r << '_' << c;
300 
301  // If this cell spans multiple rows or columns, indicate!
302  if (datum.colspan > 1) HTML << " colspan=\"" << datum.colspan << "\"";
303  if (datum.rowspan > 1) HTML << " rowspan=\"" << datum.rowspan << "\"";
304 
305  HTML << ">";
306 
307  // Loop through all children of this cell and build a span element for each.
308  for (Widget & w : datum.children) {
309  HTML << "<span id=\'" << w.GetID() << "'></span>";
310  }
311 
312  // Print closing tag.
313  HTML << (datum.header ? "</th>" : "</td>");
314  }
315 
316  HTML << "</tr>";
317  }
318 
319  HTML << "</table>";
320  }
321 
322  void ClearCellChildren(size_t row_id, size_t col_id) {
323  // Clear out this cell's children. @CAO: Keep a starting text widget if we can?
324  auto & datum = rows[row_id].data[col_id];
325  if (parent) for (Widget & child : datum.children) parent->Unregister(child);
326  datum.children.resize(0);
327  }
328  void ClearRowChildren(size_t row_id) {
329  for (size_t col_id = 0; col_id < col_count; col_id++) ClearCellChildren(row_id, col_id);
330  }
331  void ClearColChildren(size_t col_id) {
332  for (size_t row_id = 0; row_id < row_count; row_id++) ClearCellChildren(row_id, col_id);
333  }
334  void ClearRowGroupChildren(size_t row_id) {
335  for (size_t offset=0; offset < row_groups[row_id].span; offset++) {
336  ClearRowChildren(row_id+offset);
337  }
338  }
339  void ClearColGroupChildren(size_t col_id) {
340  for (size_t offset=0; offset < col_groups[col_id].span; offset++) {
341  ClearColChildren(col_id+offset);
342  }
343  }
345  for (size_t col_id = 0; col_id < col_count; col_id++) {
346  for (size_t row_id = 0; row_id < row_count; row_id++) {
347  ClearCellChildren(row_id, col_id);
348  }
349  }
350  }
351 
352  void ClearCell(size_t row_id, size_t col_id) {
353  auto & datum = rows[row_id].data[col_id];
354  datum.colspan = 1;
355  datum.rowspan = 1;
356  datum.header = false;
357  datum.masked = false; // @CAO Technically, cell might still be masked!
358  datum.extras.Clear();
359 
360  ClearCellChildren(row_id, col_id);
361  }
362  void ClearRowCells(size_t row_id) {
363  for (size_t col_id = 0; col_id < col_count; col_id++) ClearCell(row_id, col_id);
364  }
365  void ClearColCells(size_t col_id) {
366  for (size_t row_id = 0; row_id < row_count; row_id++) ClearCell(row_id, col_id);
367  }
368  void ClearRow(size_t row_id) {
369  rows[row_id].extras.Clear();
370  ClearRowCells(row_id);
371  }
372  void ClearCol(size_t col_id) {
373  cols[col_id].extras.Clear();
374  ClearColCells(col_id);
375  }
376  void ClearRowGroup(size_t row_id) {
377  row_groups[row_id].extras.Clear();
378  for (size_t offset=0; offset < row_groups[row_id].span; offset++) ClearRow(row_id+offset);
379  }
380  void ClearColGroup(size_t col_id) {
381  col_groups[col_id].extras.Clear();
382  for (size_t offset=0; offset < col_groups[col_id].span; offset++) ClearCol(col_id+offset);
383  }
384 
385  void ClearTableCells() { for (size_t r = 0; r < row_count; r++) ClearRowCells(r); }
386  void ClearTableRows() { for (size_t r = 0; r < row_count; r++) ClearRow(r); }
387  void ClearTable() { extras.Clear(); Resize(0,0); }
388 
389  bool OK(std::stringstream & ss, bool verbose=false, const std::string & prefix="") {
390  bool ok = true;
391 
392  // Basic info
393  if (verbose) {
394  ss << prefix << "Scanning: emp::TableInfo (rows=" << row_count
395  << ", cols=" << col_count << ")." << std::endl;
396  }
397 
398  // Make sure rows and columns are being sized correctly.
399  if (row_count != rows.size()) {
400  ss << prefix << "Error: row_count = " << row_count
401  << ", but rows has " << rows.size() << " elements." << std::endl;
402  ok = false;
403  }
404 
405  if (cols.size() && col_count != cols.size()) {
406  ss << prefix << "Error: col_count = " << col_count
407  << ", but cols has " << cols.size() << " elements." << std::endl;
408  ok = false;
409  }
410 
411  if (row_count < 1) {
412  ss << prefix << "Error: Cannot have " << row_count
413  << " rows in table." << std::endl;
414  ok = false;
415  }
416 
417  if (col_count < 1) {
418  ss << prefix << "Error: Cannot have " << col_count
419  << " cols in table." << std::endl;
420  ok = false;
421  }
422 
423  // And perform the same test for row/column groups.
424  if (col_groups.size() && col_count != col_groups.size()) {
425  ss << prefix << "Error: col_count = " << col_count
426  << ", but col_groups has " << col_groups.size() << " elements." << std::endl;
427  ok = false;
428  }
429 
430  if (row_groups.size() && row_count != row_groups.size()) {
431  ss << prefix << "Error: row_count = " << row_count
432  << ", but row_groups has " << row_groups.size() << " elements." << std::endl;
433  ok = false;
434  }
435 
436  // Recursively call OK on rows and data.
437  for (size_t r = 0; r < row_count; r++) {
438  ok = ok && rows[r].OK(ss, verbose, prefix+" ");
439  if (col_count != rows[r].data.size()) {
440  ss << prefix << " Error: col_count = " << col_count
441  << ", but row has " << rows[r].data.size() << " elements." << std::endl;
442  ok = false;
443  }
444  for (size_t c = 0; c < col_count; c++) {
445  auto & cell = rows[r].data[c];
446  if (c + cell.colspan > col_count) {
447  ss << prefix << " Error: Cell at row " << r << ", col " << c
448  << " extends past right side of table." << std::endl;
449  ok = false;
450  }
451  if (r + cell.rowspan > row_count) {
452  ss << prefix << " Error: Cell at row " << r << ", col " << c
453  << " extends past bottom of table." << std::endl;
454  ok = false;
455  }
456  }
457  }
458 
459  return ok;
460  }
461 
462  void ReplaceHTML() override {
463  emp_assert(cols.size() == 0 || cols.size() == col_count);
464  emp_assert(col_groups.size() == 0 || col_groups.size() == col_count);
465  emp_assert(row_groups.size() == 0 || row_groups.size() == row_count);
466 
467  // Replace Table's HTML...
469 
470  // Then replace cells
471  for (size_t r = 0; r < row_count; r++) {
472  rows[r].extras.Apply(emp::to_string(id, '_', r));
473  for (size_t c = 0; c < col_count; c++) {
474  auto & datum = rows[r].data[c];
475  if (datum.masked) continue; // If this cell is masked by another, skip it!
476  datum.extras.Apply(emp::to_string(id, '_', r, '_', c));
477 
478  // If this widget is active, immediately replace children.
479  if (state == Widget::ACTIVE) {
480  for (auto & child : datum.children) child->ReplaceHTML();
481  }
482  }
483  }
484 
485  // And setup columns, column groups, and row groups, as needed.
486  if (cols.size()) {
487  for (size_t c = 0; c < col_count; c++) {
488  if (!cols[c].extras) continue;
489  cols[c].extras.Apply(emp::to_string(id, "_c", c));
490  }
491  }
492  if (col_groups.size()) {
493  for (size_t c = 0; c < col_count; c++) {
494  if (col_groups[c].masked || !col_groups[c].extras) continue;
495  col_groups[c].extras.Apply(emp::to_string(id, "_cg", c));
496  }
497  }
498  if (row_groups.size()) {
499  for (size_t c = 0; c < col_count; c++) {
500  if (row_groups[c].masked || !row_groups[c].extras) continue;
501  row_groups[c].extras.Apply(emp::to_string(id, "_rg", c));
502  }
503  }
504  }
505 
506  public:
507  virtual std::string GetType() override { return "web::TableInfo"; }
508  }; // end TableInfo
509 
510 
511  } // end namespace internal
512 
513  class TableWidget : public internal::WidgetFacet<TableWidget> {
514  friend class internal::TableInfo;
515  protected:
516  size_t cur_row; // Which row/col is currently active?
517  size_t cur_col;
518 
520 
523  const internal::TableInfo * Info() const { return (internal::TableInfo *) info; }
524 
525  TableWidget(internal::TableInfo * in_info, size_t _row=0, size_t _col=0)
526  : WidgetFacet(in_info), cur_row(_row), cur_col(_col) { ; }
527 
529  void DoCSS(const std::string & setting, const std::string & value) override {
530  parent_t::DoCSS(setting, value);
531  }
532 
534  void DoAttr(const std::string & setting, const std::string & value) override {
535  parent_t::DoAttr(setting, value);
536  }
537 
539  void DoListen(const std::string & event_name, size_t fun_id) override {
540  parent_t::DoListen(event_name, fun_id);
541  }
542 
543  public:
544  TableWidget(size_t r, size_t c, const std::string & in_id="")
545  : WidgetFacet(in_id), cur_row(0), cur_col(0)
546  {
547  emp_assert(r > 0 && c > 0); // Ensure that we have rows and columns!
548  info = new internal::TableInfo(in_id);
549  Info()->Resize(r, c);
550  }
552  : WidgetFacet(in), cur_row(in.cur_row), cur_col(in.cur_col) { ; }
553  TableWidget(const Widget & in) : WidgetFacet(in), cur_row(0), cur_col(0) {
554  emp_assert(info->IsTableInfo());
555  }
556  TableWidget() { ; }
557  virtual ~TableWidget() { ; }
558 
560 
561  size_t GetNumCols() const { return Info()->col_count; }
562  size_t GetNumRows() const { return Info()->row_count; }
563  size_t GetNumCells() const { return Info()->col_count*Info()->row_count; }
564 
565  // Called before an append.
566  virtual void PrepareAppend() override {
567  Info()->append_row = cur_row;
568  Info()->append_col = cur_col;
569  }
570 
571 
572  size_t GetCurRow() const { return cur_row; }
573  size_t GetCurCol() const { return cur_col; }
574 
575  // Can clear anything from any widget, if properly specified.
576  // Specialized widgets should define Clear(), ClearChildren(), ClearStyle(), ClearAttr(),
577  // and ClearListen() for that table component type.
578  void ClearTable() { Info()->ClearTable(); }
579  void ClearRows() { Info()->ClearTableRows(); }
580  void ClearRow(size_t r) { Info()->ClearRow(r); }
581  void ClearCol(size_t c) { Info()->ClearCol(c); }
582  void ClearRowGroup(size_t r) { Info()->ClearRowGroup(r); }
583  void ClearColGroup(size_t c) { Info()->ClearColGroup(c); }
584  void ClearCells() { Info()->ClearTableCells(); }
585  void ClearCell(size_t r, size_t c) { Info()->ClearCell(r, c); }
586 
587  TableCell GetCell(size_t r, size_t c);
588  TableRow GetRow(size_t r);
589  TableCol GetCol(size_t c);
590  TableRowGroup GetRowGroup(size_t r);
591  TableColGroup GetColGroup(size_t c);
592  Table GetTable();
593 
595  web::Text GetTextWidget() { return Info()->GetTextWidget(); }
596 
598  Widget AddText(size_t r, size_t c, const std::string & text);
599 
601  Widget AddHeader(size_t r, size_t c, const std::string & text);
602 
603  using parent_t::SetCSS;
604 
606  std::string GetCSS(const std::string & setting) override {
607  return Info()->extras.GetStyle(setting);
608  }
609 
611  virtual bool OK(std::stringstream & ss, bool verbose=false, const std::string & prefix="") {
612  bool ok = true;
613 
614  // Basic info
615  if (verbose) {
616  ss << prefix << "Scanning: emp::Table (rows=" << Info()->row_count
617  << ", cols=" << Info()->col_count << ")." << std::endl;
618  }
619 
620  // Make sure current row and col are valid.
621  if (cur_row >= Info()->row_count) {
622  ss << prefix << "Error: cur_row = " << cur_row << "." << std::endl;
623  ok = false;
624  }
625 
626  if (cur_col >= Info()->col_count) {
627  ss << prefix << "Error: cur_col = " << cur_col << "." << std::endl;
628  ok = false;
629  }
630 
631  // Make sure internal info is okay.
632  ok = ok && Info()->OK(ss, verbose, prefix+" ");
633 
634  return ok;
635  }
636  };
637 
638  class Table : public TableWidget {
639  public:
640  Table(size_t r, size_t c, const std::string & in_id="") : TableWidget(r,c,in_id) { ; }
641  Table(const TableWidget & in) : TableWidget(in) { ; }
642  Table(const Widget & in) : TableWidget(in) { ; }
643  Table(internal::TableInfo * in_info, size_t _row, size_t _col)
644  : TableWidget(in_info, _row, _col) { ; }
645  Table() : TableWidget() { ; }
646 
647  Table & Clear() { Info()->ClearTable(); return *this; }
648  Table & ClearStyle() { Info()->extras.style.Clear(); return *this; }
649  Table & ClearAttr() { Info()->extras.attr.Clear(); return *this; }
650  Table & ClearListen() { Info()->extras.listen.Clear(); return *this; }
651  Table & ClearExtras() { Info()->extras.Clear(); return *this; }
652  Table & ClearChildren() { Info()->ClearTableChildren(); return *this; }
653 
655  Table & Rows(size_t r) {
656  Info()->Resize(r, Info()->col_count);
657  if (cur_row >= r) cur_row = 0;
658  return *this;
659  }
660 
662  Table & Cols(size_t c) {
663  Info()->Resize(Info()->row_count, c);
664  if (cur_col >= c) cur_col = 0;
665  return *this;
666  }
667 
669  Table & Resize(size_t r, size_t c) {
670  Info()->Resize(r, c);
671  if (cur_row >= r) cur_row = 0;
672  if (cur_col >= c) cur_col = 0;
673  return *this;
674  }
675 
677  Table & SetColSpan(size_t new_span) {
678  emp_assert((cur_col + new_span <= GetNumCols()) && "Col span too wide for table!",
679  cur_col, new_span, GetNumCols(), GetID());
680 
681  // If we haven't setup columns at all yet, do so.
682  if (Info()->col_groups.size() == 0) Info()->col_groups.resize(GetNumCols());
683 
684  const size_t old_span = Info()->col_groups[cur_col].span;
685  Info()->col_groups[cur_col].span = new_span;
686 
687  if (old_span != new_span) {
688  for (size_t i=old_span; i<new_span; i++) { Info()->col_groups[cur_col+i].masked = true; }
689  for (size_t i=new_span; i<old_span; i++) { Info()->col_groups[cur_col+i].masked = false; }
690  }
691 
692  // Redraw the entire table to fix col span information.
693  if (IsActive()) Info()->ReplaceHTML();
694 
695  return *this;
696  }
697 
699  template <typename SETTING_TYPE>
700  Table & RowCSS(size_t row_id, const std::string & setting, SETTING_TYPE && value) {
701  emp_assert(row_id >= 0 && row_id < Info()->row_count);
702  Info()->rows[row_id].extras.style.Set(setting, value);
703  if (IsActive()) Info()->ReplaceHTML(); // @CAO only should replace row's CSS
704  return *this;
705  }
706 
708  template <typename SETTING_TYPE>
709  Table & CellCSS(size_t row_id, size_t col_id, const std::string & setting, SETTING_TYPE && value) {
710  emp_assert(row_id >= 0 && row_id < Info()->row_count);
711  emp_assert(col_id >= 0 && col_id < Info()->row_count);
712  Info()->rows[row_id].extras.style.Set(setting, value);
713  if (IsActive()) Info()->ReplaceHTML(); // @CAO only should replace cell's CSS
714  return *this;
715  }
716 
718  template <typename SETTING_TYPE>
719  Table & RowsCSS(const std::string & setting, SETTING_TYPE && value) {
720  for (auto & row : Info()->rows) row.extras.style.Set(setting, emp::to_string(value));
721  if (IsActive()) Info()->ReplaceHTML();
722  return *this;
723  }
724 
726  template <typename SETTING_TYPE>
727  Table & CellsCSS(const std::string & setting, SETTING_TYPE && value) {
728  for (auto & row : Info()->rows) row.CellsCSS(setting, emp::to_string(value));
729  if (IsActive()) Info()->ReplaceHTML();
730  return *this;
731  }
732  };
733 }
734 }
735 
736 #include "_TableCell.h"
737 #include "_TableRow.h"
738 #include "_TableCol.h"
739 #include "_TableRowGroup.h"
740 #include "_TableColGroup.h"
741 
742 namespace emp {
743 namespace web {
744 
745  // Fill out members of Table that require extra classes...
746 
747  TableCell TableWidget::GetCell(size_t r, size_t c) {
748  emp_assert(Info() != nullptr);
749  emp_assert(r < Info()->row_count && c < Info()->col_count,
750  r, c, Info()->row_count, Info()->col_count, GetID());
751  return TableCell(Info(), r, c);
752  }
753 
755  emp_assert(r < Info()->row_count, r, Info()->row_count, GetID());
756  return TableRow(Info(), r);
757  }
758 
760  emp_assert(c < Info()->col_count, c, Info()->col_count, GetID());
761  return TableCol(Info(), c);
762  }
763 
765  emp_assert(r < Info()->row_count, r, Info()->row_count, GetID());
766  return TableRowGroup(Info(), r);
767  }
768 
770  emp_assert(c < Info()->col_count, c, Info()->col_count, GetID());
771  return TableColGroup(Info(), c);
772  }
773 
775  return Table(Info(), cur_row, cur_col);
776  }
777 
778  Widget TableWidget::AddText(size_t r, size_t c, const std::string & text) {
779  GetCell(r,c) << text;
780  return *this;
781  }
782 
783  Widget TableWidget::AddHeader(size_t r, size_t c, const std::string & text) {
784  TableCell cell = GetCell(r,c);
785  cell << text;
786  cell.SetHeader();
787  return *this;
788  }
789 
790 }
791 }
792 
793 #endif
Table & SetColSpan(size_t new_span)
Setup the number of columns the current column group.
Definition: Table.h:677
void UnregisterChildren(internal::DivInfo *regestrar) override
Definition: Table.h:244
WidgetExtras extras
Extra annotations (attributes, style, listeners)
Definition: Table.h:73
void ClearColCells(size_t col_id)
Definition: Table.h:365
WidgetExtras extras
Is the current group masked because of a previous span?
Definition: Table.h:104
A Text widget handles putting text on a web page that can be controlled and modified.
Definition: Text.h:27
size_t append_row
Detail object for each row group (if needed)
Definition: Table.h:118
Definition: Widget.h:206
Table & Resize(size_t r, size_t c)
Fully resize the table (both rows and columns)
Definition: Table.h:669
TableRowInfo & CellCSS(size_t col_id, const std::string &setting, SETTING_TYPE &&value)
Apply CSS to specific cell in row.
Definition: Table.h:84
Table(const TableWidget &in)
Definition: Table.h:641
Widget Append(Widget in) override
Definition: Table.h:193
The TableCol widget, which behaves like the Table widget, but focuses on a single column...
virtual void ReplaceHTML()
Definition: Widget.h:319
TableWidget(internal::TableInfo *in_info, size_t _row=0, size_t _col=0)
Definition: Table.h:525
Table GetTable()
Focus on a the entire table.
Definition: Table.h:774
std::string id
ID used for associated DOM element.
Definition: Widget.h:212
The TableRowGoup widget, which behaves like the Table widget, but focuses on a group of rows...
void ClearRow(size_t row_id)
Definition: Table.h:368
void ClearTableChildren()
Definition: Table.h:344
std::string to_string(ALL_TYPES &&...all_values)
Definition: string_utils.h:511
Table & ClearStyle()
Definition: Table.h:648
void Unregister(Widget &old_widget) override
Definition: Div.h:110
Definition: Table.h:52
Table & CellsCSS(const std::string &setting, SETTING_TYPE &&value)
Apply CSS to all cells.
Definition: Table.h:727
void ClearRows()
Definition: Table.h:579
size_t cur_col
Definition: Table.h:517
void AddChild(Widget in)
Definition: Table.h:225
Table & ClearExtras()
Definition: Table.h:651
std::string GetCSS(const std::string &setting) override
Get a CSS value for the currently active cell.
Definition: Table.h:606
bool header
Is this TableData a header (vs )?
Definition: Table.h:55
WidgetFacet is a template that provides accessors into Widget with a derived return type...
Definition: Widget.h:543
TableWidget(size_t r, size_t c, const std::string &in_id="")
Definition: Table.h:544
void ClearTable()
Definition: Table.h:387
void ClearRowChildren(size_t row_id)
Definition: Table.h:328
size_t row_count
Definition: Table.h:111
size_t GetCurRow() const
Determine which row currnetly has focus.
Definition: Table.h:572
Definition: Table.h:98
Table(internal::TableInfo *in_info, size_t _row, size_t _col)
Definition: Table.h:643
The TableColGoup widget, which behaves like the Table widget, but focuses on a group of columns...
void ClearColGroup(size_t c)
Definition: Table.h:583
Include information (name, keyword, description) for each instance.
void ClearColGroupChildren(size_t col_id)
Definition: Table.h:339
Style & Set(const std::string &s, SET_TYPE v)
Record that setting "s" is set to value "v" (converted to string) and return this object...
Definition: Style.h:50
virtual bool IsTableInfo() const override
Definition: Table.h:128
void ClearRowGroup(size_t row_id)
Definition: Table.h:376
TableWidget(const Widget &in)
Definition: Table.h:553
web::Text GetTextWidget()
Get the TExt widget assoited with the currently active cell.
Definition: Table.h:595
TableCol GetCol(size_t c)
Focus on a specifc column in the table.
Definition: Table.h:759
virtual ~TableWidget()
Definition: Table.h:557
An object that focuses on a group of columns in a specified table.
Definition: _TableColGroup.h:19
size_t colspan
How many columns wide is this TableData?
Definition: Table.h:53
size_t GetCurCol() const
Determine which column currently has focus.
Definition: Table.h:573
void AddChild(size_t r, size_t c, Widget in)
Definition: Table.h:200
virtual ~TableInfo()
Definition: Table.h:125
TableRowGroup GetRowGroup(size_t r)
Focus on a specifc group of rows in the table.
Definition: Table.h:764
Widget AddText(size_t r, size_t c, const std::string &text)
Add text to a specified cell in the table.
Definition: Table.h:778
Definition: Widget.h:102
TableInfo(const std::string &in_id="")
Which col is triggering an append?
Definition: Table.h:121
virtual std::string GetType() override
Definition: Table.h:507
void DoCSS(const std::string &setting, const std::string &value) override
Apply CSS to appropriate component based on current state.
Definition: Table.h:529
TableWidget()
Definition: Table.h:556
An object that focuses on a single cell in a specified table.
Definition: _TableCell.h:19
Definition: Table.h:513
data
A set of modifiers are available do describe DataNode.
Definition: DataNode.h:38
Table & ClearAttr()
Definition: Table.h:649
size_t size() const
Definition: vector.h:151
virtual void PrepareAppend() override
Setup << operator to redirect to Append; option preparation can be overridden.
Definition: Table.h:566
WidgetExtras extras
Extra annotations (attributes, style, listeners)
Definition: Table.h:57
void emplace_back(ARGS &&...args)
Definition: vector.h:219
void RegisterChildren(internal::DivInfo *regestrar) override
Definition: Table.h:236
Table & ClearChildren()
Definition: Table.h:652
TableCell GetCell(size_t r, size_t c)
Focus on a specifc cell in the table.
Definition: Table.h:747
emp::vector< Widget > children
Widgets contained in this cell.
Definition: Table.h:59
Widget::ActivityState state
Is this element active in DOM?
Definition: Widget.h:218
WidgetExtras extras
Definition: Table.h:98
void Clear()
Clear all of style, attributes, and listeners.
Definition: WidgetExtras.h:46
const std::string & GetID() const
What is the HTML string ID for this Widget?
Definition: Widget.h:401
Definition: Table.h:101
An object that focuses on a single column in a specified table.
Definition: _TableRow.h:19
bool OK(std::stringstream &ss, bool verbose=false, const std::string &prefix="")
Debug function to determine if this datum is structually consistent.
Definition: Table.h:62
virtual bool OK(std::stringstream &ss, bool verbose=false, const std::string &prefix="")
Debugging function.
Definition: Table.h:611
Table & CellCSS(size_t row_id, size_t col_id, const std::string &setting, SETTING_TYPE &&value)
Apply CSS to target cell.
Definition: Table.h:709
size_t rowspan
How many rows deep is this TableData?
Definition: Table.h:54
emp::vector< TableRowInfo > rows
Definition: Table.h:113
emp::vector< TableGroupInfo > col_groups
Detail object for each column (if needed)
Definition: Table.h:115
Table & RowCSS(size_t row_id, const std::string &setting, SETTING_TYPE &&value)
Apply CSS to target row.
Definition: Table.h:700
WidgetInfo * parent
Which WidgetInfo is this one contained within?
Definition: Widget.h:216
static const PrintStr endl("<br>")
Pre-define emp::endl to insert a "<br>" and thus acting like a newline.
void ClearRow(size_t r)
Definition: Table.h:580
void ClearCell(size_t r, size_t c)
Definition: Table.h:585
TableRow GetRow(size_t r)
Focus on a specifc row in the table.
Definition: Table.h:754
The TableCell widget, which behaves like the Table widget, but focuses on a single cell...
Widget Append(const std::string &text) override
Definition: Table.h:194
Widget AddHeader(size_t r, size_t c, const std::string &text)
Set a specified cell to be a table header.
Definition: Table.h:783
Div Widgets maintain an ordered collection of other widgets in an HTML div.
Definition: Div.h:52
TableColGroup GetColGroup(size_t c)
Focus on a specifc group of columns in the table.
Definition: Table.h:769
bool OK(std::stringstream &ss, bool verbose=false, const std::string &prefix="")
Definition: Table.h:389
TableCell & SetHeader(bool _h=true)
Definition: _TableCell.h:58
web::Text & GetTextWidget()
Definition: Table.h:184
void ClearTable()
Definition: Table.h:578
virtual void GetHTML(std::stringstream &HTML) override
Definition: Table.h:252
void resize(size_t new_size)
Definition: vector.h:161
size_t GetNumCols() const
Definition: Table.h:561
The TableRow widget, which behaves like the Table widget, but focuses on a single row...
Widgets maintain individual components on a web page and link to Elements.
Table()
Definition: Table.h:645
An object that focuses on a group of rows in a specified table.
Definition: _TableRowGroup.h:19
Widget Append(const std::function< std::string()> &in_fun) override
Definition: Table.h:195
void ClearCells()
Definition: Table.h:584
Table & Rows(size_t r)
Resize the number of rows in the table.
Definition: Table.h:655
void Resize(size_t new_rows, size_t new_cols)
Definition: Table.h:130
std::string TypeName() const override
Debugging helpers...
Definition: Table.h:127
TableRowInfo & CellsCSS(const std::string &setting, SETTING_TYPE &&value)
Apply CSS to all cells in row.
Definition: Table.h:77
A collection of extra details about HTML Widgets (attributes, style, listerns)
internal::TableInfo * Info()
Get a properly cast version of info.
Definition: Table.h:522
If we are in emscripten, make sure to include the header.
Definition: array.h:37
void ClearCol(size_t col_id)
Definition: Table.h:372
Table(size_t r, size_t c, const std::string &in_id="")
Definition: Table.h:640
Definition: WidgetExtras.h:21
virtual void DoActivate(bool top_level=true)
Definition: Widget.h:278
Build a debug wrapper emp::vector around std::vector.
Definition: vector.h:42
bool OK(std::stringstream &ss, bool verbose=false, const std::string &prefix="")
Debug function to determine if this row is structually consistent.
Definition: Table.h:90
Definition: Table.h:71
const internal::TableInfo * Info() const
Definition: Table.h:523
void DoListen(const std::string &event_name, size_t fun_id) override
Apply CSS to appropriate component based on current state.
Definition: Table.h:539
Widget is effectively a smart pointer to a WidgetInfo object, plus some basic accessors.
Definition: Widget.h:78
Table & Cols(size_t c)
Resize the number of columns in the table.
Definition: Table.h:662
An object that focuses on a single column in a specified table.
Definition: _TableCol.h:19
#define emp_assert(...)
Definition: assert.h:199
emp::vector< TableColInfo > cols
Detail object for each row.
Definition: Table.h:114
emp::vector< TableGroupInfo > row_groups
Detail object for each column group (if needed)
Definition: Table.h:116
void Register(Widget &new_widget) override
Definition: Div.h:95
Table & RowsCSS(const std::string &setting, SETTING_TYPE &&value)
Apply CSS to all rows. (: Should we use fancier jquery here?)
Definition: Table.h:719
emp::vector< TableDataInfo > data
detail object for each cell in this row.
Definition: Table.h:72
Definition: Table.h:107
void ClearColChildren(size_t col_id)
Definition: Table.h:331
Style style
CSS Style.
Definition: WidgetExtras.h:22
size_t cur_row
Definition: Table.h:516
Table & Clear()
Definition: Table.h:647
void DoAttr(const std::string &setting, const std::string &value) override
Apply CSS to appropriate component based on current state.
Definition: Table.h:534
bool masked
Is this cell masked by another cell?
Definition: Table.h:56
void ClearCell(size_t row_id, size_t col_id)
Definition: Table.h:352
void ClearCellChildren(size_t row_id, size_t col_id)
Definition: Table.h:322
void ClearRowGroupChildren(size_t row_id)
Definition: Table.h:334
void ClearCol(size_t c)
Definition: Table.h:581
void ClearTableCells()
Definition: Table.h:385
size_t col_count
How big is this table?
Definition: Table.h:112
size_t append_col
Which row is triggering an append?
Definition: Table.h:119
void ReplaceHTML() override
Definition: Table.h:462
void ClearColGroup(size_t col_id)
Definition: Table.h:380
Definition: Table.h:638
void ClearTableRows()
Definition: Table.h:386
void DoActivate(bool top_level=true) override
Definition: Table.h:159
size_t GetNumRows() const
Definition: Table.h:562
void ClearRowGroup(size_t r)
Definition: Table.h:582
size_t GetNumCells() const
Definition: Table.h:563
Table(const Widget &in)
Definition: Table.h:642
Table & ClearListen()
Definition: Table.h:650
web::Text & GetTextWidget(size_t r, size_t c)
Definition: Table.h:173
TableWidget(const TableWidget &in)
Definition: Table.h:551
void ClearRowCells(size_t row_id)
Definition: Table.h:362