initial commit, lordsawar source, slightly modified
[lordsawar] / src / editor / city-editor-dialog.cpp
1 //  Copyright (C) 2007 Ole Laursen
2 //  Copyright (C) 2007, 2008, 2009 Ben Asselstine
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 Library 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, write to the Free Software
16 //  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 
17 //  02110-1301, USA.
18
19 #include <config.h>
20
21 #include <sigc++/functors/mem_fun.h>
22 #include <gtkmm.h>
23
24 #include "city-editor-dialog.h"
25
26 #include "glade-helpers.h"
27 #include "ucompose.hpp"
28 #include "defs.h"
29 #include "city.h"
30 #include "armyprodbase.h"
31 #include "army.h"
32 #include "armyproto.h"
33 #include "armyprodbase.h"
34 #include "playerlist.h"
35 #include "stacklist.h"
36 #include "citylist.h"
37 #include "CreateScenarioRandomize.h"
38 #include "GraphicsCache.h"
39 #include "GameMap.h"
40
41 #include "select-army-dialog.h"
42
43
44 CityEditorDialog::CityEditorDialog(City *cit, CreateScenarioRandomize *randomizer)
45         : strength_column(_("Strength"), strength_renderer),
46         moves_column(_("Max Moves"), moves_renderer),
47         duration_column(_("Turns"), duration_renderer),
48         upkeep_column(_("Upkeep"), upkeep_renderer)
49 {
50     city = cit;
51     d_randomizer = randomizer;
52     
53     Glib::RefPtr<Gtk::Builder> xml
54         = Gtk::Builder::create_from_file(get_glade_path()
55                                     + "/city-editor-dialog.ui");
56
57     xml->get_widget("dialog", dialog);
58
59     xml->get_widget("capital_checkbutton", capital_checkbutton);
60     capital_checkbutton->set_active(city->isCapital());
61
62     xml->get_widget("name_entry", name_entry);
63     name_entry->set_text(city->getName());
64     
65     xml->get_widget("income_spinbutton", income_spinbutton);
66     income_spinbutton->set_value(city->getGold());
67
68     xml->get_widget("burned_checkbutton", burned_checkbutton);
69     burned_checkbutton->set_active(city->isBurnt());
70     
71     // setup the player combo
72     player_combobox = manage(new Gtk::ComboBoxText);
73
74
75     int c = 0, player_no = 0;
76     for (Playerlist::iterator i = Playerlist::getInstance()->begin(),
77              end = Playerlist::getInstance()->end(); i != end; ++i, ++c)
78     {
79         Player *player = *i;
80         player_combobox->append_text(player->getName());
81         if (player == city->getOwner())
82             player_no = c;
83     }
84
85     player_combobox->set_active(player_no);
86     player_combobox->signal_changed().connect
87       (sigc::mem_fun(this, &CityEditorDialog::on_player_changed));
88     Gtk::Alignment *alignment;
89     xml->get_widget("player_alignment", alignment);
90     alignment->add(*player_combobox);
91     
92     
93     // setup the army list
94     army_list = Gtk::ListStore::create(army_columns);
95
96     xml->get_widget("army_treeview", army_treeview);
97     army_treeview->set_model(army_list);
98     
99     army_treeview->append_column("", army_columns.image);
100     strength_renderer.property_editable() = true;
101     strength_renderer.signal_edited()
102       .connect(sigc::mem_fun(*this, &CityEditorDialog::on_strength_edited));
103     strength_column.set_cell_data_func
104               ( strength_renderer, 
105                 sigc::mem_fun(*this, &CityEditorDialog::cell_data_strength));
106     army_treeview->append_column(strength_column);
107
108     moves_renderer.property_editable() = true;
109     moves_renderer.signal_edited()
110       .connect(sigc::mem_fun(*this, &CityEditorDialog::on_moves_edited));
111     moves_column.set_cell_data_func
112               ( moves_renderer, 
113                 sigc::mem_fun(*this, &CityEditorDialog::cell_data_moves));
114     army_treeview->append_column(moves_column);
115
116     upkeep_renderer.property_editable() = true;
117     upkeep_renderer.signal_edited()
118       .connect(sigc::mem_fun(*this, &CityEditorDialog::on_upkeep_edited));
119     upkeep_column.set_cell_data_func
120               ( upkeep_renderer, 
121                 sigc::mem_fun(*this, &CityEditorDialog::cell_data_upkeep));
122     army_treeview->append_column(upkeep_column);
123
124     duration_renderer.property_editable() = true;
125     duration_renderer.signal_edited()
126       .connect(sigc::mem_fun(*this, &CityEditorDialog::on_turns_edited));
127     duration_column.set_cell_data_func
128               ( duration_renderer, 
129                 sigc::mem_fun(*this, &CityEditorDialog::cell_data_turns));
130     army_treeview->append_column(strength_column);
131
132     army_treeview->append_column(_("Name"), army_columns.name);
133
134     xml->get_widget("add_button", add_button);
135     xml->get_widget("remove_button", remove_button);
136     xml->get_widget("randomize_armies_button", randomize_armies_button);
137     xml->get_widget("randomize_name_button", randomize_name_button);
138     xml->get_widget("randomize_income_button", randomize_income_button);
139
140     add_button->signal_clicked().connect(
141         sigc::mem_fun(this, &CityEditorDialog::on_add_clicked));
142     remove_button->signal_clicked().connect(
143         sigc::mem_fun(this, &CityEditorDialog::on_remove_clicked));
144     randomize_armies_button->signal_clicked().connect(
145         sigc::mem_fun(this, &CityEditorDialog::on_randomize_armies_clicked));
146     randomize_name_button->signal_clicked().connect(
147         sigc::mem_fun(this, &CityEditorDialog::on_randomize_name_clicked));
148     randomize_income_button->signal_clicked().connect(
149         sigc::mem_fun(this, &CityEditorDialog::on_randomize_income_clicked));
150
151     army_treeview->get_selection()->signal_changed()
152         .connect(sigc::mem_fun(this, &CityEditorDialog::on_selection_changed));
153
154     for (unsigned int i = 0; i < city->getMaxNoOfProductionBases(); i++)
155     {
156         const ArmyProdBase* a = city->getProductionBase(i);
157         if (a)
158             add_army(a);
159     }
160 }
161 CityEditorDialog::~CityEditorDialog()
162 {
163   delete dialog;
164 }
165
166 void CityEditorDialog::set_parent_window(Gtk::Window &parent)
167 {
168     dialog->set_transient_for(parent);
169     //dialog->set_position(Gtk::WIN_POS_CENTER_ON_PARENT);
170 }
171
172 void CityEditorDialog::change_city_ownership()
173 {
174   // set allegiance
175   Player *player = get_selected_player();
176   if (player == city->getOwner()) //no change? do nothing.
177     return;
178   city->setOwner(player);
179   //look for stacks in the city, and set them to this player
180   for (unsigned int x = 0; x < city->getSize(); x++)
181     {
182       for (unsigned int y = 0; y < city->getSize(); y++)
183         {
184           Stack *s = GameMap::getStack(city->getPos() + Vector<int>(x,y));
185           if (s)
186             Stacklist::changeOwnership(s, player);
187         }
188     }
189 }
190
191 int CityEditorDialog::run()
192 {
193   dialog->show_all();
194   int response = dialog->run();
195
196   if (response == Gtk::RESPONSE_ACCEPT) // accepted
197     {
198       unsigned int c = 0;
199       // set attributes
200       bool capital = capital_checkbutton->get_active();
201       if (capital)
202         {
203           // make sure player doesn't have other capitals
204           Citylist* cl = Citylist::getInstance();
205           for (Citylist::iterator i = cl->begin(); i != cl->end(); ++i)
206             if ((*i)->isCapital() && (*i)->getOwner() == city->getOwner())
207               {
208                 (*i)->setCapital(false);
209                 (*i)->setCapitalOwner(NULL);
210               }
211           city->setCapital(true);
212           city->setCapitalOwner(city->getOwner());
213         }
214       else
215         {
216           city->setCapital(false);
217           city->setCapitalOwner(NULL);
218         }
219
220       city->setName(name_entry->get_text());
221       city->setGold(income_spinbutton->get_value_as_int());
222       city->setBurnt(burned_checkbutton->get_active());
223
224       // set production slots
225       c = 0;
226       for (Gtk::TreeIter i = army_list->children().begin(),
227            end = army_list->children().end(); i != end; ++i, ++c)
228         {
229           const ArmyProdBase *a = (*i)[army_columns.army];
230           ArmyProdBase *army = new ArmyProdBase(*a);
231           army->setStrength((*i)[army_columns.strength]);
232           army->setProduction((*i)[army_columns.duration]);
233           city->addProductionBase(c, army);
234
235           // FIXME: use (*i)[army_columns.duration] to set special city
236           // production ability
237         }
238       for (; c < city->getMaxNoOfProductionBases(); ++c)
239         city->removeProductionBase(c);
240       //set owner of the city
241       change_city_ownership();
242     }
243   else
244     {
245       if (name_entry->get_text() != City::getDefaultName())
246         d_randomizer->pushRandomCityName(name_entry->get_text());
247     }
248   return response;
249 }
250
251 void CityEditorDialog::on_add_clicked()
252 {
253   SelectArmyDialog d(city->getOwner());
254   d.set_parent_window(*dialog);
255   d.run();
256
257   const ArmyProto *army = d.get_selected_army();
258   if (army)
259     add_army(new ArmyProdBase(*army));
260 }
261
262
263 void CityEditorDialog::on_remove_clicked()
264 {
265   Gtk::TreeIter i = army_treeview->get_selection()->get_selected();
266   if (i)
267     {
268       army_list->erase(i);
269     }
270
271   set_button_sensitivity();
272 }
273
274 void CityEditorDialog::on_randomize_armies_clicked()
275 {
276   const ArmyProdBase *army;
277   army_list->clear();
278   city->setRandomArmytypes(true, 1);
279   for (unsigned int i = 0; i < city->getMaxNoOfProductionBases(); i++)
280     {
281       army = city->getProductionBase(i);
282       if (army)
283         add_army(army);
284     }
285   set_button_sensitivity();
286 }
287
288 void CityEditorDialog::on_randomize_name_clicked()
289 {
290   std::string existing_name = name_entry->get_text();
291   if (existing_name == City::getDefaultName())
292     name_entry->set_text(d_randomizer->popRandomCityName());
293   else
294     {
295       name_entry->set_text(d_randomizer->popRandomCityName());
296       d_randomizer->pushRandomCityName(existing_name);
297     }
298 }
299
300 void CityEditorDialog::on_randomize_income_clicked()
301 {
302   int gold;
303   gold = d_randomizer->getRandomCityIncome(capital_checkbutton->get_active());
304   income_spinbutton->set_value(gold);
305 }
306
307 void CityEditorDialog::add_army(const ArmyProdBase *a)
308 {
309   Player *player = get_selected_player();
310   GraphicsCache *gc = GraphicsCache::getInstance();
311   Gtk::TreeIter i = army_list->append();
312   (*i)[army_columns.army] = a;
313   (*i)[army_columns.image] = gc->getArmyPic(player->getArmyset(),
314                                             a->getTypeId(), player,
315                                             NULL)->to_pixbuf();
316   (*i)[army_columns.strength] = a->getStrength();
317   (*i)[army_columns.moves] = a->getMaxMoves();
318   (*i)[army_columns.upkeep] = a->getUpkeep();
319   (*i)[army_columns.duration] = a->getProduction();
320   (*i)[army_columns.name] = a->getName();
321   army_treeview->get_selection()->select(i);
322
323   set_button_sensitivity();
324 }
325
326 void CityEditorDialog::on_selection_changed()
327 {
328   set_button_sensitivity();
329 }
330
331 void CityEditorDialog::set_button_sensitivity()
332 {
333   Gtk::TreeIter i = army_treeview->get_selection()->get_selected();
334   unsigned int armies = army_list->children().size();
335   add_button->set_sensitive(armies < city->getMaxNoOfProductionBases());
336   remove_button->set_sensitive(i);
337 }
338
339 void CityEditorDialog::cell_data_strength(Gtk::CellRenderer *renderer,
340                                      const Gtk::TreeIter& i)
341 {
342     dynamic_cast<Gtk::CellRendererSpin*>(renderer)->property_adjustment()
343           = new Gtk::Adjustment((*i)[army_columns.strength], 
344                                 MIN_STRENGTH_FOR_ARMY_UNITS, 
345                                 MAX_STRENGTH_FOR_ARMY_UNITS, 1);
346     dynamic_cast<Gtk::CellRendererSpin*>(renderer)->property_text() = 
347       String::ucompose("%1", (*i)[army_columns.strength]);
348 }
349
350 void CityEditorDialog::on_strength_edited(const Glib::ustring &path,
351                                    const Glib::ustring &new_text)
352 {
353   int str = atoi(new_text.c_str());
354   if (str < (int)MIN_STRENGTH_FOR_ARMY_UNITS || 
355       str > (int)MAX_STRENGTH_FOR_ARMY_UNITS)
356     return;
357   (*army_list->get_iter(Gtk::TreePath(path)))[army_columns.strength] = str;
358 }
359
360 void CityEditorDialog::cell_data_moves(Gtk::CellRenderer *renderer,
361                                   const Gtk::TreeIter& i)
362 {
363     dynamic_cast<Gtk::CellRendererSpin*>(renderer)->property_adjustment()
364           = new Gtk::Adjustment((*i)[army_columns.moves], 
365                                 MIN_MOVES_FOR_ARMY_UNITS, 
366                                 MAX_MOVES_FOR_ARMY_UNITS, 1);
367     dynamic_cast<Gtk::CellRendererSpin*>(renderer)->property_text() = 
368       String::ucompose("%1", (*i)[army_columns.moves]);
369 }
370
371 void CityEditorDialog::on_moves_edited(const Glib::ustring &path,
372                                    const Glib::ustring &new_text)
373 {
374   int moves = atoi(new_text.c_str());
375   if (moves < (int)MIN_MOVES_FOR_ARMY_UNITS || 
376       moves > (int)MAX_MOVES_FOR_ARMY_UNITS)
377     return;
378   (*army_list->get_iter(Gtk::TreePath(path)))[army_columns.moves] = moves;
379 }
380
381 void CityEditorDialog::cell_data_turns(Gtk::CellRenderer *renderer,
382                                    const Gtk::TreeIter& i)
383 {
384     dynamic_cast<Gtk::CellRendererSpin*>(renderer)->property_adjustment()
385           = new Gtk::Adjustment((*i)[army_columns.duration], 
386                                 MIN_PRODUCTION_TURNS_FOR_ARMY_UNITS, 
387                                 MAX_PRODUCTION_TURNS_FOR_ARMY_UNITS, 1);
388     dynamic_cast<Gtk::CellRendererSpin*>(renderer)->property_text() = 
389       String::ucompose("%1", (*i)[army_columns.duration]);
390 }
391
392 void CityEditorDialog::on_turns_edited(const Glib::ustring &path,
393                                    const Glib::ustring &new_text)
394 {
395   int turns = atoi(new_text.c_str());
396   if (turns < (int)MIN_PRODUCTION_TURNS_FOR_ARMY_UNITS || 
397       turns > (int)MAX_PRODUCTION_TURNS_FOR_ARMY_UNITS)
398     return;
399   (*army_list->get_iter(Gtk::TreePath(path)))[army_columns.duration] = turns;
400 }
401
402 void CityEditorDialog::cell_data_upkeep(Gtk::CellRenderer *renderer,
403                                    const Gtk::TreeIter& i)
404 {
405     dynamic_cast<Gtk::CellRendererSpin*>(renderer)->property_adjustment()
406           = new Gtk::Adjustment((*i)[army_columns.upkeep], 0, 20, 1);
407     dynamic_cast<Gtk::CellRendererSpin*>(renderer)->property_text() = 
408       String::ucompose("%1", (*i)[army_columns.upkeep]);
409 }
410
411 void CityEditorDialog::on_upkeep_edited(const Glib::ustring &path,
412                                    const Glib::ustring &new_text)
413 {
414   int upkeep = atoi(new_text.c_str());
415   if (upkeep < (int) MIN_UPKEEP_FOR_ARMY_UNITS || 
416       upkeep > (int) MAX_UPKEEP_FOR_ARMY_UNITS)
417     return;
418   (*army_list->get_iter(Gtk::TreePath(path)))[army_columns.upkeep] = upkeep;
419 }
420
421       
422 Player *CityEditorDialog::get_selected_player()
423 {
424   int c = 0, row = player_combobox->get_active_row_number();
425   Player *player = Playerlist::getInstance()->getNeutral();
426   for (Playerlist::iterator i = Playerlist::getInstance()->begin(),
427        end = Playerlist::getInstance()->end(); i != end; ++i, ++c)
428     if (c == row)
429       {
430         player = *i;
431         break;
432       }
433   return player;
434 }
435
436 void CityEditorDialog::on_player_changed()
437 {
438   GraphicsCache *gc = GraphicsCache::getInstance();
439   // set allegiance
440   Player *player = get_selected_player();
441   for (Gtk::TreeIter j = army_list->children().begin(),
442        jend = army_list->children().end(); j != jend; ++j)
443     {
444       const ArmyProdBase *a = (*j)[army_columns.army];
445       (*j)[army_columns.image] = gc->getArmyPic(player->getArmyset(),
446                                                 a->getTypeId(), 
447                                                 player, NULL)->to_pixbuf();
448     }
449 }