Symphony Of Empires
top_window.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/top_window.cpp
20 //
21 // Abstract:
22 // Does some important stuff.
23 // ----------------------------------------------------------------------------
24 
25 #include "eng3d/texture.hpp"
26 #include "eng3d/ui/components.hpp"
27 #include "eng3d/ttf.hpp"
28 #include "eng3d/string.hpp"
29 
32 #include "client/game_state.hpp"
35 #include "client/map.hpp"
36 #include "world.hpp"
41 #include "client/lua_save_util.hpp"
42 
43 using namespace Interface;
44 
46  : UI::Group(0, 0),
47  gs{ _gs }
48 {
49  this->is_scroll = false;
50  this->is_pinned = true;
51 
52  this->gs.time_win = static_cast<UI::Widget*>(new TimeControlView(gs));
53 
54  UI::Image::make_transparent(0, 0, 147, 499, "gfx/top_window.png", this);
55  auto& flag_img = this->make_widget<UI::Image>(5, 4, 138, 88, this->gs.tex_man.get_white());
56  flag_img.set_on_each_tick([this](UI::Widget& w) {
57  w.current_texture = this->gs.get_nation_flag(*this->gs.curr_nation);
58  });
59  flag_img.on_each_tick(flag_img);
60 #ifndef E3D_HANDHELD
61  this->make_widget<UI::Image>(5, 4, flag_img.width, flag_img.height, "gfx/drop_shadow.png");
62 #endif
63 
64  auto& event_tray_grp = this->make_widget<UI::Image>(150, 32, 356 + 256, 32, "gfx/background2.png", true);
65  event_tray_grp.flex = UI::Flex::ROW;
66  this->gs.event_tray_grp = &event_tray_grp;
67 
68  auto& stats_grp = this->make_widget<UI::Image>(150, 0, 356 + 256, 32, "gfx/background2.png", true);
69  stats_grp.flex = UI::Flex::ROW;
70 
71  auto& money_grp = stats_grp.make_widget<UI::Div>(0, 0, 24 + 96, 24);
72  money_grp.flex = UI::Flex::ROW;
73  auto& money_img = money_grp.make_widget<UI::Image>(0, 0, 24, 24, "gfx/economy.png", true);
74  money_img.set_tooltip("Money");
75  auto& money_lab = money_grp.make_widget< UI::Label>(0, 0, " ");
76  money_lab.set_on_each_tick([this](UI::Widget& w) {
77  w.set_text(Eng3D::translate_format("%.0f", this->gs.curr_nation->budget));
78  });
79  money_lab.on_each_tick(money_lab);
80 
81  auto& population_grp = stats_grp.make_widget<UI::Div>(0, 0, 24 + 96, 24);
82  population_grp.flex = UI::Flex::ROW;
83  auto& population_img = population_grp.make_widget< UI::Image>(0, 0, 24, 24, "gfx/pop.png", true);
84  population_img.set_tooltip("Population");
85  auto& population_lab = population_grp.make_widget< UI::Label>(0, 0, " ");
86  population_lab.set_on_each_tick([this](UI::Widget& w) {
87  const auto total = std::accumulate(gs.curr_nation->owned_provinces.cbegin(), gs.curr_nation->owned_provinces.cend(), 0.f, [this](auto&& a, const auto province_id) -> float {
88  return a + gs.world->provinces[province_id].total_pops();
89  });
90  w.set_text(Eng3D::string_format("%.0f", total));
91 
92  const auto [it1, it2] = std::minmax_element(gs.curr_nation->owned_provinces.cbegin(), gs.curr_nation->owned_provinces.cend(), [this](const auto province_id, const auto other_province_id) {
93  return gs.world->provinces[province_id].total_pops() < gs.world->provinces[other_province_id].total_pops();
94  });
95  const auto& smallest_province = gs.world->provinces[*it1];
96  const auto& largest_province = gs.world->provinces[*it2];
97 
98  w.set_tooltip(Eng3D::string_format("Average population density: %.0f\nLargest province: %s (%.0f)\nSmallest province: %s (%.0f)", total / gs.curr_nation->owned_provinces.size(), largest_province.name.c_str(), largest_province.total_pops(), smallest_province.name.c_str(), smallest_province.total_pops()));
99  });
100  population_lab.on_each_tick(population_lab);
101 
102  auto& military_score_grp = stats_grp.make_widget<UI::Div>(0, 0, 24 + 64, 24);
103  military_score_grp.flex = UI::Flex::ROW;
104  auto& military_score_img = military_score_grp.make_widget<UI::Image>(0, 0, 24, 24, "gfx/military_score.png", true);
105  military_score_img.set_tooltip("Military score");
106  auto& military_score_lab = military_score_grp.make_widget<UI::Label>(0, 0, " ");
107  military_score_lab.set_on_each_tick([this](UI::Widget& w) {
108  const auto total = std::accumulate(gs.curr_nation->owned_provinces.cbegin(), gs.curr_nation->owned_provinces.cend(), 0.f, [this](const auto a, const auto province_id) -> float {
109  const auto& province = this->gs.world->provinces[province_id];
110  const auto& units = this->gs.world->unit_manager.get_province_units(province.get_id());
111  return a + std::accumulate(units.cbegin(), units.cend(), 0, [this](const auto a2, const auto unit_id) {
112  const auto& unit = this->gs.world->unit_manager.units[unit_id];
113  return a2 + (unit.owner_id == this->gs.curr_nation->get_id() ? unit.get_strength() : 0.f);
114  });
115  });
116  w.set_text(Eng3D::string_format("%.0f", total));
117  });
118  military_score_lab.on_each_tick(military_score_lab);
119 
120  auto& industrial_score_grp = stats_grp.make_widget<UI::Div>(0, 0, 24 + 64, 24);
121  industrial_score_grp.flex = UI::Flex::ROW;
122  auto& industrial_score_img = industrial_score_grp.make_widget<UI::Image>(0, 0, 24, 24, "gfx/industry.png", true);
123  industrial_score_img.set_tooltip("Industrial score");
124  auto& industrial_score_lab = industrial_score_grp.make_widget<UI::Label>(0, 0, " ");
125  industrial_score_lab.set_on_each_tick([this](UI::Widget& w) {
126  const auto total = std::accumulate(gs.curr_nation->owned_provinces.cbegin(), gs.curr_nation->owned_provinces.cend(), 0.f, [this](const auto a, const auto province_id) -> float {
127  const auto& province = this->gs.world->provinces[province_id];
128  const auto& buildings = province.get_buildings();
129  return a + std::accumulate(buildings.cbegin(), buildings.cend(), 0.f, [](const auto a2, const auto& building) {
130  return a2 + (building.production_scale * building.level);
131  });
132  });
133  w.set_text(Eng3D::string_format("%.0f", total));
134  });
135  industrial_score_lab.on_each_tick(industrial_score_lab);
136 
137  auto& prestige_score_grp = stats_grp.make_widget<UI::Div>(0, 0, 24 + 64, 24);
138  prestige_score_grp.flex = UI::Flex::ROW;
139  auto& prestige_score_img = prestige_score_grp.make_widget<UI::Image>(0, 0, 24, 24, "gfx/prestige.png", true);
140  prestige_score_img.set_tooltip("Prestige");
141  auto& prestige_score_lab = prestige_score_grp.make_widget<UI::Label>(0, 0, " ");
142  prestige_score_lab.set_on_each_tick([this](UI::Widget& w) {
143  w.set_text(Eng3D::string_format("%.0f", this->gs.curr_nation->prestige));
144  });
145  prestige_score_lab.on_each_tick(prestige_score_lab);
146 
147  auto& flex_column = this->make_widget<UI::Div>(3, 96, 42, 390);
148  flex_column.flex = UI::Flex::COLUMN;
149  flex_column.flex_justify = UI::FlexJustify::SPACE_AROUND;
150  flex_column.flex_align = UI::Align::CENTER;
151 
152  int icon_size = 28;
153 
154  auto& policy_ibtn = flex_column.make_widget<UI::Image>(0, 0, icon_size, icon_size, "gfx/book.png", true);
155  policy_ibtn.set_on_click([this](UI::Widget&) {
156  new Interface::PoliciesView(this->gs);
157  });
158  policy_ibtn.set_tooltip("Laws & Policies");
159 
160  auto& economy_ibtn = flex_column.make_widget<UI::Image>(0, 0, icon_size, icon_size, "gfx/economy.png", true);
161  economy_ibtn.set_on_click([this](UI::Widget&) {
162 
163  });
164  economy_ibtn.set_tooltip("Economy");
165 
166  auto& pops_ibtn = flex_column.make_widget<UI::Image>(0, 0, icon_size, icon_size, "gfx/pop.png", true);
167  pops_ibtn.set_on_click([this](UI::Widget&) {
168  new Interface::PopWindow(this->gs);
169  });
170  pops_ibtn.set_tooltip("Population");
171 
172  auto& industry_ibtn = flex_column.make_widget<UI::Image>(0, 0, icon_size, icon_size, "gfx/industry.png", true);
173  industry_ibtn.set_on_click([this](UI::Widget&) {
174  new Interface::IndustryWindow(this->gs);
175  });
176  industry_ibtn.set_tooltip("Factories");
177 
178  auto& military_ibtn = flex_column.make_widget<UI::Image>(0, 0, icon_size, icon_size, "gfx/military_score.png", true);
179  military_ibtn.set_on_click([this](UI::Widget&) {
180  new Interface::ArmyView(this->gs);
181  });
182  military_ibtn.set_tooltip("Military");
183 
184  auto& research_ibtn = flex_column.make_widget<UI::Image>(0, 0, icon_size, icon_size, "gfx/tech.png", true);
185  research_ibtn.set_on_click([this](UI::Widget&) {
186 
187  });
188  research_ibtn.set_tooltip("Research");
189 
190  auto& save_ibtn = flex_column.make_widget<UI::Image>(0, 0, icon_size, icon_size, "gfx/save.png", true);
191  save_ibtn.set_on_click([this](UI::Widget&) {
192  LUA_util::save(this->gs, string_format("%s_%zu-%zu-%zu.sc4", gs.curr_nation->ref_name.c_str(), gs.world->get_year(), gs.world->get_month(), gs.world->get_day()));
193  });
194  save_ibtn.set_tooltip("Saves the current game");
195 
196  auto& load_ibtn = flex_column.make_widget<UI::Image>(9, 275, 25, 25, "gfx/top_bar/save.png", true);
197  load_ibtn.set_on_click([this](UI::Widget&) {
198  LUA_util::load(this->gs, "autosave.sc4");
199  });
200  load_ibtn.set_tooltip("Load latest autosave");
201 
202  auto& exit_ibtn = flex_column.make_widget<UI::Image>(0, 0, icon_size, icon_size, "gfx/exit.png", true);
203  exit_ibtn.set_on_click([this](UI::Widget&) {
204  this->gs.ui_ctx.clear();
205  this->gs.ui_ctx.use_tooltip(nullptr, { 0, 0 });
206  this->gs.paused = true;
207  this->gs.client.reset();
208  this->gs.server.reset();
209  new Interface::MainMenu(this->gs);
210  });
211  exit_ibtn.set_tooltip("Back to the main menu");
212 }
213 
214 TimeControlView::TimeControlView(GameState& _gs)
215  : UI::Group(-480, 0),
216  gs{ _gs }
217 {
218  this->is_scroll = false;
219  this->is_pinned = true;
221 
222  UI::Image::make_transparent(0, 0, 480, 60, "gfx/ui/bg/time_control_bg.png", true, this);
223 
224  int btn_size = 30;
225  if(!gs.editor) {
226  auto& btn_group = this->make_widget<UI::Group>(320, 12);
227  auto& speed0_btn = btn_group.make_widget<UI::Image>(0, 0, btn_size, btn_size, "gfx/ui/button/time_control_pause.png", true);
228  speed0_btn.set_on_click([this](UI::Widget&) {
229  this->gs.paused = true;
230  });
231  speed0_btn.set_tooltip(translate("Pause"));
232  auto& speed1_btn = btn_group.make_widget<UI::Image>(45, 0, btn_size, btn_size, "gfx/ui/button/time_control_1.png", true);
233  speed1_btn.set_on_click([this](UI::Widget&) {
234  this->gs.paused = false;
235  this->gs.ms_delay_speed = 1000;
236  });
237  speed1_btn.set_tooltip(translate("Turtle speed"));
238  auto& speed2_btn = btn_group.make_widget<UI::Image>(80, 0, btn_size, btn_size, "gfx/ui/button/time_control_2.png", true);
239  speed2_btn.set_on_click([this](UI::Widget&) {
240  this->gs.paused = false;
241  this->gs.ms_delay_speed = 500;
242  });
243  speed2_btn.set_tooltip(translate("Horse speed"));
244  auto& speed3_btn = btn_group.make_widget<UI::Image>(115, 0, btn_size, btn_size, "gfx/ui/button/time_control_3.png", true);
245  speed3_btn.set_on_click([this](UI::Widget&) {
246  this->gs.paused = false;
247  this->gs.ms_delay_speed = 100;
248  });
249  speed3_btn.set_tooltip(translate("Fire speed"));
250  }
251 
252  auto& time_lab = this->make_widget<UI::Label>(50, 30, " ");
253  time_lab.font = gs.ttf_man.load(gs.package_man.get_unique("fonts/neon_euler/euler.ttf"));
254  time_lab.text_color = Eng3D::Color(1., 1., 1.);
255  time_lab.set_on_each_tick([this](UI::Widget& w) {
256  std::tm tm{};
257  tm.tm_year = this->gs.world->get_year() - 1900;
258  tm.tm_mon = this->gs.world->get_month() - 1;
259  tm.tm_mday = this->gs.world->get_day() + 1;
260  char mbstr[100];
261  std::strftime(mbstr, sizeof mbstr, "%x", &tm);
262  w.set_text(mbstr);
263  });
264  time_lab.on_each_tick(time_lab);
265 }
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::TrueType::Manager ttf_man
Definition: state.hpp:127
Eng3D::TextureManager tex_man
Definition: state.hpp:124
Eng3D::IO::PackageManager package_man
Definition: state.hpp:122
std::shared_ptr< Eng3D::Texture > get_white()
Definition: texture.cpp:417
std::shared_ptr< Eng3D::TrueType::Font > load(std::shared_ptr< Eng3D::IO::Asset::Base > asset)
Definition: ttf.cpp:58
UI::Widget * event_tray_grp
Definition: game_state.hpp:169
std::atomic< bool > paused
Definition: game_state.hpp:151
Nation * curr_nation
Definition: game_state.hpp:158
UI::Widget * time_win
Definition: game_state.hpp:166
std::shared_ptr< Eng3D::Texture > get_nation_flag(const Nation &nation)
Definition: game_state.cpp:84
World * world
Definition: game_state.hpp:156
std::atomic< int > ms_delay_speed
Definition: game_state.hpp:152
TopWindow(GameState &gs)
Definition: top_window.cpp:45
float budget
Definition: nation.hpp:129
std::vector< ProvinceId > owned_provinces
Definition: nation.hpp:148
Image widget, can display pictures or effects on the screen.
Definition: image.hpp:43
static Image * make_transparent(int x, int y, unsigned w, unsigned h, const std::string &tex_path, Widget *parent=nullptr)
Definition: image.cpp:64
Simple widget for drawing text on the screen, no multiline support.
Definition: label.hpp:40
The master widget all the other widgets inherit from, do not use directly instead use one of the many...
Definition: widget.hpp:176
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
virtual void set_tooltip(UI::Tooltip *tooltip)
Set the tooltip to be shown when this widget is hovered, overrides the previous tooltip.
Definition: widget.cpp:458
bool is_scroll
Definition: widget.hpp:306
std::shared_ptr< Eng3D::Texture > current_texture
Definition: widget.hpp:327
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
UI::Flex flex
Definition: widget.hpp:337
bool is_pinned
Definition: widget.hpp:302
virtual void set_text(const std::string &text)
Generates text for the widget and overrides the current text texture.
Definition: widget.cpp:445
int get_year(void) const
Definition: world.hpp:204
int get_month(void) const
Definition: world.hpp:208
int get_day(void) const
Definition: world.hpp:212
@ UPPER_RIGHT_SCREEN
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
void save(GameState &gs, const std::string &savefile_path)
void load(GameState &gs, const std::string &savefile_path)
Primitive color type used through the engine.
Definition: color.hpp:32
A basic widget without any presets.
Definition: div.hpp:38