initial commit, lordsawar source, slightly modified
[lordsawar] / src / gui / report-dialog.cpp
1 //  Copyright (C) 2007, 2008, 2009 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
25 #include "glade-helpers.h"
26 #include "image-helpers.h"
27 #include "input-helpers.h"
28 #include "bar-chart.h"
29 #include "ucompose.hpp"
30 #include "defs.h"
31 #include "File.h"
32 #include "GameMap.h"
33 #include "playerlist.h"
34 #include "citylist.h"
35 #include "city.h"
36 #include "action.h"
37 #include "GraphicsCache.h"
38 #include "armyprodbase.h"
39 #include "armysetlist.h"
40
41 ReportDialog::ReportDialog(Player *player, ReportType type)
42 {
43   d_player = player;
44   Glib::RefPtr<Gtk::Builder> xml
45     = Gtk::Builder::create_from_file(get_glade_path() + "/report-dialog.ui");
46
47   xml->get_widget("dialog", dialog);
48   decorate(dialog);
49   window_closed.connect(sigc::mem_fun(dialog, &Gtk::Dialog::hide));
50
51   xml->get_widget("map_image", map_image);
52   citymap = new CityMap();
53   citymap->map_changed.connect
54     (sigc::mem_fun(this, &ReportDialog::on_city_map_changed));
55   armymap = new ArmyMap();
56   armymap->map_changed.connect
57     (sigc::mem_fun(this, &ReportDialog::on_army_map_changed));
58   City *c = Citylist::getInstance()->getFirstCity(d_player);
59   vectormap = new VectorMap(c, VectorMap::SHOW_ALL_VECTORING, false);
60   vectormap->map_changed.connect
61     (sigc::mem_fun(this, &ReportDialog::on_vector_map_changed));
62
63   xml->get_widget("army_label", army_label);
64   xml->get_widget("city_label", city_label);
65   xml->get_widget("gold_label", gold_label);
66   xml->get_widget("production_label", production_label);
67   xml->get_widget("winning_label", winning_label);
68
69
70   xml->get_widget("report_notebook", report_notebook);
71   report_notebook->set_current_page(type);
72   report_notebook->signal_switch_page().connect(
73         sigc::mem_fun(*this, &ReportDialog::on_switch_page));
74
75   armies_list = Gtk::ListStore::create(armies_columns);
76   xml->get_widget("treeview", armies_treeview);
77   armies_treeview->set_model(armies_list);
78   armies_treeview->append_column("", armies_columns.image);
79   armies_treeview->append_column("", armies_columns.desc);
80
81   //loop through the action list looking for production actions
82   std::list<Action*> actions = player->getReportableActions();
83   guint32 total = 0;
84   std::list<Action*>::const_iterator it;
85   for (it = actions.begin(); it != actions.end(); it++)
86     {
87       if ((*it)->getType() == Action::PRODUCE_UNIT ||
88           (*it)->getType() == Action::PRODUCE_VECTORED_UNIT)
89         total++;
90     addProduction(*it);
91     }
92     armies_treeview->get_selection()->signal_changed().connect
93       (sigc::mem_fun(*this, &ReportDialog::on_army_selected));
94
95   Glib::ustring s;
96   s = String::ucompose(ngettext("You produced %1 army this turn!",
97                                 "You produced %1 armies this turn!",
98                                 total), total);
99   production_label->set_text(s);
100
101   Gtk::Button *close_button;
102   xml->get_widget("close_button", close_button);
103   close_button->signal_clicked().connect
104     (sigc::mem_fun(*this, &ReportDialog::on_close_button));
105   xml->get_widget("army_alignment", army_alignment);
106   xml->get_widget("city_alignment", city_alignment);
107   xml->get_widget("gold_alignment", gold_alignment);
108   xml->get_widget("winning_alignment", winning_alignment);
109   updateArmyChart();
110   updateGoldChart();
111   updateCityChart();
112   updateWinningChart();
113   fill_in_info();
114   closing = false;
115 }
116
117 ReportDialog::~ReportDialog()
118 {
119     delete dialog;
120     delete vectormap;
121     delete armymap;
122     delete citymap;
123 }
124 void ReportDialog::on_close_button()
125 {
126   closing = true;
127   //FIXME: find out why the page_switch events with crap data,
128   //and then remove this function, and the closing variable too.
129 }
130
131 void ReportDialog::set_parent_window(Gtk::Window &parent)
132 {
133   dialog->set_transient_for(parent);
134   //dialog->set_position(Gtk::WIN_POS_CENTER_ON_PARENT);
135 }
136
137 void ReportDialog::hide()
138 {
139   dialog->hide();
140 }
141
142 void ReportDialog::run()
143 {
144   citymap->resize();
145   citymap->draw(Playerlist::getActiveplayer());
146   vectormap->resize();
147   vectormap->draw(Playerlist::getActiveplayer());
148   armymap->resize();
149   armymap->draw(Playerlist::getActiveplayer());
150
151   dialog->show_all();
152   dialog->run();
153 }
154
155 void ReportDialog::on_army_map_changed(Glib::RefPtr<Gdk::Pixmap> map)
156 {
157   if (report_notebook->get_current_page() == ARMY)
158     map_image->property_pixmap() = map;
159 }
160
161 void ReportDialog::on_city_map_changed(Glib::RefPtr<Gdk::Pixmap> map)
162 {
163   if (report_notebook->get_current_page() == CITY ||
164       report_notebook->get_current_page() == GOLD ||
165       report_notebook->get_current_page() == WINNING)
166     map_image->property_pixmap() = map;
167 }
168
169 void ReportDialog::on_vector_map_changed(Glib::RefPtr<Gdk::Pixmap> map)
170 {
171   if (report_notebook->get_current_page() == PRODUCTION)
172     map_image->property_pixmap() = map;
173 }
174
175 void ReportDialog::on_switch_page(GtkNotebookPage *page, guint number)
176 {
177   if (closing)
178     return;
179   switch (number)
180     {
181     case ARMY:
182       map_image->property_pixmap() = armymap->get_surface();
183       break;
184     case CITY: 
185     case GOLD: 
186     case WINNING:
187       map_image->property_pixmap() = citymap->get_surface();
188       break;
189     case PRODUCTION:
190       map_image->property_pixmap() = vectormap->get_surface();
191       break;
192     }
193   fill_in_info();
194 }
195
196 void ReportDialog::fill_in_info()
197 {
198   switch (report_notebook->get_current_page())
199     {
200     case ARMY:
201       set_title(_("Army Report"));
202       break;
203     case CITY: 
204       set_title(_("City Report"));
205       break;
206     case GOLD: 
207       set_title(_("Gold Report"));
208       break;
209     case PRODUCTION:
210       set_title(_("Production Report"));
211       break;
212     case WINNING:
213       set_title(_("Winning Report"));
214       break;
215     }
216 }
217
218 void ReportDialog::updateArmyChart()
219 {
220   std::list<guint32> bars;
221   std::list<Gdk::Color> colours;
222   Gdk::Color colour;
223   Glib::ustring s;
224   guint32 total;
225   for (unsigned int i = 0; i < MAX_PLAYERS; i++)
226     {
227       Player *p = Playerlist::getInstance()->getPlayer(i);
228       if (p == NULL)
229         continue;
230       if (p == Playerlist::getInstance()->getNeutral())
231         continue;
232       total = 0;
233       total = p->countArmies();
234       bars.push_back(total);
235       colour = p->getColor();
236       colours.push_back(colour);
237       if (p == d_player)
238         {
239           s = String::ucompose(ngettext("You have %1 army!",
240                                         "You have %1 armies!",
241                                         total), total);
242           army_label->set_text(s);
243         }
244     }
245
246   army_chart = new BarChart(bars, colours, 0);
247   army_alignment->add(*manage(army_chart));
248 }
249
250 void ReportDialog::updateCityChart()
251 {
252   std::list<guint32> bars;
253   std::list<Gdk::Color> colours;
254   Gdk::Color colour;
255   Glib::ustring s;
256   guint32 total;
257   for (unsigned int i = 0; i < MAX_PLAYERS; i++)
258     {
259       Player *p = Playerlist::getInstance()->getPlayer(i);
260       if (p == NULL)
261         continue;
262       if (p == Playerlist::getInstance()->getNeutral())
263         continue;
264       total = Citylist::getInstance()->countCities(p);
265
266       bars.push_back(total);
267       colour = p->getColor();
268       colours.push_back(colour);
269       if (p == d_player)
270         {
271           s = String::ucompose(ngettext("You have %1 city!",
272                                         "You have %1 cities!",
273                                         total), total);
274           city_label->set_text(s);
275         }
276
277     }
278   city_chart = new BarChart(bars, colours, Citylist::getInstance()->size());
279   city_alignment->add(*manage(city_chart));
280 }
281
282 void ReportDialog::updateGoldChart()
283 {
284   std::list<guint32> bars;
285   std::list<Gdk::Color> colours;
286   Gdk::Color colour;
287   Glib::ustring s;
288   guint32 total;
289   bars.clear();
290   for (unsigned int i = 0; i < MAX_PLAYERS; i++)
291     {
292       Player *p = Playerlist::getInstance()->getPlayer(i);
293       if (p == NULL)
294         continue;
295       if (p == Playerlist::getInstance()->getNeutral())
296         continue;
297       total = p->getGold();
298       bars.push_back(total);
299       colour = p->getColor();
300       colours.push_back(colour);
301       if (p == d_player)
302         {
303           s = String::ucompose(ngettext("You have %1 gold piece!",
304                                         "You have %1 gold pieces!",
305                                         total), total);
306           gold_label->set_text(s);
307         }
308     }
309   gold_chart = new BarChart(bars, colours, 0);
310   gold_alignment->add(*manage(gold_chart));
311 }
312
313 std::string ReportDialog::calculateRank(std::list<guint32> scores, guint32 score)
314 {
315   char* rank_strings[MAX_PLAYERS] =
316     {
317       _("first"), _("second"), _("third"), _("fourth"), _("fifth"),
318       _("sixth"), _("seventh"), _("eighth"),
319     };
320   guint32 rank = 0;
321   std::list<guint32>::iterator it = scores.begin();
322   for (; it != scores.end(); it++)
323     {
324       if (score < *it)
325         rank++;
326     }
327   Glib::ustring s = String::ucompose(_("%1"), rank_strings[rank]);
328   return s;
329 }
330
331 void ReportDialog::updateWinningChart()
332 {
333   std::list<guint32> bars;
334   std::list<Gdk::Color> colours;
335   Gdk::Color colour;
336   Glib::ustring s;
337   guint32 score;
338   for (unsigned int i = 0; i < MAX_PLAYERS; i++)
339     {
340       Player *p = Playerlist::getInstance()->getPlayer(i);
341       if (p == NULL)
342         continue;
343       if (p == Playerlist::getInstance()->getNeutral())
344         continue;
345       score = p->getScore();
346       bars.push_back(score);
347       colour = p->getColor();
348       colours.push_back(colour);
349     }
350   s = String::ucompose(_("You are coming %1"), calculateRank(bars, d_player->getScore()));
351   winning_label->set_text(s);
352   winning_chart = new BarChart(bars, colours, 100);
353   winning_alignment->add(*manage(winning_chart));
354 }
355
356 void ReportDialog::addProduction(const Action *action)
357 {
358   GraphicsCache *gc = GraphicsCache::getInstance();
359   Player *p = d_player;
360
361   int army_type = 0;
362   guint32 city_id = 0;
363
364   Glib::ustring s = "";
365   if (action->getType() == Action::PRODUCE_UNIT)
366     {
367       const Action_Produce *act;
368       act = dynamic_cast<const Action_Produce*>(action);
369       army_type = act->getArmy()->getTypeId();
370       Citylist::iterator cit = Citylist::getInstance()->begin();
371       for (; cit != Citylist::getInstance()->end(); ++cit)
372         if ((*cit)->getId() == act->getCityId())
373           {
374             s += (*cit)->getName();
375             break;
376           }
377       if (act->getVectored())
378         s += "...";
379       city_id = act->getCityId();
380     }
381   else if (action->getType() == Action::PRODUCE_VECTORED_UNIT)
382     {
383       const Action_ProduceVectored *act;
384       act = dynamic_cast<const Action_ProduceVectored*>(action);
385       army_type = act->getArmy()->getTypeId();
386       Vector<int> pos = act->getDestination();
387       City *c = GameMap::getCity(pos);
388       s+="...";
389       if (c)
390         s += c->getName();
391       else
392         s += _("Standard");
393       city_id = GameMap::getCity(act->getOrigination())->getId();
394     }
395   else if (action->getType() == Action::CITY_DESTITUTE)
396     {
397       const Action_CityTooPoorToProduce *act;
398       act = dynamic_cast<const Action_CityTooPoorToProduce*>(action);
399       army_type = act->getArmyType();
400       City *c = Citylist::getInstance()->getById(act->getCityId());
401       s = c->getName();
402       s += " stops production!";
403       city_id = act->getCityId();
404     }
405   const ArmyProto *a;
406   a = Armysetlist::getInstance()->getArmy(p->getArmyset(), army_type);
407   Gtk::TreeIter i = armies_list->append();
408   (*i)[armies_columns.city_id] = city_id;
409   (*i)[armies_columns.image] = gc->getArmyPic(p->getArmyset(), army_type, p, 
410                                               NULL)->to_pixbuf();
411   (*i)[armies_columns.desc] = s;
412 }
413
414 void ReportDialog::on_army_selected()
415 {
416     Gtk::TreeIter i = armies_treeview->get_selection()->get_selected();
417     if (i)
418     {
419         City *c = 
420           Citylist::getInstance()->getById((*i)[armies_columns.city_id]);
421         if (c)
422           vectormap->setCity(c);
423     }
424
425 }