initial commit, lordsawar source, slightly modified
[lordsawar] / src / gui / stack-info-dialog.cpp
1 //  Copyright (C) 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 <sigc++/functors/mem_fun.h>
21
22 #include "stack-info-dialog.h"
23
24 #include <gtkmm.h>
25 #include "glade-helpers.h"
26 #include "input-helpers.h"
27 #include "image-helpers.h"
28 #include "ucompose.hpp"
29 #include "defs.h"
30 #include "army.h"
31 #include "player.h"
32 #include "armysetlist.h"
33 #include "playerlist.h"
34 #include "stack.h"
35 #include "GraphicsCache.h"
36 #include "Tile.h"
37 #include <assert.h>
38 #include "stacktile.h"
39 #include "GameMap.h"
40
41 StackInfoDialog::StackInfoDialog(Vector<int> pos)
42 {
43   army_info_tip = NULL;
44   tile = pos;
45   currently_selected_stack = NULL;
46     
47     Glib::RefPtr<Gtk::Builder> xml
48         = Gtk::Builder::create_from_file(get_glade_path()
49                                     + "/stack-info-dialog.ui");
50
51     xml->get_widget("dialog", dialog);
52     decorate(dialog);
53     window_closed.connect(sigc::mem_fun(dialog, &Gtk::Dialog::hide));
54
55     xml->get_widget("stack_table", stack_table);
56
57
58     xml->get_widget("group_button", group_button);
59     group_button->signal_clicked().connect
60       (sigc::mem_fun(*this, &StackInfoDialog::on_group_clicked));
61     xml->get_widget("ungroup_button", ungroup_button);
62     ungroup_button->signal_clicked().connect
63       (sigc::mem_fun(*this, &StackInfoDialog::on_ungroup_clicked));
64     fill_stack_info();
65 }
66
67 StackInfoDialog::~StackInfoDialog()
68 {
69   if (army_info_tip != NULL)
70     delete army_info_tip;
71   delete dialog;
72 }
73 void StackInfoDialog::set_parent_window(Gtk::Window &parent)
74 {
75     dialog->set_transient_for(parent);
76     //dialog->set_position(Gtk::WIN_POS_CENTER_ON_PARENT);
77 }
78
79 void StackInfoDialog::hide()
80 {
81   dialog->hide();
82 }
83
84 void StackInfoDialog::run()
85 {
86     static int width = -1;
87     static int height = -1;
88
89     if (width != -1 && height != -1)
90         dialog->set_default_size(width, height);
91     
92     dialog->show();
93     dialog->run();
94
95     dialog->get_size(width, height);
96
97 }
98
99 void StackInfoDialog::addStack(Stack *s, guint32 &idx)
100 {
101   s->sortForViewing(true);
102   Stack *target = new Stack(Playerlist::getInstance()->getNeutral(), s->getPos());
103   ArmyProto *baseproto = ArmyProto::createScout();
104   Army *army = new Army(*baseproto);
105   delete baseproto;
106   target->add(army);
107   Fight fight(s, target, Fight::FOR_KICKS);
108   delete target;
109
110   bool first = true;
111   for (Stack::iterator it = s->begin(); it != s->end(); it++)
112     {
113       guint32 str = fight.getModifiedStrengthBonus(*it);
114       addArmy(first, s, *it, str, idx);
115       if (first == true)
116         first = false;
117       idx++;
118     }
119 }
120
121 void StackInfoDialog::addArmy (bool first, Stack *s, Army *h, guint32 modified_strength, int idx)
122 {
123   GraphicsCache *gc = GraphicsCache::getInstance();
124   Player *player = h->getOwner();
125     
126           
127   bool greyed_out = s->getId() != currently_selected_stack->getId();
128   Gtk::ToggleButton *toggle = manage(new Gtk::ToggleButton);
129   Glib::RefPtr<Gdk::Pixbuf> pixbuf= 
130     gc->getArmyPic(player->getArmyset(), h->getTypeId(), player, NULL,
131                    greyed_out)->to_pixbuf();
132   
133   Gtk::Image *image = NULL;
134   guint32 move_bonus = h->getStat(Army::MOVE_BONUS);
135   bool ship = h->getStat(Army::SHIP);
136   if (ship || move_bonus == (Tile::GRASS | Tile::WATER | Tile::FOREST | 
137                              Tile::HILLS | Tile::SWAMP | Tile::MOUNTAIN))
138     {
139       image = new Gtk::Image();
140       image->property_pixbuf() = gc->getMoveBonusPic(move_bonus, ship)->to_pixbuf();
141     }
142
143   armies.push_back(h);
144   toggle->set_active(s->getId() == currently_selected_stack->getId());
145   toggle->signal_toggled().connect
146     (sigc::bind(sigc::mem_fun(this, 
147                               &StackInfoDialog::on_army_toggled), toggle, s, h));
148   toggle->add_events(Gdk::BUTTON_PRESS_MASK | Gdk::BUTTON_RELEASE_MASK);
149   toggles.push_back(toggle);
150   toggle->signal_button_press_event().connect
151     (sigc::bind(sigc::mem_fun(*this, &StackInfoDialog::on_army_button_event),
152                 toggle), false);
153   toggle->signal_button_release_event().connect
154     (sigc::bind(sigc::mem_fun(*this, &StackInfoDialog::on_army_button_event),
155                 toggle), false);
156   Gtk::Image *army_image = new Gtk::Image();
157   army_image->property_pixbuf() = pixbuf;
158   toggle->add(*manage(army_image));
159
160   Gtk::Label *name = new Gtk::Label(h->getName());
161   Glib::ustring str = "";
162    
163   unsigned int strength_value = h->getStat(Army::STRENGTH);
164   str = String::ucompose("%1", strength_value);
165   if (modified_strength != strength_value)
166     str += String::ucompose(" (%1)", modified_strength);
167       
168   Gtk::Label *strength = new Gtk::Label(str);
169
170   Gtk::Label *bonus = new Gtk::Label(h->getArmyBonusDescription());
171   Gtk::Label *moves = new Gtk::Label(String::ucompose("%1", h->getMoves()));
172         
173   if (first)
174     {
175       Gtk::RadioButton *radio;
176       if (radios.size() > 0)
177         {
178           Gtk::RadioButtonGroup b;
179           b = radios.front()->get_group();
180           radio = new Gtk::RadioButton(b);
181         }
182       else
183         radio = new Gtk::RadioButton();
184       radios.push_back(radio);
185       radio->set_active(s->getId() == currently_selected_stack->getId());
186       radio->signal_toggled().connect
187         (sigc::bind(sigc::mem_fun(this, &StackInfoDialog::on_stack_toggled), 
188                     radio, s));
189       stack_table->attach(*manage(radio), 0, 1, idx, idx + 1,
190                           Gtk::SHRINK, Gtk::SHRINK);
191     }
192
193   stack_table->attach(*manage(toggle), 1, 2, idx, idx + 1,
194                       Gtk::SHRINK, Gtk::SHRINK);
195   stack_table->attach(*manage(name), 2, 3, idx, idx + 1,
196                       Gtk::SHRINK, Gtk::SHRINK);
197   stack_table->attach(*manage(strength), 3, 4, idx, idx+1,
198                       Gtk::SHRINK, Gtk::SHRINK);
199   stack_table->attach(*manage(moves), 4, 5, idx, idx+1,
200                       Gtk::SHRINK, Gtk::SHRINK);
201   if (image)
202     stack_table->attach(*manage(image), 5, 6, idx, idx+1,
203                         Gtk::SHRINK, Gtk::SHRINK);
204   stack_table->attach(*manage(bonus), 6, 7, idx, idx + 1,
205                       Gtk::SHRINK, Gtk::SHRINK);
206           
207 }
208        
209 void StackInfoDialog::on_group_clicked()
210 {
211   StackTile *stile = GameMap::getStacks(tile);
212   Stack *stack = stile->group(Playerlist::getActiveplayer());
213   currently_selected_stack = stack;
214   stack->sortForViewing(true);
215   fill_stack_info();
216 }
217
218 void StackInfoDialog::on_ungroup_clicked()
219 {
220   StackTile *stile = GameMap::getStacks(tile);
221   stile->ungroup(Playerlist::getActiveplayer());
222   fill_stack_info();
223 }
224
225 void StackInfoDialog::fill_stack_info()
226 {
227   StackTile *stile = GameMap::getStacks(tile);
228   guint32 idx = 1;
229
230   armies.clear();
231   toggles.clear();
232   radios.clear();
233   stack_table->foreach(sigc::mem_fun(stack_table, &Gtk::Container::remove));
234   stack_table->resize(6, MAX_ARMIES_ON_A_SINGLE_TILE);
235
236   Gtk::Label *str = new Gtk::Label(_("Str"));
237   stack_table->attach(*manage(str), 3, 4, 0, 1, Gtk::SHRINK, Gtk::SHRINK);
238
239   Gtk::Label *moves = new Gtk::Label(_("Move"));
240   stack_table->attach(*manage(moves), 4, 5, 0, 1, Gtk::SHRINK, Gtk::SHRINK);
241
242   Gtk::Label *bonus = new Gtk::Label(_("Bonus"));
243   stack_table->attach(*manage(bonus), 6, 7, 0, 1, Gtk::SHRINK, Gtk::SHRINK);
244
245   std::list<Stack*> stks;
246   stks = stile->getFriendlyStacks(Playerlist::getActiveplayer());
247   currently_selected_stack = stks.front();
248   for (std::list<Stack *>::iterator i = stks.begin(); i != stks.end(); i++)
249     {
250       addStack(*i, idx);
251     }
252   stack_table->show_all();
253 }
254
255 bool StackInfoDialog::on_army_button_event(GdkEventButton *e, Gtk::ToggleButton *toggle)
256 {
257   MouseButtonEvent event = to_input_event(e);
258   if (event.button == MouseButtonEvent::RIGHT_BUTTON
259       && event.state == MouseButtonEvent::PRESSED) 
260     {
261       int slot = -1;
262       for (unsigned int i = 0; i < toggles.size(); ++i) 
263         {
264           if (toggle == toggles[i])
265             slot = i;
266         }
267       assert(slot != -1);
268
269       const Army *army = armies[slot];
270
271       if (army)
272         {
273           if (army_info_tip != NULL)
274             delete army_info_tip;
275           army_info_tip = new ArmyInfoTip(toggle, army);
276         }
277       return true;
278     }
279   else if (event.button == MouseButtonEvent::RIGHT_BUTTON
280            && event.state == MouseButtonEvent::RELEASED) 
281     {
282       if (army_info_tip != NULL)
283         {
284           delete army_info_tip;
285           army_info_tip = NULL;
286         }
287       return true;
288     }
289
290   return false;
291 }
292
293 void StackInfoDialog::on_army_toggled(Gtk::ToggleButton *toggle, Stack *stack, Army *army)
294 {
295   Player *p = Playerlist::getActiveplayer();
296   group_button->set_sensitive(false);
297   ungroup_button->set_sensitive(false);
298   if (toggle->get_active() == true)
299     {
300       if (stack->size() > 1)
301         {
302           Stack *new_stack = p->stackSplitArmy(stack, army);
303           if (new_stack)
304             p->stackJoin(currently_selected_stack, new_stack);
305         }
306       else
307         p->stackJoin(currently_selected_stack, stack);
308       currently_selected_stack->sortForViewing(true);
309     }
310   else
311     {
312       p->stackSplitArmy(stack, army);
313       stack->sortForViewing(true);
314     }
315   group_button->set_sensitive(true);
316   ungroup_button->set_sensitive(true);
317   fill_stack_info();
318 }
319
320 void StackInfoDialog::on_stack_toggled(Gtk::RadioButton *radio, Stack *stack)
321 {
322   if (radio->get_active() == true)
323     {
324       if (stack == currently_selected_stack)
325         return;
326       currently_selected_stack = stack;
327       fill_stack_info();
328     }
329 }
330