initial commit, lordsawar source, slightly modified
[lordsawar] / src / gui / city-window.cpp
diff --git a/src/gui/city-window.cpp b/src/gui/city-window.cpp
new file mode 100644 (file)
index 0000000..8d0128e
--- /dev/null
@@ -0,0 +1,526 @@
+//  Copyright (C) 2007 Ole Laursen
+//  Copyright (C) 2007, 2008, 2009 Ben Asselstine
+//
+//  This program is free software; you can redistribute it and/or modify
+//  it under the terms of the GNU General Public License as published by
+//  the Free Software Foundation; either version 3 of the License, or
+//  (at your option) any later version.
+//
+//  This program is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//  GNU Library General Public License for more details.
+//
+//  You should have received a copy of the GNU General Public License
+//  along with this program; if not, write to the Free Software
+//  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 
+//  02110-1301, USA.
+
+#include <config.h>
+
+#include <assert.h>
+
+#include <gtkmm.h>
+#include <sigc++/functors/mem_fun.h>
+
+#include "city-window.h"
+
+#include "glade-helpers.h"
+#include "image-helpers.h"
+#include "input-helpers.h"
+#include "ucompose.hpp"
+#include "defs.h"
+#include "army.h"
+#include "armyprodbase.h"
+#include "player.h"
+#include "city.h"
+#include "GraphicsCache.h"
+#include "armysetlist.h"
+#include "buy-production-dialog.h"
+#include "destination-dialog.h"
+#include "GameMap.h"
+#include "citylist.h"
+#include "playerlist.h"
+#include "File.h"
+
+CityWindow::CityWindow(City *c, bool razing_possible, 
+                      bool see_opponents_production)
+{
+  army_info_tip = NULL;
+    city = c;
+    
+    Glib::RefPtr<Gtk::Builder> xml
+       = Gtk::Builder::create_from_file(get_glade_path() + "/city-window.ui");
+
+    xml->get_widget("dialog", dialog);
+    decorate(dialog);
+    window_closed.connect(sigc::mem_fun(dialog, &Gtk::Dialog::hide));
+    set_title(c->getName());
+    
+    xml->get_widget("map_image", map_image);
+
+    prodmap = new VectorMap(c, VectorMap::SHOW_ORIGIN_CITY_VECTORING,
+                 see_opponents_production);
+    prodmap->map_changed.connect(
+       sigc::mem_fun(this, &CityWindow::on_map_changed));
+
+    Gtk::EventBox *map_eventbox;
+    xml->get_widget("map_eventbox", map_eventbox);
+    map_eventbox->add_events(Gdk::BUTTON_PRESS_MASK);
+    map_eventbox->signal_button_press_event().connect(
+       sigc::mem_fun(*this, &CityWindow::on_map_mouse_button_event));
+    xml->get_widget("status_label", status_label);
+    xml->get_widget("turns_left_label", turns_left_label);
+    xml->get_widget("current_label", current_label);
+    xml->get_widget("current_image", current_image);
+    xml->get_widget("production_info_label1", production_info_label1);
+    xml->get_widget("production_info_label2", production_info_label2);
+    xml->get_widget("buy_button", buy_button);
+    xml->get_widget("on_hold_button", on_hold_button);
+    on_hold_button->signal_clicked().connect(
+           sigc::mem_fun(this, &CityWindow::on_on_hold_clicked));
+    buy_button->signal_clicked().connect(
+       sigc::mem_fun(this, &CityWindow::on_buy_clicked));
+    xml->get_widget("destination_button", destination_button);
+    destination_button->signal_clicked().connect(
+       sigc::mem_fun(this, &CityWindow::on_destination_clicked));
+    xml->get_widget("rename_button", rename_button);
+    rename_button->signal_clicked().connect(
+       sigc::mem_fun(this, &CityWindow::on_rename_clicked));
+    xml->get_widget("raze_button", raze_button);
+    raze_button->signal_clicked().connect(
+       sigc::mem_fun(this, &CityWindow::on_raze_clicked));
+
+    xml->get_widget("production_toggles_hbox", production_toggles_hbox);
+    for (unsigned int i = 1; i <= city->getMaxNoOfProductionBases(); ++i) {
+       Gtk::ToggleButton *toggle = new Gtk::ToggleButton();
+       production_toggles_hbox->pack_start(*manage(toggle), false, false, 0);
+       production_toggles.push_back(toggle);
+       toggle->signal_toggled().connect(
+           sigc::bind(sigc::mem_fun(this, &CityWindow::on_production_toggled),
+                      toggle));
+       toggle->add_events(Gdk::BUTTON_PRESS_MASK | Gdk::BUTTON_RELEASE_MASK);
+       toggle->signal_button_press_event().connect(
+           sigc::bind(sigc::mem_fun(*this, &CityWindow::on_production_button_event),
+                      toggle), false);
+       
+       toggle->signal_button_release_event().connect(
+           sigc::bind(sigc::mem_fun(*this, &CityWindow::on_production_button_event),
+                      toggle), false);
+       
+    }
+
+    d_razing_possible = razing_possible;
+    fill_in_city_info();
+    fill_in_production_toggles();
+
+    ignore_toggles = false;
+}
+
+CityWindow::~CityWindow()
+{
+  delete dialog;
+  delete prodmap;
+  if (army_info_tip != NULL)
+    delete army_info_tip;
+}
+
+bool CityWindow::on_map_mouse_button_event(GdkEventButton *e)
+{
+    if (e->type != GDK_BUTTON_PRESS)
+       return true;    // useless event
+    
+    prodmap->mouse_button_event(to_input_event(e));
+    
+    city = prodmap->getCity();
+    fill_in_city_info();
+    fill_in_production_toggles();
+    fill_in_production_info();
+    return true;
+}
+
+void CityWindow::set_parent_window(Gtk::Window &parent)
+{
+    dialog->set_transient_for(parent);
+    //dialog->set_position(Gtk::WIN_POS_CENTER_ON_PARENT);
+}
+
+void CityWindow::hide()
+{
+  dialog->hide();
+}
+
+void CityWindow::run()
+{
+    prodmap->resize();
+    prodmap->draw(Playerlist::getActiveplayer());
+    dialog->show();
+    dialog->run();
+}
+
+void CityWindow::fill_in_city_info()
+{
+    
+    set_title(city->getName());
+
+    // fill in status label
+    Glib::ustring s;
+    if (city->isCapital())
+    {
+       s += String::ucompose(_("Capital city of %1"),
+                             city->getCapitalOwner()->getName());
+       s += "\n";
+    }
+
+    s += String::ucompose(_("Defence: %1"), city->getDefenseLevel());
+    s += "\n";
+    s += String::ucompose(_("Income: %1"), city->getGold());
+    status_label->set_text(s);
+}
+
+void CityWindow::fill_in_production_toggles()
+{
+    Player *player = city->getOwner();
+    unsigned int as = player->getArmyset();
+    int production_index = city->getActiveProductionSlot();
+    int type;
+    Glib::RefPtr<Gdk::Pixbuf> pic;
+    GraphicsCache *gc = GraphicsCache::getInstance();
+
+    Glib::RefPtr<Gdk::Pixbuf> s
+       = GraphicsCache::getInstance()->getArmyPic(as, 0, player, NULL)->to_pixbuf();
+    Glib::RefPtr<Gdk::Pixbuf> empty_pic
+       = Gdk::Pixbuf::create(Gdk::COLORSPACE_RGB, true, 8, s->get_width(), s->get_height());
+    empty_pic->fill(0x00000000);
+    
+    ignore_toggles = true;
+    for (unsigned int i = 0; i < city->getMaxNoOfProductionBases(); i++)
+    {
+       Gtk::ToggleButton *toggle = production_toggles[i];
+       toggle->foreach(sigc::mem_fun(toggle, &Gtk::Container::remove));
+
+       type = city->getArmytype(i);
+        if (type != -1)
+            // use GraphicsCache to load army pics because of player-specific
+            // colors
+            pic = gc->getArmyPic(as, type, player, NULL)->to_pixbuf();
+       else
+           pic = empty_pic;
+       
+       Gtk::Image *image = new Gtk::Image();
+       image->property_pixbuf() = pic;
+       toggle->add(*manage(image));
+
+       toggle->set_active((int)i == production_index);
+       toggle->show_all();
+    }
+    ignore_toggles = false;
+
+    on_hold_button->set_sensitive(production_index != -1);
+    fill_in_production_info();
+
+}
+
+void CityWindow::on_production_toggled(Gtk::ToggleButton *toggle)
+{
+    if (city->getOwner() != Playerlist::getActiveplayer())
+    {
+        toggle->set_active(false);
+        return;
+    }
+    if (ignore_toggles)
+       return;
+    
+    int slot = -1;
+    ignore_toggles = true;
+    for (unsigned int i = 0; i < production_toggles.size(); ++i) {
+       if (toggle == production_toggles[i])
+           slot = i;
+       
+       production_toggles[i]->set_active(toggle == production_toggles[i]);
+    }
+    ignore_toggles = false;
+
+    bool is_empty = city->getArmytype(slot) == -1;
+    
+    if (is_empty)
+       city->getOwner()->cityChangeProduction(city, -1);
+    else
+       city->getOwner()->cityChangeProduction(city, slot);
+
+    on_hold_button->set_sensitive(!is_empty);
+    
+    fill_in_production_info();
+}
+
+void CityWindow::fill_in_production_info()
+{
+    Player *player = city->getOwner();
+    unsigned int as = player->getArmyset();
+    Glib::RefPtr<Gdk::Pixbuf> pic;
+    GraphicsCache *gc = GraphicsCache::getInstance();
+    int slot = city->getActiveProductionSlot();
+    Glib::RefPtr<Gdk::Pixbuf> s
+       = GraphicsCache::getInstance()->getArmyPic(as, 0, player, NULL)->to_pixbuf();
+    Glib::RefPtr<Gdk::Pixbuf> empty_pic
+       = Gdk::Pixbuf::create(Gdk::COLORSPACE_RGB, true, 8, s->get_width(), s->get_height());
+    empty_pic->fill(0x00000000);
+    
+    Glib::ustring s1, s2, s3;
+    Glib::ustring s4 = _("Current:");
+    
+    if (slot == -1)
+    {
+        pic = empty_pic;
+       s1 = _("No production");
+       s1 += "\n\n";
+       s2 = "\n\n";
+        s3 = "";
+    }
+    else
+    {
+        const ArmyProdBase * a = city->getProductionBase(slot);
+
+       // fill in first column
+       s1 += a->getName();
+       s1 += "\n";
+       // note to translators: %1/%2 is the no. of steps completed out of the
+       // total no. of steps in the production
+       s1 += String::ucompose(_("Time: %1"), a->getProduction());
+       s1 += "\n";
+       s1 += String::ucompose(_("Strength: %1"),
+                             a->getStrength());
+       
+       // fill in second column
+       s2 += "\n";
+       s2 += String::ucompose(_("Moves: %1"), a->getMaxMoves());
+       s2 += "\n";
+       s2 += String::ucompose(_("Cost: %1"), a->getUpkeep());
+
+        s3 = String::ucompose(_("%1t"), city->getDuration());
+        if (city->getVectoring() != Vector<int>(-1, -1))
+          {
+            Citylist *cl = Citylist::getInstance();
+            City *dest = cl->getNearestFriendlyCity(city->getVectoring(), 4);
+            s3 += String::ucompose(_(", then to %1"), 
+                                   dest ? dest->getName() : "Standard");
+          }
+      pic = gc->getArmyPic(as, a->getTypeId(), player, NULL)->to_pixbuf();
+    }
+    
+    current_image->property_pixbuf() = pic;
+    production_info_label1->set_markup(s1);
+    production_info_label2->set_markup(s2);
+    turns_left_label->set_markup("<i>" + s3 + "</i>");
+    current_label->set_markup("<i>" + s4 + "</i>");
+
+    if (city->getOwner () != Playerlist::getActiveplayer())
+      {
+        turns_left_label->hide();
+        current_label->hide();
+        current_image->hide();
+        buy_button->set_sensitive(false);
+        raze_button->set_sensitive(false);
+        rename_button->set_sensitive(false);
+        destination_button->set_sensitive(false);
+        on_hold_button->set_sensitive(false);
+        for (unsigned int i = 0; i < production_toggles.size(); ++i) 
+          {
+           // production_toggles[i]->set_sensitive(false);
+           production_toggles[i]->set_active(false);
+          }
+        production_info_label1->hide();
+        production_info_label2->hide();
+      }
+    else
+      {
+        turns_left_label->show();
+        current_label->show();
+        current_image->show();
+        buy_button->set_sensitive(true);
+        raze_button->set_sensitive (d_razing_possible);
+        rename_button->set_sensitive(true);
+        destination_button->set_sensitive(true);
+        on_hold_button->set_sensitive(true);
+        //for (unsigned int i = 0; i < production_toggles.size(); ++i) 
+          //production_toggles[i]->set_sensitive(true);
+        production_info_label1->show();
+        production_info_label2->show();
+      }
+}
+
+bool CityWindow::on_production_button_event(GdkEventButton *e, Gtk::ToggleButton *toggle)
+{
+    MouseButtonEvent event = to_input_event(e);
+    if (event.button == MouseButtonEvent::RIGHT_BUTTON
+       && event.state == MouseButtonEvent::PRESSED) {
+       int slot = -1;
+       for (unsigned int i = 0; i < production_toggles.size(); ++i) {
+           if (toggle == production_toggles[i])
+               slot = i;
+       }
+       assert(slot != -1);
+
+       const ArmyProdBase *prodbase = city->getProductionBase(slot);
+
+       if (prodbase)
+         {
+           if (army_info_tip != NULL)
+               delete army_info_tip;
+           army_info_tip = new ArmyInfoTip(toggle, prodbase, city);
+         }
+       return true;
+    }
+    else if (event.button == MouseButtonEvent::RIGHT_BUTTON
+            && event.state == MouseButtonEvent::RELEASED) {
+       {
+         if (army_info_tip != NULL)
+           {
+             delete army_info_tip;
+             army_info_tip = NULL;
+           }
+       }
+       return true;
+    }
+    
+    return false;
+}
+
+void CityWindow::on_on_hold_clicked() //stop button
+{
+    city->setVectoring(Vector<int>(-1,-1));
+    city->getOwner()->cityChangeProduction(city, -1);
+    on_hold_button->set_sensitive(false);
+    ignore_toggles = true;
+    for (unsigned int i = 0; i < production_toggles.size(); ++i)
+       production_toggles[i]->set_active(false);
+    ignore_toggles = false;
+    fill_in_production_info();
+    prodmap->draw(Playerlist::getActiveplayer());
+}
+
+void CityWindow::on_buy_clicked()
+{
+    BuyProductionDialog d(city);
+    d.set_parent_window(*dialog);
+    d.run();
+
+    int army = d.get_selected_army();
+    d.hide();
+    if (army != BuyProductionDialog::NO_ARMY_SELECTED)
+    {
+       int slot = -1;
+       slot = city->getFreeSlot();
+       
+       if  (slot == -1)
+         {
+           //no free slots available.  change the one we're on.
+           slot = city->getActiveProductionSlot();
+           if (slot == -1) 
+             slot = 0;
+         }
+       city->getOwner()->cityBuyProduction(city, slot, army);
+       city->getOwner()->cityChangeProduction(city, slot);
+
+       fill_in_production_toggles();
+       fill_in_production_info();
+
+    }
+}
+
+void CityWindow::on_destination_clicked()
+{
+    DestinationDialog d(city, &d_see_all);
+    d.set_parent_window(*dialog);
+    d.run();
+    fill_in_production_info();
+    prodmap->draw(Playerlist::getActiveplayer());
+}
+
+void CityWindow::on_map_changed(Glib::RefPtr<Gdk::Pixmap> map)
+{
+    map_image->property_pixmap() = map;
+}
+
+void CityWindow::on_rename_clicked ()
+{
+    Gtk::Dialog* subdialog;
+    
+    Glib::RefPtr<Gtk::Builder> renamexml
+       = Gtk::Builder::create_from_file(get_glade_path() + "/city-rename-dialog.ui");
+       
+    renamexml->get_widget("dialog", subdialog);
+    Decorated decorator;
+    decorator.decorate(subdialog);
+    decorator.window_closed.connect(sigc::mem_fun(subdialog, &Gtk::Dialog::hide));
+    subdialog->set_transient_for(*dialog);
+    
+    Glib::ustring s = _("Rename City");
+
+    Gtk::Label *l;
+    renamexml->get_widget("label", l);
+    Gtk::Entry *e;
+    renamexml->get_widget("name_entry", e);
+
+    decorator.set_title(s);
+    s = _("Type the new name for this city:");
+    l->set_text(s);
+
+    e->set_text(city->getName());
+    subdialog->show_all();
+    int response = subdialog->run();
+
+    if (response == Gtk::RESPONSE_ACCEPT)              // changed city name
+      {
+        Playerlist::getActiveplayer()->cityRename(city, e->get_text());
+        fill_in_city_info();
+      }
+    subdialog->hide();
+    delete subdialog;
+  return;
+}
+
+void CityWindow::on_raze_clicked ()
+{
+  on_raze_clicked (city, dialog);
+}
+
+bool CityWindow::on_raze_clicked (City *city, Gtk::Dialog *parent)
+{
+    Gtk::Dialog* subdialog;
+    
+    Glib::RefPtr<Gtk::Builder> razexml
+       = Gtk::Builder::create_from_file(get_glade_path() + "/city-raze-dialog.ui");
+       
+    razexml->get_widget("dialog", subdialog);
+    Decorated decorator;
+    decorator.decorate(subdialog);
+    decorator.window_closed.connect(sigc::mem_fun(subdialog, &Gtk::Dialog::hide));
+    subdialog->set_transient_for(*parent);
+    subdialog->set_icon_from_file(File::getMiscFile("various/castle_icon.png"));
+    
+    Glib::ustring s = _("Raze City");
+
+    Gtk::Label *l;
+    razexml->get_widget("label", l);
+
+    decorator.set_title(s);
+    s = String::ucompose(_("Are you sure that you want to raze %1?"), 
+                           city->getName());
+    s += "\n";
+    s += _("You won't be popular!");
+    l->set_text(s);
+
+    subdialog->show_all();
+    int response = subdialog->run();
+    subdialog->hide();
+    delete subdialog;
+
+    if (response == Gtk::RESPONSE_ACCEPT) // burn it to the ground ralphie boy!
+      {
+       Playerlist::getActiveplayer()->cityRaze(city);
+       parent->hide();
+       return true;
+      }
+  return false;
+}