Symphony Of Empires
table.hpp
Go to the documentation of this file.
1 // Symphony of Empires
2 // Copyright (C) 2021, Symphony of Empires contributors
3 //
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with this program. If not, see <https://www.gnu.org/licenses/>.
16 //
17 // ----------------------------------------------------------------------------
18 // Name:
19 // eng3d/ui/table.hpp
20 //
21 // Abstract:
22 // Dynamic table widget, it's sortable and very flexible.
23 // ----------------------------------------------------------------------------
24 
25 #pragma once
26 
27 #include <cstddef>
28 #include <deque>
29 #include <functional>
30 #include <vector>
31 #include <string>
32 #include <unordered_map>
33 #include <numeric>
34 #include <stdexcept>
35 #include "eng3d/ui/widget.hpp"
36 #include "eng3d/ui/div.hpp"
37 #include "eng3d/ui/scrollbar.hpp"
38 #include "eng3d/utils.hpp"
39 
40 namespace UI {
43  class TableRow;
44 
48  class TableElement : public UI::Widget {
49  public:
50  TableElement(int width, int height, UI::Widget* _parent);
51  virtual ~TableElement() override {}
52 
53  void set_key(const std::string& key);
54  void set_key(float key);
55  void set_key(float key, const std::string_view format);
56  bool operator< (const UI::TableElement& right) const;
57  private:
58  enum class KeyType {
59  NUMBER = 0,
60  STRING = 1,
61  NONE = 2
62  };
63  float key_number;
64  std::string key_string;
65  UI::TableElement::KeyType key_type = UI::TableElement::KeyType::NONE;
66  };
67 
71  class TableRow : public UI::Widget {
72  public:
73  TableRow(int width, int height, std::vector<int>& columns_width, UI::Widget* _parent);
74  virtual ~TableRow() override {}
75  UI::TableElement* get_element(size_t index);
76 
77  bool is_active = true;
78  private:
79  std::vector<UI::TableElement*> elements;
80  std::vector<int>& columns_width;
81  };
82 
86  template <typename T>
87  class Table : public UI::Widget {
88  public:
89  Table(int _x, int _y, unsigned _h, int _row_height, std::vector<int> _widths, std::vector<std::string> _header_labels, UI::Widget* _parent = nullptr)
90  : UI::Widget(_parent, _x, _y, 0, _h, UI::WidgetType::TABLE),
91  row_height{ _row_height }, columns_width{ _widths }
92  {
93  assert(_widths.size() == _header_labels.size());
94  this->width = std::accumulate(_widths.begin(), _widths.end(), 35);
95  auto& header = this->template make_widget<UI::TableRow>(this->width - 35, _row_height, this->columns_width);
96  for(size_t i = 0; i < _header_labels.size(); i++) {
97  auto& label = _header_labels[i];
98  auto* column = header.get_element(i);
99  column->set_text(label);
100  column->set_on_click([this, i](Widget&) {
101  this->sorting_ascending = (this->sorting_row == (int)i) ? !this->sorting_ascending : true;
102  this->sorting_row = i;
103  this->sort(i, this->sorting_ascending);
104  });
105  }
106  auto& wrapper = this->template make_widget<UI::Div>(0, _row_height, this->width, this->height - row_height);
107  wrapper.is_scroll = true;
108  this->column_wrapper = &wrapper.template make_widget<UI::Div>(0, 0, this->width - 25, 0);
109  this->column_wrapper->flex = UI::Flex::COLUMN;
110  this->column_wrapper->flex_justify = UI::FlexJustify::START;
111  this->scrollbar = &wrapper.template make_widget<UI::Scrollbar>(this->width - 20, 0, wrapper.height - 40);
112  this->on_update = [this](Widget&) {
113  int total_height = this->row_height * this->rows.size();
114  this->column_wrapper->height = total_height;
115  };
116  }
117  virtual ~Table() override {}
118 
119  void reserve(size_t _size) {
120  this->rows.reserve(_size);
121  }
122 
123  UI::TableRow& get_row(T _row_id) {
124  if(!this->rows.count(_row_id)) {
125  auto& row = this->column_wrapper->template make_widget<UI::TableRow>(this->width - 25, this->row_height, this->columns_width);
126  this->rows.insert({ _row_id, &row });
127  }
128  auto* row = this->rows[_row_id];
129  row->is_active = true;
130  return *row;
131  }
132 
133  void remove_row(T _row_id) {
134  if(this->rows.count(_row_id)) {
135  this->rows[_row_id]->kill();
136  this->rows.erase(_row_id);
137  }
138  }
139 
141  for(auto it = rows.begin(); it != rows.end(); it++) {
142  it->second->is_active = false;
143  }
144  }
145 
147  for(auto it = rows.begin(); it != rows.end(); ) {
148  if(!it->second->is_active) {
149  it->second->kill();
150  it = rows.erase(it);
151  } else {
152  ++it;
153  }
154  }
155  }
156 
157  void sort(size_t _column_index, bool ascending) {
158  this->column_wrapper->sort_children([_column_index, ascending](const auto& a, const auto& b) {
159  UI::TableRow &row_a = static_cast<UI::TableRow&>(*a);
160  auto &element_a = *(row_a.get_element(_column_index));
161  UI::TableRow &row_b = static_cast<UI::TableRow&>(*b);
162  auto &element_b = *(row_b.get_element(_column_index));
163  return ascending ? (element_a < element_b) : (element_b < element_a);
164  });
165  }
166  private:
167  std::unordered_map<T, UI::TableRow*> rows;
168  int sorting_row = -1;
169  bool sorting_ascending = true;
170  UI::Div* column_wrapper;
171  UI::Scrollbar* scrollbar;
172  int row_height;
173  std::vector<int> columns_width;
174  };
175 }
Scrollbar widget.
Definition: scrollbar.hpp:43
An element on a table, operates on a k=v fashion where the key is used for sorting the table.
Definition: table.hpp:48
void set_key(const std::string &key)
Definition: table.cpp:41
TableElement(int width, int height, UI::Widget *_parent)
Definition: table.cpp:35
virtual ~TableElement() override
Definition: table.hpp:51
bool operator<(const UI::TableElement &right) const
Definition: table.cpp:57
A dynamic/smart table that can sort elements by ascending/descending order.
Definition: table.hpp:87
void make_rows_unactive()
Definition: table.hpp:140
virtual ~Table() override
Definition: table.hpp:117
void remove_row(T _row_id)
Definition: table.hpp:133
void reserve(size_t _size)
Definition: table.hpp:119
UI::TableRow & get_row(T _row_id)
Definition: table.hpp:123
Table(int _x, int _y, unsigned _h, int _row_height, std::vector< int > _widths, std::vector< std::string > _header_labels, UI::Widget *_parent=nullptr)
Definition: table.hpp:89
void sort(size_t _column_index, bool ascending)
Definition: table.hpp:157
void clear_unactive_rows()
Definition: table.hpp:146
A row of a table, contains table elements and specifies the width of the entire row.
Definition: table.hpp:71
virtual ~TableRow() override
Definition: table.hpp:74
UI::TableElement * get_element(size_t index)
Definition: table.cpp:100
bool is_active
Definition: table.hpp:77
TableRow(int width, int height, std::vector< int > &columns_width, UI::Widget *_parent)
Definition: table.cpp:69
The master widget all the other widgets inherit from, do not use directly instead use one of the many...
Definition: widget.hpp:176
void sort_children(F &&comp)
Sort the children of this widget.
Definition: widget.hpp:276
std::function< void(UI::Widget &)> on_update
Definition: widget.hpp:349
size_t width
Definition: widget.hpp:325
UI::Flex flex
Definition: widget.hpp:337
UI::FlexJustify flex_justify
Definition: widget.hpp:338
size_t height
Definition: widget.hpp:325
WidgetType
The type of the widget, some widgets share types between them to keep simplicity.
Definition: widget.hpp:76
A basic widget without any presets.
Definition: div.hpp:38