1 // Copyright (C) 2009 Ben Asselstine
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.
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.
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
25 #include <sigc++/functors/mem_fun.h>
26 #include <sigc++/functors/ptr_fun.h>
29 #include "cityset-window.h"
30 #include "cityset-info-dialog.h"
31 #include "masked-image-editor-dialog.h"
33 #include "image-helpers.h"
34 #include "input-helpers.h"
35 #include "error-utils.h"
40 #include "ucompose.hpp"
42 #include "glade-helpers.h"
43 #include "image-editor-dialog.h"
44 #include "GraphicsCache.h"
45 #include "citysetlist.h"
48 CitySetWindow::CitySetWindow(std::string load_filename)
52 Glib::RefPtr<Gtk::Builder> xml
53 = Gtk::Builder::create_from_file(get_glade_path() + "/cityset-window.ui");
55 xml->get_widget("window", window);
56 window->set_icon_from_file(File::getMiscFile("various/castle_icon.png"));
57 window->signal_delete_event().connect
58 (sigc::mem_fun(*this, &CitySetWindow::on_window_closed));
60 xml->get_widget("cityset_frame", cityset_frame);
61 xml->get_widget("new_cityset_menuitem", new_cityset_menuitem);
62 new_cityset_menuitem->signal_activate().connect
63 (sigc::mem_fun(this, &CitySetWindow::on_new_cityset_activated));
64 xml->get_widget("load_cityset_menuitem", load_cityset_menuitem);
65 load_cityset_menuitem->signal_activate().connect
66 (sigc::mem_fun(this, &CitySetWindow::on_load_cityset_activated));
67 xml->get_widget("save_cityset_menuitem", save_cityset_menuitem);
68 save_cityset_menuitem->signal_activate().connect
69 (sigc::mem_fun(this, &CitySetWindow::on_save_cityset_activated));
70 xml->get_widget("validate_cityset_menuitem", validate_cityset_menuitem);
71 validate_cityset_menuitem->signal_activate().connect
72 (sigc::mem_fun(this, &CitySetWindow::on_validate_cityset_activated));
73 xml->get_widget("quit_menuitem", quit_menuitem);
74 quit_menuitem->signal_activate().connect
75 (sigc::mem_fun(this, &CitySetWindow::on_quit_activated));
76 xml->get_widget("edit_cityset_info_menuitem", edit_cityset_info_menuitem);
77 edit_cityset_info_menuitem->signal_activate().connect
78 (sigc::mem_fun(this, &CitySetWindow::on_edit_cityset_info_activated));
79 xml->get_widget ("help_about_menuitem", help_about_menuitem);
80 help_about_menuitem->signal_activate().connect
81 (sigc::mem_fun(this, &CitySetWindow::on_help_about_activated));
82 xml->get_widget("city_tile_width_spinbutton", city_tile_width_spinbutton);
83 city_tile_width_spinbutton->set_range (1, 4);
84 city_tile_width_spinbutton->signal_changed().connect
85 (sigc::mem_fun(this, &CitySetWindow::on_city_tile_width_changed));
86 city_tile_width_spinbutton->signal_insert_text().connect
87 (sigc::mem_fun(this, &CitySetWindow::on_city_tile_width_text_changed));
88 xml->get_widget("ruin_tile_width_spinbutton", ruin_tile_width_spinbutton);
89 ruin_tile_width_spinbutton->set_range (1, 4);
90 ruin_tile_width_spinbutton->signal_changed().connect
91 (sigc::mem_fun(this, &CitySetWindow::on_ruin_tile_width_changed));
92 ruin_tile_width_spinbutton->signal_insert_text().connect
93 (sigc::mem_fun(this, &CitySetWindow::on_ruin_tile_width_text_changed));
94 xml->get_widget("temple_tile_width_spinbutton",
95 temple_tile_width_spinbutton);
96 temple_tile_width_spinbutton->set_range (1, 4);
97 temple_tile_width_spinbutton->signal_changed().connect
98 (sigc::mem_fun(this, &CitySetWindow::on_temple_tile_width_changed));
99 temple_tile_width_spinbutton->signal_insert_text().connect
100 (sigc::mem_fun(this, &CitySetWindow::on_temple_tile_width_text_changed));
102 window->signal_delete_event().connect
103 (sigc::mem_fun(*this, &CitySetWindow::on_delete_event));
104 xml->get_widget("change_citypics_button", change_citypics_button);
105 change_citypics_button->signal_clicked().connect(
106 sigc::mem_fun(this, &CitySetWindow::on_change_citypics_clicked));
107 xml->get_widget("change_razedcitypics_button", change_razedcitypics_button);
108 change_razedcitypics_button->signal_clicked().connect(
109 sigc::mem_fun(this, &CitySetWindow::on_change_razedcitypics_clicked));
110 xml->get_widget("change_portpic_button", change_portpic_button);
111 change_portpic_button->signal_clicked().connect(
112 sigc::mem_fun(this, &CitySetWindow::on_change_portpic_clicked));
113 xml->get_widget("change_signpostpic_button", change_signpostpic_button);
114 change_signpostpic_button->signal_clicked().connect(
115 sigc::mem_fun(this, &CitySetWindow::on_change_signpostpic_clicked));
116 xml->get_widget("change_ruinpics_button", change_ruinpics_button);
117 change_ruinpics_button->signal_clicked().connect(
118 sigc::mem_fun(this, &CitySetWindow::on_change_ruinpics_clicked));
119 xml->get_widget("change_templepic_button", change_templepic_button);
120 change_templepic_button->signal_clicked().connect(
121 sigc::mem_fun(this, &CitySetWindow::on_change_templepic_clicked));
122 xml->get_widget("change_towerpics_button", change_towerpics_button);
123 change_towerpics_button->signal_clicked().connect(
124 sigc::mem_fun(this, &CitySetWindow::on_change_towerpics_clicked));
126 update_cityset_panel();
128 if (load_filename.empty() == false)
130 load_cityset (load_filename);
131 update_cityset_panel();
133 update_cityset_menuitems();
137 CitySetWindow::update_cityset_menuitems()
139 if (d_cityset == NULL)
141 save_cityset_menuitem->set_sensitive(false);
142 validate_cityset_menuitem->set_sensitive(false);
143 edit_cityset_info_menuitem->set_sensitive(false);
147 std::string file = d_cityset->getConfigurationFile();
148 if (File::exists(file) == false)
149 save_cityset_menuitem->set_sensitive(true);
150 else if (File::is_writable(file) == false)
151 save_cityset_menuitem->set_sensitive(false);
153 save_cityset_menuitem->set_sensitive(true);
154 edit_cityset_info_menuitem->set_sensitive(true);
155 validate_cityset_menuitem->set_sensitive(true);
160 CitySetWindow::update_cityset_panel()
162 cityset_frame->set_sensitive(d_cityset != NULL);
163 std::string no_image = _("no image set");
165 if (d_cityset && d_cityset->getCitiesFilename().empty() == false)
166 s = d_cityset->getCitiesFilename() + ".png";
169 change_citypics_button->set_label(s);
170 if (d_cityset && d_cityset->getRazedCitiesFilename().empty() == false)
171 s = d_cityset->getRazedCitiesFilename() + ".png";
174 change_razedcitypics_button->set_label(s);
175 if (d_cityset && d_cityset->getPortFilename().empty() == false)
176 s = d_cityset->getPortFilename() + ".png";
179 change_portpic_button->set_label(s);
180 if (d_cityset && d_cityset->getSignpostFilename().empty() == false)
181 s = d_cityset->getSignpostFilename() + ".png";
184 change_signpostpic_button->set_label(s);
185 if (d_cityset && d_cityset->getRuinsFilename().empty() == false)
186 s = d_cityset->getRuinsFilename() + ".png";
189 change_ruinpics_button->set_label(s);
190 if (d_cityset && d_cityset->getTemplesFilename().empty() == false)
191 s = d_cityset->getTemplesFilename() + ".png";
194 change_templepic_button->set_label(s);
195 if (d_cityset && d_cityset->getTowersFilename().empty() == false)
196 s = d_cityset->getTowersFilename() + ".png";
199 change_towerpics_button->set_label(s);
201 city_tile_width_spinbutton->set_value(d_cityset->getCityTileWidth());
203 city_tile_width_spinbutton->set_value(2);
205 ruin_tile_width_spinbutton->set_value(d_cityset->getRuinTileWidth());
207 ruin_tile_width_spinbutton->set_value(1);
209 temple_tile_width_spinbutton->set_value(d_cityset->getTempleTileWidth());
211 temple_tile_width_spinbutton->set_value(1);
214 CitySetWindow::~CitySetWindow()
219 void CitySetWindow::show()
224 void CitySetWindow::hide()
229 bool CitySetWindow::on_delete_event(GdkEventAny *e)
236 void CitySetWindow::on_new_cityset_activated()
238 std::string name = "";
239 int id = Citysetlist::getNextAvailableId();
240 Cityset *cityset = new Cityset(id, name);
241 CitySetInfoDialog d(cityset, false);
242 d.set_parent_window(*window);
243 int response = d.run();
244 if (response != Gtk::RESPONSE_ACCEPT)
252 std::string dir = File::getUserCitysetDir() + "/" + d_cityset->getSubDir();
253 d_cityset->setDirectory(dir);
254 File::create_dir(dir);
255 current_save_filename = d_cityset->getConfigurationFile();
257 update_cityset_panel();
258 update_cityset_menuitems();
260 XML_Helper helper(current_save_filename, std::ios::out, false);
261 d_cityset->save(&helper);
266 void CitySetWindow::on_load_cityset_activated()
268 Gtk::FileChooserDialog chooser(*window,
269 _("Choose a Cityset to Load"));
270 Gtk::FileFilter sav_filter;
271 sav_filter.add_pattern("*" + CITYSET_EXT);
272 chooser.set_filter(sav_filter);
273 chooser.set_current_folder(File::getUserCitysetDir());
275 chooser.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
276 chooser.add_button(Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
277 chooser.set_default_response(Gtk::RESPONSE_ACCEPT);
280 int res = chooser.run();
282 if (res == Gtk::RESPONSE_ACCEPT)
284 load_cityset(chooser.get_filename());
288 update_cityset_menuitems();
289 update_cityset_panel();
292 void CitySetWindow::on_validate_cityset_activated()
294 std::list<std::string> msgs;
295 if (d_cityset == NULL)
297 if (d_cityset->validateCitiesFilename() == false)
298 msgs.push_back(_("The cities picture is not set."));
299 if (d_cityset->validateRazedCitiesFilename() == false)
300 msgs.push_back(_("The razed cities picture is not set."));
301 if (d_cityset->validatePortFilename() == false)
302 msgs.push_back(_("The port picture is not set."));
303 if (d_cityset->validateSignpostFilename() == false)
304 msgs.push_back(_("The signpost picture is not set."));
305 if (d_cityset->validateRuinsFilename() == false)
306 msgs.push_back(_("The ruins picture is not set."));
307 if (d_cityset->validateTemplesFilename() == false)
308 msgs.push_back(_("The temple picture is not set."));
309 if (d_cityset->validateTowersFilename() == false)
310 msgs.push_back(_("The towers picture is not set."));
311 if (d_cityset->validateCityTileWidth() == false)
312 msgs.push_back(_("The tile width for temples must be over zero."));
313 if (d_cityset->validateRuinTileWidth() == false)
314 msgs.push_back(_("The tile width for ruins must be over zero."));
315 if (d_cityset->validateTempleTileWidth() == false)
316 msgs.push_back(_("The tile width for temples must be over zero."));
318 std::string msg = "";
319 for (std::list<std::string>::iterator it = msgs.begin(); it != msgs.end();
325 Gtk::MessageDialog dialog(*window, msg);
333 void CitySetWindow::on_save_cityset_activated()
335 if (current_save_filename.empty())
336 current_save_filename = d_cityset->getConfigurationFile();
338 XML_Helper helper(current_save_filename, std::ios::out, false);
339 d_cityset->save(&helper);
341 needs_saving = false;
344 void CitySetWindow::on_edit_cityset_info_activated()
346 CitySetInfoDialog d(d_cityset, true);
347 d.set_parent_window(*window);
348 int response = d.run();
349 if (response == Gtk::RESPONSE_ACCEPT)
353 void CitySetWindow::on_help_about_activated()
355 Gtk::AboutDialog* dialog;
357 Glib::RefPtr<Gtk::Builder> xml
358 = Gtk::Builder::create_from_file(get_glade_path() + "/../about-dialog.ui");
360 xml->get_widget("dialog", dialog);
361 dialog->set_transient_for(*window);
362 dialog->set_icon_from_file(File::getMiscFile("various/castle_icon.png"));
364 dialog->set_version(PACKAGE_VERSION);
365 dialog->set_logo(GraphicsCache::getMiscPicture("castle_icon.png")->to_pixbuf());
373 void CitySetWindow::load_cityset(std::string filename)
375 current_save_filename = filename;
377 std::string name = File::get_basename(filename);
379 Cityset *cityset = Cityset::create(filename);
383 msg = "Error! Cityset could not be loaded.";
384 Gtk::MessageDialog dialog(*window, msg);
393 d_cityset->setSubDir(name);
394 d_cityset->instantiateImages();
397 bool CitySetWindow::quit()
399 if (needs_saving == true)
402 Glib::RefPtr<Gtk::Builder> xml
403 = Gtk::Builder::create_from_file(get_glade_path() +
404 "/editor-quit-dialog.ui");
405 xml->get_widget("dialog", dialog);
406 dialog->set_transient_for(*window);
407 int response = dialog->run();
411 if (response == Gtk::RESPONSE_CANCEL) //we don't want to quit
414 else if (response == Gtk::RESPONSE_ACCEPT) // save and quit
415 on_save_cityset_activated();
416 //else if (Response == Gtk::CLOSE) // don't save just quit
424 bool CitySetWindow::on_window_closed(GdkEventAny*)
429 void CitySetWindow::on_quit_activated()
434 void CitySetWindow::on_city_tile_width_text_changed(const Glib::ustring &s, int* p)
436 city_tile_width_spinbutton->set_value(atoi(city_tile_width_spinbutton->get_text().c_str()));
437 on_city_tile_width_changed();
440 void CitySetWindow::on_city_tile_width_changed()
444 d_cityset->setCityTileWidth(city_tile_width_spinbutton->get_value());
448 void CitySetWindow::on_ruin_tile_width_text_changed(const Glib::ustring &s, int* p)
450 ruin_tile_width_spinbutton->set_value(atoi(ruin_tile_width_spinbutton->get_text().c_str()));
451 on_ruin_tile_width_changed();
454 void CitySetWindow::on_ruin_tile_width_changed()
458 d_cityset->setRuinTileWidth(ruin_tile_width_spinbutton->get_value());
462 void CitySetWindow::on_temple_tile_width_text_changed(const Glib::ustring &s, int* p)
464 temple_tile_width_spinbutton->set_value(atoi(temple_tile_width_spinbutton->get_text().c_str()));
465 on_temple_tile_width_changed();
468 void CitySetWindow::on_temple_tile_width_changed()
472 d_cityset->setTempleTileWidth(temple_tile_width_spinbutton->get_value());
476 void CitySetWindow::on_change_citypics_clicked()
478 std::string filename = "";
479 if (d_cityset->getCitiesFilename().empty() == false)
480 filename = d_cityset->getFile(d_cityset->getCitiesFilename());
481 ImageEditorDialog d(filename, MAX_PLAYERS + 1);
482 int response = d.run();
483 if (response == Gtk::RESPONSE_ACCEPT)
485 if (d_cityset->getFile(d_cityset->getCitiesFilename()) !=
486 d.get_selected_filename())
488 File::copy(d.get_selected_filename(),
489 d_cityset->getFile(d_cityset->getCitiesFilename()));
492 d_cityset->setCitiesFilename
493 (File::get_basename(d.get_selected_filename()));
495 update_cityset_panel();
498 void CitySetWindow::on_change_razedcitypics_clicked()
500 std::string filename = "";
501 if (d_cityset->getRazedCitiesFilename().empty() == false)
502 filename = d_cityset->getFile(d_cityset->getRazedCitiesFilename());
503 ImageEditorDialog d(filename, MAX_PLAYERS);
504 int response = d.run();
505 if (response == Gtk::RESPONSE_ACCEPT)
507 if (d_cityset->getFile(d_cityset->getRazedCitiesFilename()) !=
508 d.get_selected_filename())
510 File::copy(d.get_selected_filename(),
511 d_cityset->getFile(d_cityset->getRazedCitiesFilename()));
514 d_cityset->setRazedCitiesFilename
515 (File::get_basename(d.get_selected_filename()));
517 update_cityset_panel();
520 void CitySetWindow::on_change_portpic_clicked()
522 std::string filename = "";
523 if (d_cityset->getPortFilename().empty() == false)
524 filename = d_cityset->getFile(d_cityset->getPortFilename());
525 ImageEditorDialog d(filename, 1);
526 int response = d.run();
527 if (response == Gtk::RESPONSE_ACCEPT)
529 if (d_cityset->getFile(d_cityset->getPortFilename()) !=
530 d.get_selected_filename())
532 File::copy(d.get_selected_filename(),
533 d_cityset->getFile(d_cityset->getPortFilename()));
536 d_cityset->setPortFilename(File::get_basename(d.get_selected_filename()));
538 update_cityset_panel();
541 void CitySetWindow::on_change_signpostpic_clicked()
543 std::string filename = "";
544 if (d_cityset->getSignpostFilename().empty() == false)
545 filename = d_cityset->getFile(d_cityset->getSignpostFilename());
546 ImageEditorDialog d(filename, 1);
547 int response = d.run();
548 if (response == Gtk::RESPONSE_ACCEPT)
550 if (d_cityset->getFile(d_cityset->getSignpostFilename()) !=
551 d.get_selected_filename())
553 File::copy(d.get_selected_filename(),
554 d_cityset->getFile(d_cityset->getSignpostFilename()));
557 d_cityset->setSignpostFilename
558 (File::get_basename(d.get_selected_filename()));
560 update_cityset_panel();
563 void CitySetWindow::on_change_ruinpics_clicked()
565 std::string filename = "";
566 if (d_cityset->getRuinsFilename().empty() == false)
567 filename = d_cityset->getFile(d_cityset->getRuinsFilename());
568 ImageEditorDialog d(filename, RUIN_TYPES);
569 int response = d.run();
570 if (response == Gtk::RESPONSE_ACCEPT)
572 if (d_cityset->getFile(d_cityset->getRuinsFilename()) !=
573 d.get_selected_filename())
575 File::copy(d.get_selected_filename(),
576 d_cityset->getFile(d_cityset->getRuinsFilename()));
579 d_cityset->setRuinsFilename
580 (File::get_basename(d.get_selected_filename()));
582 update_cityset_panel();
585 void CitySetWindow::on_change_templepic_clicked()
587 std::string filename = "";
588 if (d_cityset->getTemplesFilename().empty() == false)
589 filename = d_cityset->getFile(d_cityset->getTemplesFilename());
590 ImageEditorDialog d(filename, TEMPLE_TYPES);
591 int response = d.run();
592 if (response == Gtk::RESPONSE_ACCEPT)
594 if (d_cityset->getFile(d_cityset->getTemplesFilename()) !=
595 d.get_selected_filename())
597 File::copy(d.get_selected_filename(),
598 d_cityset->getFile(d_cityset->getTemplesFilename()));
601 d_cityset->setTemplesFilename
602 (File::get_basename(d.get_selected_filename()));
604 update_cityset_panel();
607 void CitySetWindow::on_change_towerpics_clicked()
609 std::string filename = "";
610 if (d_cityset->getTowersFilename().empty() == false)
611 filename = d_cityset->getFile(d_cityset->getTowersFilename());
612 ImageEditorDialog d(filename, MAX_PLAYERS);
613 int response = d.run();
614 if (response == Gtk::RESPONSE_ACCEPT)
616 if (d_cityset->getFile(d_cityset->getTowersFilename()) !=
617 d.get_selected_filename())
619 File::copy(d.get_selected_filename(),
620 d_cityset->getFile(d_cityset->getTowersFilename()));
623 d_cityset->setTowersFilename
624 (File::get_basename(d.get_selected_filename()));
626 update_cityset_panel();