Symphony Of Empires
province_view.cpp
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 // client/interface/province_view.cpp
20 //
21 // Abstract:
22 // Does some important stuff.
23 // ----------------------------------------------------------------------------
24 
25 #include "eng3d/texture.hpp"
26 #include "eng3d/string.hpp"
27 #include "eng3d/ui/piechart.hpp"
28 #include "eng3d/ui/label.hpp"
29 #include "eng3d/ui/image.hpp"
30 #include "eng3d/ui/tooltip.hpp"
31 #include "eng3d/ui/button.hpp"
32 #include "eng3d/ui/table.hpp"
33 #include "eng3d/ui/close_button.hpp"
34 
38 #include "client/game_state.hpp"
39 #include "client/map.hpp"
40 #include "client/map_render.hpp"
41 #include "nation.hpp"
42 #include "world.hpp"
43 #include "building.hpp"
44 #include "action.hpp"
46 
47 using namespace Interface;
48 
50  // Obtain population information
51  std::vector<UI::ChartData> languages_data, religions_data, pop_types_data;
52  for(const auto& language : gs.world->languages) {
53  const auto size = province.languages[language] * province.total_pops();
54  languages_data.emplace_back(size, language.name, Eng3D::Color::bgr32(language.color));
55  }
56  languages_pie->set_data(languages_data);
57 
58  for(const auto& religion : gs.world->religions) {
59  const auto size = province.religions[religion] * province.total_pops();
60  religions_data.emplace_back(size, religion.name, Eng3D::Color::bgr32(religion.color));
61  }
62  religions_pie->set_data(religions_data);
63 
64  std::vector<size_t> pop_type_sizes(gs.world->pop_types.size(), 0);
65  for(const auto& pop : province.pops)
66  pop_type_sizes[pop.type_id] += pop.size;
67  for(const auto& pop_type : gs.world->pop_types) {
68  const auto i = static_cast<size_t>(pop_type.get_id());
69  const auto color = Eng3D::Color(
70  static_cast<uint8_t>((i * 3) % 256),
71  static_cast<uint8_t>((i * 7) % 256),
72  static_cast<uint8_t>((i * 15) % 256)
73  );
74  pop_types_data.push_back(UI::ChartData(pop_type_sizes[gs.world->get_id(pop_type)], pop_type.name, color));
75  }
76  pop_types_pie->set_data(pop_types_data);
77 }
78 
79 UI::Widget& ProvincePopulationTab::create_pop_table() {
80  std::vector<int> sizes{ 64, 96 };
81  std::vector<std::string> header{ "Size", "Budget" };
82  if(gs.editor) {
83  sizes.push_back(32);
84  header.push_back(" ");
85  }
86 
87  auto& pop_table = this->make_widget<UI::Table<uint32_t>>(0, 352, this->height - (352 + 32), 30, sizes, header);
88  pop_table.reserve(this->province.pops.size());
89  pop_table.set_on_each_tick([this, &pop_table](UI::Widget&) {
90  for(size_t i = 0; i < this->province.pops.size(); i++) {
91  auto& pop = this->province.pops[i];
92  auto& row = pop_table.get_row(i);
93  size_t row_index = 0;
94 
95  auto* size = row.get_element(row_index++);
96  auto size_str = string_format("%.0f", pop.size);
97  size->set_text(size_str);
98  size->set_key(pop.size);
99 
100  auto* budget = row.get_element(row_index++);
101  auto budget_str = string_format("%.0f", pop.budget / pop.size);
102  budget->set_text(budget_str);
103  auto budget_tip = Eng3D::translate_format("Total budget: %.2f", pop.budget);
104  budget->set_tooltip(budget_tip);
105  budget->set_key(pop.budget / pop.size);
106 
107  if(this->gs.editor) {
108  auto* remove_btn = row.get_element(row_index++);
109  auto remove_btn_str = "X";
110  remove_btn->set_text(remove_btn_str);
111  remove_btn->set_key(remove_btn_str);
112  remove_btn->set_on_click([this, i, &pop_table](UI::Widget&) {
113  pop_table.remove_row(i);
114  const_cast<Province&>(this->province).pops[i].size = 0.f;
115  pop_table.on_each_tick(pop_table);
116  });
117  }
118  }
119  });
120  pop_table.on_each_tick(pop_table);
121  return pop_table;
122 }
123 
124 UI::Widget& ProvincePopulationTab::create_stock_table() {
125  std::vector<int> sizes{ 100, 100, 100, 100, 100 };
126  std::vector<std::string> header{ "Commodity", "Amount", "Demand", "Glob Demand", "Price" };
127  auto& stock_table = this->make_widget<UI::Table<uint32_t>>(0, 352, this->height - (352 + 32), 30, sizes, header);
128  stock_table.reserve(this->province.pops.size());
129  stock_table.set_on_each_tick([this, &stock_table](UI::Widget&) {
130  for(const auto& commodity : this->gs.world->commodities) {
131  auto& product = this->province.products[commodity];
132  auto& row = stock_table.get_row(commodity.get_id());
133  size_t row_index = 0;
134 
135  auto* commodity_row = row.get_element(row_index++);
136  commodity_row->set_key(commodity.name.c_str());
137  auto& commodity_img = commodity_row->make_widget<UI::Image>(0, 0, 35, 35, commodity.get_icon_path(), true);
138  commodity_img.set_tooltip(commodity.name);
139 
140  auto* amount = row.get_element(row_index++);
141  amount->set_key(product.supply, "%.0f");
142 
143  auto* demand = row.get_element(row_index++);
144  demand->set_key(product.demand, "%.1f");
145 
146  auto* global_demand = row.get_element(row_index++);
147  global_demand->set_key(product.global_demand, "%.2f");
148 
149  auto* price = row.get_element(row_index++);
150  price->set_key(product.price, "%.2f");
151  }
152  });
153  stock_table.on_each_tick(stock_table);
154  return stock_table;
155 }
156 
158  : UI::Group(_x, _y, _parent->width - _x, _parent->height - _y, _parent),
159  gs{ _gs },
160  province{ _province }
161 {
162  this->is_scroll = true;
163  this->set_text(province.name);
164 
165  const auto& terrain_type = gs.world->terrain_types[province.terrain_type_id];
166  auto& landscape_img = this->make_widget<UI::Image>(0, 0, this->width - 16, 128 + 64 + 16, terrain_type.get_icon_path());
167  landscape_img.set_tooltip(translate_format("%s, penalty %.2f", terrain_type.name.c_str(), terrain_type.penalty));
168 
169  auto& owner_flag = this->make_widget<UI::AspectImage>(0, 0, 96, 48, gs.get_nation_flag(gs.world->nations[this->province.owner_id]));
170  owner_flag.set_on_click([this](UI::Widget&) {
171  new Interface::NationView(this->gs, gs.world->nations[this->province.owner_id]);
172  });
173  owner_flag.set_tooltip(translate_format("%s owns this province", gs.world->nations[this->province.owner_id].name.c_str()));
174  //this->make_widget<UI::Image>(owner_flag->x, owner_flag->y, owner_flag->width, owner_flag->height, "gfx/flag_rug.png");
175 
176  // Display all the nuclei
177  auto& nuclei_flex_row = this->make_widget<UI::Div>(0, landscape_img.height - 24, this->width, 24);
178  nuclei_flex_row.flex = UI::Flex::ROW;
179  for(const auto nucleus_id : province.nuclei) {
180  auto& nucleus = this->gs.world->nations[nucleus_id];
181  auto& owner_flag = nuclei_flex_row.make_widget<UI::AspectImage>(0, 0, 32, 24, gs.get_nation_flag(nucleus));
182  owner_flag.set_on_click([this, nucleus_id](UI::Widget&) {
183  new Interface::NationView(this->gs, this->gs.world->nations[nucleus_id]);
184  });
185  owner_flag.set_tooltip(translate_format("%s has claims on this province", nucleus.name.c_str()));
186  }
187 
188  auto& pop_table = create_pop_table();
189  auto& stock_table = create_stock_table();
190  stock_table.right_side_of(pop_table);
191 
192  auto& languages_lab = this->make_widget<UI::Label>(0, 0, "Languages");
193  languages_lab.below_of(landscape_img);
194  this->languages_pie = &this->make_widget<UI::PieChart>(0, 0, 96, 96);
195  this->languages_pie->below_of(languages_lab);
196 
197  auto& religions_lab = this->make_widget<UI::Label>(0, 0, "Religions");
198  religions_lab.below_of(landscape_img);
199  religions_lab.right_side_of(*this->languages_pie);
200  this->religions_pie = &this->make_widget<UI::PieChart>(0, 0, 96, 96);
201  this->religions_pie->below_of(religions_lab);
202  this->religions_pie->right_side_of(*this->languages_pie);
203 
204  auto& pop_types_lab = this->make_widget<UI::Label>(0, 0, "Professions");
205  pop_types_lab.below_of(landscape_img);
206  pop_types_lab.right_side_of(*this->religions_pie);
207  this->pop_types_pie = &this->make_widget<UI::PieChart>(0, 0, 96, 96);
208  this->pop_types_pie->below_of(pop_types_lab);
209  this->pop_types_pie->right_side_of(*this->religions_pie);
210 
211  this->set_on_each_tick([this](UI::Widget&) {
212  this->update_piecharts();
213  });
214  this->on_each_tick(*this);
215 }
216 
217 ProvinceEconomyTab::ProvinceEconomyTab(GameState& _gs, int _x, int _y, Province& _province, UI::Widget* _parent)
218  : UI::Group(_x, _y, _parent->width - _x, _parent->height - _y, _parent),
219  gs{ _gs },
220  province{ _province }
221 {
222  this->set_text(province.name);
223  this->is_scroll = true;
224 }
225 
226 ProvinceBuildingTab::ProvinceBuildingTab(GameState& _gs, int _x, int _y, Province& _province, UI::Widget* _parent)
227  : UI::Group(_x, _y, _parent->width - _x, _parent->height - _y, _parent),
228  gs{ _gs },
229  province{ _province }
230 {
231  Interface::IndustryWindow::new_table(gs, 0, 0, 0, this->height, { province.get_id() }, this);
232 }
233 
235  : UI::Group(_x, _y, _parent->width - _x, _parent->height - _y, _parent),
236  gs{ _gs },
237  province{ _province },
238  language{ _gs.world->languages[0] },
239  religion{ _gs.world->religions[0] }
240 {
241  this->is_scroll = false;
242 
243  std::vector<int> sizes{ 96, 128 };
244  std::vector<std::string> header{ "Language", "Religion" };
245  auto& table = this->make_widget<UI::Table<uint32_t>>(0, 0, this->height, 30, sizes, header);
246  table.reserve(this->gs.world->languages.size());
247  table.set_on_each_tick([this, &table](Widget&) {
248  for(size_t i = 0; i < this->gs.world->religions.size() || i < this->gs.world->languages.size(); i++) {
249  auto& row = table.get_row(i);
250  size_t row_index = 0;
251 
252  auto& row_religion = i >= this->gs.world->religions.size() ? this->gs.world->religions[0] : this->gs.world->religions[i];
253  auto* religion_icon = row.get_element(row_index++);
254  religion_icon->current_texture = this->gs.tex_man.load(gs.package_man.get_unique(row_religion.get_icon_path()));
255  religion_icon->set_tooltip(row_religion.name);
256  religion_icon->set_key(row_religion.name);
257  religion_icon->set_on_click([this, religion_id = row_religion.get_id()](UI::Widget&) {
258  const_cast<Province&>(this->province).religions[religion_id] = 1.f;
259  this->gs.map->update_mapmode();
260  this->gs.input.selected_religion = &this->gs.world->religions[religion_id];
261  });
262 
263  auto& row_language = i >= this->gs.world->languages.size() ? this->gs.world->languages[0] : this->gs.world->languages[i];
264  auto* name = row.get_element(row_index++);
265  name->set_text(row_language.name);
266  name->set_tooltip(row_language.name);
267  name->set_key(row_language.name);
268  name->set_on_click([this, language_id = row_language.get_id()](UI::Widget&) {
269  const_cast<Province&>(this->province).languages[language_id] = 1.f;
270  this->gs.map->update_mapmode();
271  this->gs.input.selected_language = &this->gs.world->languages[language_id];
272  });
273  }
274  });
275  table.on_each_tick(table);
276 }
277 
279  : UI::Group(_x, _y, _parent->width - _x, _parent->height - _y, _parent),
280  gs{ _gs },
281  province{ _province },
282  terrain_type{ _gs.world->terrain_types[0] }
283 {
284  std::vector<int> sizes{ 96, 128 };
285  std::vector<std::string> header{ "Landscape", "Name" };
286  auto& table = this->make_widget<UI::Table<uint32_t>>(0, 0, this->height, 30, sizes, header);
287  table.reserve(gs.world->terrain_types.size());
288  table.set_on_each_tick([this, &table](Widget&) {
289  for(auto& terrain_type_row : this->gs.world->terrain_types) {
290  auto& row = table.get_row(terrain_type_row);
291  size_t row_index = 0;
292 
293  auto landscape = row.get_element(row_index++);
294  auto landscape_icon = gs.tex_man.load(gs.package_man.get_unique(terrain_type_row.get_icon_path()));
295  landscape->current_texture = landscape_icon;
296  landscape->set_tooltip(terrain_type_row.name);
297  landscape->set_key(terrain_type_row.name);
298 
299  auto name = row.get_element(row_index++);
300  name->set_text(terrain_type_row.name);
301  name->set_tooltip(terrain_type_row.name);
302  name->set_key(terrain_type_row.name);
303  name->set_on_click([this, &terrain_type_row](UI::Widget&) {
304  auto& nc_province = const_cast<Province&>(this->province);
305  nc_province.terrain_type_id = terrain_type_row;
306  if(terrain_type_row.is_water_body) {
307  nc_province.unpopulate();
308  nc_province.nuclei.clear();
309  for(auto& building : nc_province.buildings)
310  building.level = 0;
311  }
312 
313  this->gs.map->update_mapmode();
314  });
315  }
316  });
317  table.on_each_tick(table);
318 }
319 
321  : UI::Window(-400, -400, 800, 800),
322  gs{ _gs },
323  province{ _province }
324 {
325  this->set_close_btn_function([this](Widget&) {
326  this->kill();
327  this->gs.map->set_selected_province(false, ProvinceId(-1));
328  });
329  this->gs.map->set_selected_province(true, this->province.get_id());
330 
332  this->is_scroll = false;
333  this->set_text(province.name);
334 
335  auto& flex_row = this->make_widget<UI::Div>(0, 0, this->width, 32);
336  flex_row.flex = UI::Flex::ROW;
337  if(gs.editor)
338  flex_row.height += 32;
339 
340  this->pop_tab = &this->make_widget<ProvincePopulationTab>(gs, 0, flex_row.height, province);
341  this->pop_tab->is_render = true;
342  auto& pop_ibtn = flex_row.make_widget<UI::Image>(0, 0, 32, 32, "gfx/pv_1.png");
343  pop_ibtn.set_on_click([this](UI::Widget&) {
344  this->pop_tab->is_render = true;
345  this->econ_tab->is_render = false;
346  this->build_tab->is_render = false;
347  if(gs.editor) {
348  this->edit_language_tab->is_render = false;
349  this->edit_terrain_tab->is_render = false;
350  }
351  });
352  pop_ibtn.set_tooltip(translate("Population"));
353 
354  this->econ_tab = &this->make_widget<ProvinceEconomyTab>(gs, 0, flex_row.height, province);
355  this->econ_tab->is_render = false;
356  auto& econ_ibtn = flex_row.make_widget<UI::Image>(0, 0, 32, 32, "gfx/money.png");
357  econ_ibtn.set_on_click([this](UI::Widget&) {
358  this->pop_tab->is_render = false;
359  this->econ_tab->is_render = true;
360  this->build_tab->is_render = false;
361  if(gs.editor) {
362  this->edit_language_tab->is_render = false;
363  this->edit_terrain_tab->is_render = false;
364  }
365  });
366  econ_ibtn.set_tooltip(translate("Economy"));
367 
368  this->build_tab = &this->make_widget<ProvinceBuildingTab>(gs, 0, flex_row.height, province);
369  this->build_tab->is_render = false;
370  auto& build_ibtn = flex_row.make_widget<UI::Image>(0, 0, 32, 32, "gfx/pv_0.png");
371  build_ibtn.set_on_click([this](UI::Widget&) {
372  this->pop_tab->is_render = false;
373  this->econ_tab->is_render = false;
374  this->build_tab->is_render = true;
375  if(gs.editor) {
376  this->edit_language_tab->is_render = false;
377  this->edit_terrain_tab->is_render = false;
378  }
379  });
380  build_ibtn.set_tooltip(translate("Buildings"));
381 
382  if(gs.editor) {
383  auto& fill_pops_btn = flex_row.make_widget<UI::Button>(0, this->height - 64, 32, 32);
384  fill_pops_btn.set_on_click([this](UI::Widget&) {
385  // Get max sv
386  auto max_sv = 1.f;
387  for(const auto& pop_type : this->gs.world->pop_types)
388  if(pop_type.social_value > max_sv)
389  max_sv = pop_type.social_value;
390 
391  if(this->gs.input.selected_language == nullptr)
392  this->gs.input.selected_language = &this->gs.world->languages[0];
393  if(this->gs.input.selected_religion == nullptr)
394  this->gs.input.selected_religion = &this->gs.world->religions[0];
395 
396  for(const auto& pop_type : this->gs.world->pop_types) {
397  auto& pop = province.pops[pop_type];
398  pop.type_id = pop_type.get_id();
399  pop.size = 1000.f;
400  pop.literacy = 0.5;
401  pop.budget = pop.size;
402  }
403  this->gs.map->update_mapmode();
404  this->gs.update_tick = true;
405  });
406  fill_pops_btn.set_tooltip(translate_format("Add POPs (will add %zu POPs)", gs.world->pop_types.size()));
407 
408  this->edit_language_tab = &this->make_widget<ProvinceEditLanguageTab>(gs, 0, 32, province);
409  this->edit_language_tab->is_render = false;
410  auto& edit_language_btn = flex_row.make_widget<UI::Image>(0, 0, 32, 32, "gfx/money.png");
411  edit_language_btn.set_on_click([this](UI::Widget&) {
412  this->pop_tab->is_render = false;
413  this->econ_tab->is_render = false;
414  this->build_tab->is_render = false;
415  this->edit_language_tab->is_render = true;
416  this->edit_terrain_tab->is_render = false;
417  });
418  edit_language_btn.set_tooltip(translate("Edit primary language and religion"));
419 
420  this->edit_terrain_tab = &this->make_widget<ProvinceEditTerrainTab>(gs, 0, 32, province);
421  this->edit_terrain_tab->is_render = false;
422  auto& edit_terrain_btn = flex_row.make_widget<UI::Image>(0, 0, 32, 32, "gfx/money.png");
423  edit_terrain_btn.set_on_click([this](UI::Widget&) {
424  this->pop_tab->is_render = false;
425  this->econ_tab->is_render = false;
426  this->build_tab->is_render = false;
427  this->edit_language_tab->is_render = false;
428  this->edit_terrain_tab->is_render = true;
429  });
430  edit_terrain_btn.set_tooltip(translate("Edit terrain"));
431 
432  auto& density_sld = this->make_widget<UI::Slider>(0, 32, 128, 24, 0.1f, 2.f);
433  density_sld.set_value(0.f);
434  density_sld.set_on_click([this](UI::Widget& w) {
435  auto& o = static_cast<UI::Slider&>(w);
436  w.set_text(string_format("%.2f", o.get_value()));
437  const auto den = o.get_value();
438  for(auto& pop : const_cast<Province&>(this->province).pops)
439  pop.size *= den;
440  this->gs.map->update_mapmode();
441  this->gs.map->map_render->request_update_visibility();
442  this->gs.update_tick = true;
443  });
444  density_sld.set_tooltip(translate("Density slider"));
445 
446  auto& rename_inp = this->make_widget<UI::Input>(128, 32, 128, 24);
447  rename_inp.set_buffer(province.name);
448  auto& xchg_name_btn = this->make_widget<UI::Button>(128 + 128, 32, 32, 32);
449  xchg_name_btn.set_on_click([this, &rename_inp](UI::Widget&) {
450  const_cast<Province&>(this->province).name = Eng3D::StringRef{rename_inp.get_buffer()};
451  this->gs.map->create_labels();
452  this->gs.update_tick = true;
453  });
454  xchg_name_btn.set_tooltip("Rename province");
455  }
456 }
457 
459  gs.map->set_selected_province(true, ProvinceId(0));
460 }
std::shared_ptr< Eng3D::IO::Asset::Base > get_unique(const Eng3D::IO::Path &path)
Obtaining an unique asset means the "first-found" policy applies.
Definition: io.cpp:146
Eng3D::TextureManager tex_man
Definition: state.hpp:124
Eng3D::IO::PackageManager package_man
Definition: state.hpp:122
std::shared_ptr< Eng3D::Texture > load(const std::string &path, TextureOptions options=default_options)
Finds a texture in the list of a texture manager if the texture is already in the list we load the sa...
Definition: texture.cpp:432
std::atomic< bool > update_tick
Definition: game_state.hpp:150
Input input
Definition: game_state.hpp:160
std::unique_ptr< Map > map
Definition: game_state.hpp:159
std::shared_ptr< Eng3D::Texture > get_nation_flag(const Nation &nation)
Definition: game_state.cpp:84
World * world
Definition: game_state.hpp:156
Language * selected_language
Definition: game_state.hpp:102
Religion * selected_religion
Definition: game_state.hpp:103
static UI::Table< uint32_t > * new_table(GameState &gs, int _x, int _y, int _w, int _h, std::vector< ProvinceId > provinces, UI::Widget *parent)
ProvincePopulationTab(GameState &gs, int x, int y, Province &province, UI::Widget *_parent)
ProvinceView(GameState &gs, Province &province)
A single province, which is used to simulate economy in a "bulk-tiles" way instead of doing economica...
Definition: province.hpp:48
std::vector< float > religions
Percentage of each religion prescence on the pops, from 0 to 1.
Definition: province.hpp:128
std::array< Pop, 7 > pops
Definition: province.hpp:107
Eng3D::StringRef name
Definition: province.hpp:96
std::vector< NationId > nuclei
Definition: province.hpp:123
std::vector< float > languages
Percentage of each languages from 0 to 1.
Definition: province.hpp:126
TerrainTypeId terrain_type_id
Definition: province.hpp:105
float total_pops() const
Definition: province.hpp:51
A version of the Image widget that keeps aspect ratio of the image (useful for flags)
Definition: image.hpp:56
Button widget.
Definition: button.hpp:32
Generalized chart data, used mostly by chart widgets, however it's not specific to any widget.
Definition: widget.hpp:129
Image widget, can display pictures or effects on the screen.
Definition: image.hpp:43
void set_data(std::vector< ChartData > data)
Definition: piechart.cpp:52
Slider widget.
Definition: slider.hpp:38
The master widget all the other widgets inherit from, do not use directly instead use one of the many...
Definition: widget.hpp:176
constexpr void below_of(const UI::Widget &rhs)
Definition: widget.hpp:246
virtual void set_on_click(std::function< void(UI::Widget &)> _on_click)
Sets the on_click function of this widget.
Definition: widget.hpp:259
UI::Origin origin
Definition: widget.hpp:318
bool is_scroll
Definition: widget.hpp:306
size_t width
Definition: widget.hpp:325
constexpr void right_side_of(const UI::Widget &rhs)
Definition: widget.hpp:254
virtual void set_on_each_tick(std::function< void(UI::Widget &)> _on_each_tick)
Sets the on_each_tick function of this widget.
Definition: widget.hpp:264
void kill()
Kills the current widget, setting it up for deletion when dead widgets are cleared by the UI context.
Definition: widget.hpp:283
std::function< void(UI::Widget &)> on_each_tick
Definition: widget.hpp:352
Widget()=default
virtual void set_text(const std::string &text)
Generates text for the widget and overrides the current text texture.
Definition: widget.cpp:445
size_t height
Definition: widget.hpp:325
bool is_render
Definition: widget.hpp:303
void set_close_btn_function(std::function< void(Widget &)> on_click)
Definition: window.cpp:65
T::Id get_id(const T &obj) const
Get the id of an object, this is a template for all types except for tiles and locally-stored types (...
Definition: world.hpp:179
std::string translate(const std::string_view str)
Definition: string.cpp:76
std::string string_format(const std::string_view format, Args &&... args)
String formatter.
Definition: string.hpp:100
std::string translate_format(const std::string_view format, Args &&... args)
String formatter, with translation.
Definition: string.hpp:128
Primitive color type used through the engine.
Definition: color.hpp:32
constexpr static Color bgr32(uint32_t abgr)
Definition: color.hpp:101
A reference to a string on the global string pool.
Definition: string.hpp:39
constexpr Id get_id() const
Definition: entity.hpp:152
ProvinceBuildingTab(GameState &gs, int x, int y, Province &province, UI::Widget *_parent)
ProvinceEconomyTab(GameState &gs, int x, int y, Province &province, UI::Widget *_parent)
ProvinceEditLanguageTab(GameState &gs, int x, int y, Province &province, UI::Widget *_parent)
ProvinceEditTerrainTab(GameState &gs, int x, int y, Province &province, UI::Widget *_parent)