1 // Copyright (C) 2007-2009, 2011, 2012, 2014-2017, 2020 Ben Asselstine
2 //
3 // This program is free software; you can redistribute it and/or modify
4 // it under the terms of the GNU General Public License as published by
5 // the Free Software Foundation; either version 3 of the License, or
6 // (at your option) any later version.
7 //
8 // This program is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 // GNU Library General Public License for more details.
12 //
13 // You should have received a copy of the GNU General Public License
14 // along with this program; if not, write to the Free Software
15 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
16 // 02110-1301, USA.
17
18 #include <config.h>
19
20 #include <gtkmm.h>
21 #include <sigc++/functors/mem_fun.h>
22
23 #include "report-dialog.h"
24 #include "bar-chart.h"
25 #include "ucompose.hpp"
26 #include "defs.h"
27 #include "GameMap.h"
28 #include "playerlist.h"
29 #include "citylist.h"
30 #include "city.h"
31 #include "action.h"
32 #include "ImageCache.h"
33 #include "armysetlist.h"
34 #include "shield.h"
35 #include "armyprodbase.h"
36 #include "font-size.h"
37
38 #define method(x) sigc::mem_fun(*this, &ReportDialog::x)
39
ReportDialog(Gtk::Window & parent,Player * player,ReportType type)40 ReportDialog::ReportDialog(Gtk::Window &parent, Player *player, ReportType type)
41 : LwDialog(parent, "report-dialog.ui")
42 {
43 d_player = player;
44 xml->get_widget("map_image", map_image);
45 citymap = new CityMap();
46 citymap->map_changed.connect (method(on_city_map_changed));
47 armymap = new ArmyMap();
48 armymap->map_changed.connect (method(on_army_map_changed));
49 City *c = d_player->getFirstCity();
50 vectormap = new VectorMap(c, VectorMap::SHOW_ALL_VECTORING, false);
51 vectormap->map_changed.connect (method(on_vector_map_changed));
52
53 xml->get_widget("army_label", army_label);
54 xml->get_widget("city_label", city_label);
55 xml->get_widget("gold_label", gold_label);
56 xml->get_widget("production_label", production_label);
57 xml->get_widget("winning_label", winning_label);
58
59
60 xml->get_widget("report_notebook", report_notebook);
61 report_notebook->set_current_page(type);
62 switch_conn = report_notebook->signal_switch_page().connect
63 (sigc::hide<0>(method(on_switch_page)));
64
65 armies_list = Gtk::ListStore::create(armies_columns);
66 xml->get_widget("treeview", armies_treeview);
67 armies_treeview->set_model(armies_list);
68 armies_treeview->append_column("", armies_columns.image);
69 armies_treeview->append_column("", armies_columns.desc);
70
71 //loop through the action list looking for production actions
72 std::list<Action*> actions = player->getReportableActions();
73 guint32 total = 0;
74 std::list<Action*>::const_iterator it;
75 for (it = actions.begin(); it != actions.end(); it++)
76 {
77 if ((*it)->getType() == Action::PRODUCE_UNIT ||
78 (*it)->getType() == Action::PRODUCE_VECTORED_UNIT)
79 total++;
80 addProduction(*it);
81 }
82 armies_treeview->get_selection()->signal_changed().connect
83 (method(on_army_selected));
84
85 Glib::ustring s;
86 s = String::ucompose(ngettext("You produced %1 army this turn!",
87 "You produced %1 armies this turn!",
88 total), total);
89 production_label->set_text(s);
90
91 xml->get_widget("army_alignment", army_alignment);
92 xml->get_widget("city_alignment", city_alignment);
93 xml->get_widget("gold_alignment", gold_alignment);
94 xml->get_widget("winning_alignment", winning_alignment);
95 updateArmyChart();
96 updateGoldChart();
97 updateCityChart();
98 updateWinningChart();
99 fill_in_info();
100 }
101
~ReportDialog()102 ReportDialog::~ReportDialog()
103 {
104 switch_conn.disconnect();
105 delete vectormap;
106 delete armymap;
107 delete citymap;
108 report_notebook->property_show_tabs () = false;
109 }
110
run()111 void ReportDialog::run()
112 {
113 citymap->resize();
114 citymap->draw();
115 vectormap->resize();
116 vectormap->draw();
117 armymap->resize();
118 armymap->draw();
119
120 dialog->show_all();
121 dialog->run();
122 }
123
on_army_map_changed(Cairo::RefPtr<Cairo::Surface> map)124 void ReportDialog::on_army_map_changed(Cairo::RefPtr<Cairo::Surface> map)
125 {
126 if (report_notebook->get_current_page() == ARMY)
127 {
128 Glib::RefPtr<Gdk::Pixbuf> pixbuf =
129 Gdk::Pixbuf::create(map, 0, 0,
130 armymap->get_width(), armymap->get_height());
131 map_image->property_pixbuf() = pixbuf;
132 }
133 }
134
on_city_map_changed(Cairo::RefPtr<Cairo::Surface> map)135 void ReportDialog::on_city_map_changed(Cairo::RefPtr<Cairo::Surface> map)
136 {
137 if (report_notebook->get_current_page() == CITY ||
138 report_notebook->get_current_page() == GOLD ||
139 report_notebook->get_current_page() == WINNING)
140 {
141 Glib::RefPtr<Gdk::Pixbuf> pixbuf =
142 Gdk::Pixbuf::create(map, 0, 0,
143 citymap->get_width(), citymap->get_height());
144 map_image->property_pixbuf() = pixbuf;
145 }
146 }
147
on_vector_map_changed(Cairo::RefPtr<Cairo::Surface> map)148 void ReportDialog::on_vector_map_changed(Cairo::RefPtr<Cairo::Surface> map)
149 {
150 if (report_notebook->get_current_page() == PRODUCTION)
151 {
152 Glib::RefPtr<Gdk::Pixbuf> pixbuf =
153 Gdk::Pixbuf::create(map, 0, 0,
154 vectormap->get_width(), vectormap->get_height());
155 map_image->property_pixbuf() = pixbuf;
156 }
157 }
158
on_switch_page(guint number)159 void ReportDialog::on_switch_page(guint number)
160 {
161 switch (number)
162 {
163 case ARMY:
164 map_image->property_pixbuf() =
165 Gdk::Pixbuf::create(armymap->get_surface(), 0, 0,
166 armymap->get_width(), citymap->get_height());
167 break;
168 case CITY:
169 case GOLD:
170 case WINNING:
171 map_image->property_pixbuf() =
172 Gdk::Pixbuf::create(citymap->get_surface(), 0, 0,
173 citymap->get_width(), citymap->get_height());
174 break;
175 case PRODUCTION:
176 map_image->property_pixbuf() =
177 Gdk::Pixbuf::create(vectormap->get_surface(), 0, 0,
178 vectormap->get_width(), vectormap->get_height());
179 break;
180 }
181 fill_in_info();
182 }
183
fill_in_info()184 void ReportDialog::fill_in_info()
185 {
186 switch (report_notebook->get_current_page())
187 {
188 case ARMY:
189 dialog->set_title(_("Army Report"));
190 break;
191 case CITY:
192 dialog->set_title(_("City Report"));
193 break;
194 case GOLD:
195 dialog->set_title(_("Gold Report"));
196 break;
197 case PRODUCTION:
198 dialog->set_title(_("Production Report"));
199 break;
200 case WINNING:
201 dialog->set_title(_("Winning Report"));
202 break;
203 }
204 }
205
updateArmyChart()206 void ReportDialog::updateArmyChart()
207 {
208 std::list<guint32> bars;
209 std::list<Gdk::RGBA> colours;
210 Gdk::RGBA colour;
211 Glib::ustring s;
212 guint32 total;
213 for (unsigned int i = 0; i < MAX_PLAYERS; i++)
214 {
215 Player *p = Playerlist::getInstance()->getPlayer(i);
216 if (p == NULL)
217 continue;
218 if (p == Playerlist::getInstance()->getNeutral())
219 continue;
220 total = 0;
221 total = p->countArmies();
222 bars.push_back(total);
223 colour = p->getColor();
224 colours.push_back(colour);
225 if (p == d_player)
226 army_label->set_text
227 (String::ucompose(ngettext("You have %1 army!", "You have %1 armies!",
228 total), total));
229 }
230
231 army_chart = new BarChart(bars, colours, 0);
232 army_alignment->add(*manage(army_chart));
233 }
234
updateCityChart()235 void ReportDialog::updateCityChart()
236 {
237 std::list<guint32> bars;
238 std::list<Gdk::RGBA> colours;
239 Gdk::RGBA colour;
240 Glib::ustring s;
241 guint32 total;
242 for (unsigned int i = 0; i < MAX_PLAYERS; i++)
243 {
244 Player *p = Playerlist::getInstance()->getPlayer(i);
245 if (p == NULL)
246 continue;
247 if (p == Playerlist::getInstance()->getNeutral())
248 continue;
249 total = Citylist::getInstance()->countCities(p);
250
251 bars.push_back(total);
252 colour = p->getColor();
253 colours.push_back(colour);
254 if (p == d_player)
255 city_label->set_text
256 (String::ucompose(ngettext("You have %1 city!", "You have %1 cities!",
257 total), total));
258
259 }
260 city_chart = new BarChart(bars, colours, Citylist::getInstance()->size());
261 city_alignment->add(*manage(city_chart));
262 }
263
updateGoldChart()264 void ReportDialog::updateGoldChart()
265 {
266 std::list<guint32> bars;
267 std::list<Gdk::RGBA> colours;
268 Gdk::RGBA colour;
269 Glib::ustring s;
270 guint32 total;
271 bars.clear();
272 for (unsigned int i = 0; i < MAX_PLAYERS; i++)
273 {
274 Player *p = Playerlist::getInstance()->getPlayer(i);
275 if (p == NULL)
276 continue;
277 if (p == Playerlist::getInstance()->getNeutral())
278 continue;
279 total = p->getGold();
280 bars.push_back(total);
281 colour = p->getColor();
282 colours.push_back(colour);
283 if (p == d_player)
284 gold_label->set_text
285 (String::ucompose(ngettext("You have %1 gold piece!",
286 "You have %1 gold pieces!", total), total));
287 }
288 gold_chart = new BarChart(bars, colours, 0);
289 gold_alignment->add(*manage(gold_chart));
290 }
291
get_rank_string(int rank)292 Glib::ustring ReportDialog::get_rank_string(int rank)
293 {
294 if (rank == 0)
295 return _("first");
296 else if (rank == 1)
297 return _("second");
298 else if (rank == 2)
299 return _("third");
300 else if (rank == 3)
301 return _("fourth");
302 else if (rank == 4)
303 return _("fifth");
304 else if (rank == 5)
305 return _("sixth");
306 else if (rank == 6)
307 return _("seventh");
308 else if (rank == 7)
309 return _("eighth");
310 else
311 return _("unknown");
312 }
313
calculateRank(std::list<guint32> scores,guint32 score)314 Glib::ustring ReportDialog::calculateRank(std::list<guint32> scores, guint32 score)
315 {
316 guint32 rank = 0;
317 std::list<guint32>::iterator it = scores.begin();
318 for (; it != scores.end(); it++)
319 {
320 if (score < *it)
321 rank++;
322 }
323 Glib::ustring s = String::ucompose("%1", get_rank_string(rank));
324 return s;
325 }
326
updateWinningChart()327 void ReportDialog::updateWinningChart()
328 {
329 std::list<guint32> bars;
330 std::list<Gdk::RGBA> colours;
331 Gdk::RGBA colour;
332 Glib::ustring s;
333 guint32 score;
334 for (unsigned int i = 0; i < MAX_PLAYERS; i++)
335 {
336 Player *p = Playerlist::getInstance()->getPlayer(i);
337 if (p == NULL)
338 continue;
339 if (p == Playerlist::getInstance()->getNeutral())
340 continue;
341 score = p->getScore();
342 bars.push_back(score);
343 colour = p->getColor();
344 colours.push_back(colour);
345 }
346 s = String::ucompose(_("You are coming %1"), calculateRank(bars, d_player->getScore()));
347 winning_label->set_text(s);
348 winning_chart = new BarChart(bars, colours, 100);
349 winning_alignment->add(*manage(winning_chart));
350 }
351
addProduction(const Action * action)352 void ReportDialog::addProduction(const Action *action)
353 {
354 ImageCache *gc = ImageCache::getInstance();
355 Player *p = d_player;
356
357 int army_type = 0;
358 guint32 city_id = 0;
359
360 Glib::ustring s = "";
361 if (action->getType() == Action::PRODUCE_UNIT)
362 {
363 const Action_Produce *act;
364 act = dynamic_cast<const Action_Produce*>(action);
365 army_type = act->getArmy()->getTypeId();
366 Citylist::iterator cit = Citylist::getInstance()->begin();
367 for (; cit != Citylist::getInstance()->end(); ++cit)
368 if ((*cit)->getId() == act->getCityId())
369 {
370 s += (*cit)->getName();
371 break;
372 }
373 if (act->getVectored())
374 s += "...";
375 city_id = act->getCityId();
376 }
377 else if (action->getType() == Action::PRODUCE_VECTORED_UNIT)
378 {
379 const Action_ProduceVectored *act =
380 dynamic_cast<const Action_ProduceVectored*>(action);
381 army_type = act->getArmy()->getTypeId();
382 Vector<int> pos = act->getDestination();
383 City *c = GameMap::getCity(pos);
384 s+="...";
385 if (c)
386 s += c->getName();
387 else
388 s += _("Standard");
389 city_id = GameMap::getCity(act->getOrigination())->getId();
390 }
391 else if (action->getType() == Action::CITY_DESTITUTE)
392 {
393 const Action_CityTooPoorToProduce *act;
394 act = dynamic_cast<const Action_CityTooPoorToProduce*>(action);
395 army_type = act->getArmyType();
396 City *c = Citylist::getInstance()->getById(act->getCityId());
397 s = String::ucompose(_("%1 stops production!"), c->getName());
398 city_id = act->getCityId();
399 }
400 Gtk::TreeIter i = armies_list->append();
401 (*i)[armies_columns.city_id] = city_id;
402 (*i)[armies_columns.image] =
403 gc->getCircledArmyPic(p->getArmyset(), army_type, p, NULL, false,
404 Shield::NEUTRAL, true,
405 FontSize::getInstance ()->get_height ())->to_pixbuf();
406 (*i)[armies_columns.desc] = s;
407 }
408
on_army_selected()409 void ReportDialog::on_army_selected()
410 {
411 Gtk::TreeIter i = armies_treeview->get_selection()->get_selected();
412 if (i)
413 {
414 City *c =
415 Citylist::getInstance()->getById((*i)[armies_columns.city_id]);
416 if (c)
417 vectormap->setCity(c);
418 }
419 }
420