1 //  Copyright (C) 2007 Ole Laursen
2 //  Copyright (C) 2007, 2008, 2009, 2010, 2012, 2014, 2015, 2017,
3 //  2020 Ben Asselstine
4 //
5 //  This program is free software; you can redistribute it and/or modify
6 //  it under the terms of the GNU General Public License as published by
7 //  the Free Software Foundation; either version 3 of the License, or
8 //  (at your option) any later version.
9 //
10 //  This program is distributed in the hope that it will be useful,
11 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
12 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 //  GNU Library General Public License for more details.
14 //
15 //  You should have received a copy of the GNU General Public License
16 //  along with this program; if not, write to the Free Software
17 //  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18 //  02110-1301, USA.
19 
20 #include <config.h>
21 
22 #include <assert.h>
23 #include <sigc++/functors/mem_fun.h>
24 #include <gtkmm.h>
25 
26 #include "new-map-dialog.h"
27 #include "defs.h"
28 #include "File.h"
29 #include "tileset.h"
30 #include "tilesetlist.h"
31 #include "armysetlist.h"
32 #include "citysetlist.h"
33 #include "shieldsetlist.h"
34 #include "ucompose.hpp"
35 #include "GameMap.h"
36 
37 #define method(x) sigc::mem_fun(*this, &NewMapDialog::x)
38 
NewMapDialog(Gtk::Window & parent)39 NewMapDialog::NewMapDialog(Gtk::Window &parent)
40  : LwEditorDialog(parent, "new-map-dialog.ui")
41 {
42     map_set = false;
43     fill_style_combobox = NULL;
44 
45     xml->get_widget("dialog-vbox", dialog_vbox);
46     xml->get_widget("map_size_combobox", map_size_combobox);
47     xml->get_widget("width_spinbutton", width_spinbutton);
48     xml->get_widget("height_spinbutton", height_spinbutton);
49     xml->get_widget("random_map_container", random_map_container);
50     xml->get_widget("grass_scale", grass_scale);
51     xml->get_widget("water_scale", water_scale);
52     xml->get_widget("swamp_scale", swamp_scale);
53     xml->get_widget("forest_scale", forest_scale);
54     xml->get_widget("hills_scale", hills_scale);
55     xml->get_widget("mountains_scale", mountains_scale);
56     xml->get_widget("cities_scale", cities_scale);
57     xml->get_widget("ruins_scale", ruins_scale);
58     xml->get_widget("temples_scale", temples_scale);
59     xml->get_widget("signposts_scale", signposts_scale);
60     xml->get_widget("stones_scale", stones_scale);
61     xml->get_widget("accept_button", accept_button);
62     xml->get_widget("random_roads_switch", random_roads_switch);
63     random_roads_switch->property_active().signal_changed().connect
64       (method(on_random_roads_toggled));
65     xml->get_widget("random_names_switch", random_names_switch);
66     xml->get_widget("num_players_spinbutton", num_players_spinbutton);
67     xml->get_widget("stone_road_spinbutton", stone_road_spinbutton);
68     xml->get_widget ("notebook", notebook);
69 
70     // fill in tile themes combobox
71 
72     guint32 counter = 0;
73     guint32 default_id = 0;
74     Gtk::Box *box;
75 
76     //fill in tile sizes combobox
77     tile_size_combobox = manage(new Gtk::ComboBoxText);
78     std::list<guint32> sizes;
79     Tilesetlist::getInstance()->getSizes(sizes);
80     Citysetlist::getInstance()->getSizes(sizes);
81     Armysetlist::getInstance()->getSizes(sizes);
82     for (std::list<guint32>::iterator it = sizes.begin(); it != sizes.end();
83 	 it++)
84       {
85 	Glib::ustring s = String::ucompose("%1x%1", *it);
86 	tile_size_combobox->append(s);
87 	if ((*it) == Tileset::getDefaultTileSize())
88 	  default_id = counter;
89 	counter++;
90       }
91     tile_size_combobox->set_active(default_id);
92     xml->get_widget("tile_size_box", box);
93     box->pack_start(*tile_size_combobox, Gtk::PACK_SHRINK);
94     tile_size_combobox->signal_changed().connect (method(on_tile_size_changed));
95 
96     // make new tile themes combobox
97     tile_theme_combobox = manage(new Gtk::ComboBoxText);
98     xml->get_widget("tile_theme_box", box);
99     box->pack_start(*tile_theme_combobox, Gtk::PACK_SHRINK);
100 
101     // make new army themes combobox
102     army_theme_combobox = manage(new Gtk::ComboBoxText);
103     xml->get_widget("army_theme_box", box);
104     box->pack_start(*army_theme_combobox, Gtk::PACK_SHRINK);
105 
106     // make new city themes combobox
107     city_theme_combobox = manage(new Gtk::ComboBoxText);
108     xml->get_widget("city_theme_box", box);
109     box->pack_start(*city_theme_combobox, Gtk::PACK_SHRINK);
110 
111     counter = 0;
112     default_id = 0;
113     shield_theme_combobox = manage(new Gtk::ComboBoxText);
114     Shieldsetlist *sl = Shieldsetlist::getInstance();
115     std::list<Glib::ustring> shield_themes = sl->getValidNames();
116     for (std::list<Glib::ustring>::iterator i = shield_themes.begin(),
117 	 end = shield_themes.end(); i != end; ++i)
118       {
119 	if (*i == _("Default"))
120 	  default_id = counter;
121 	shield_theme_combobox->append(Glib::filename_to_utf8(*i));
122 	counter++;
123       }
124 
125     shield_theme_combobox->set_active(default_id);
126 
127     xml->get_widget("shield_theme_box", box);
128     box->pack_start(*shield_theme_combobox, Gtk::PACK_SHRINK);
129 
130     on_tile_size_changed();
131 
132     // create fill style combobox
133     fill_style_combobox = manage(new Gtk::ComboBoxText);
134 
135     add_fill_style(Tile::GRASS);
136     add_fill_style(Tile::WATER);
137     add_fill_style(Tile::FOREST);
138     add_fill_style(Tile::HILLS);
139     add_fill_style(Tile::MOUNTAIN);
140     add_fill_style(Tile::SWAMP);
141 
142     fill_style_combobox->append(_("Random"));
143     fill_style.push_back(-1);
144 
145     Gtk::Alignment *alignment;
146     xml->get_widget("fill_style_alignment", alignment);
147     alignment->add(*fill_style_combobox);
148 
149     fill_style_combobox->signal_changed().connect (method(on_fill_style_changed));
150     fill_style_combobox->set_active(6);
151 
152     // map size
153     map_size_combobox->set_active(MAP_SIZE_NORMAL);
154     map_size_combobox->signal_changed().connect(method(on_map_size_changed));
155     grass_scale->set_value(78);
156     water_scale->set_value(7);
157     swamp_scale->set_value(2);
158     forest_scale->set_value(3);
159     hills_scale->set_value(5);
160     signposts_scale->set_value(20);
161     stones_scale->set_value(40);
162     mountains_scale->set_value(5);
163     on_map_size_changed();
164     width_spinbutton->set_value (MAP_SIZE_NORMAL_WIDTH);
165     height_spinbutton->set_value (MAP_SIZE_NORMAL_HEIGHT);
166 
167     random_names_switch->set_active(true);
168     num_players_spinbutton->set_value(8);
169     stone_road_spinbutton->set_value (ROAD_STONE_CHANCE);
170     stone_road_spinbutton->set_sensitive (false);
171 }
172 
run()173 void NewMapDialog::run()
174 {
175   dialog->show_all();
176   int response = dialog->run();
177   if (response == Gtk::RESPONSE_ACCEPT)	// accepted
178     {
179       switch (map_size_combobox->get_active_row_number()) {
180       case MAP_SIZE_SMALL:
181 	map.width = MAP_SIZE_SMALL_WIDTH;
182 	map.height = MAP_SIZE_SMALL_HEIGHT;
183 	break;
184 
185       case MAP_SIZE_TINY:
186 	map.width = MAP_SIZE_TINY_WIDTH;
187 	map.height = MAP_SIZE_TINY_HEIGHT;
188 	break;
189 
190       case MAP_SIZE_NORMAL:
191       default:
192 	map.width = MAP_SIZE_NORMAL_WIDTH;
193 	map.height = MAP_SIZE_NORMAL_HEIGHT;
194 	break;
195 
196       case MAP_SIZE_CUSTOM:
197 	map.width = int(width_spinbutton->get_value());
198 	map.height = int(height_spinbutton->get_value());
199         break;
200       }
201 
202       int row = fill_style_combobox->get_active_row_number();
203       assert(row >= 0 && row < int(fill_style.size()));
204       map.fill_style = fill_style[row];
205 
206       map.tileset = Tilesetlist::getInstance()->getSetDir
207 	(Glib::filename_from_utf8(tile_theme_combobox->get_active_text()),
208 	 get_active_tile_size());
209 
210       map.shieldset = Shieldsetlist::getInstance()->getSetDir
211 	(Glib::filename_from_utf8(shield_theme_combobox->get_active_text()));
212 
213       map.cityset = Citysetlist::getInstance()->getSetDir
214 	(Glib::filename_from_utf8(city_theme_combobox->get_active_text()),
215 	 get_active_tile_size());
216 
217       map.armyset = Armysetlist::getInstance()->getSetDir
218 	(Glib::filename_from_utf8(army_theme_combobox->get_active_text()),
219 	 get_active_tile_size());
220 
221       if (map.fill_style == -1)
222 	{
223 	  map.grass = int(grass_scale->get_value());
224 	  map.water = int(water_scale->get_value());
225 	  map.swamp = int(swamp_scale->get_value());
226 	  map.forest = int(forest_scale->get_value());
227 	  map.hills = int(hills_scale->get_value());
228 	  map.mountains = int(mountains_scale->get_value());
229 	  map.cities = int(cities_scale->get_value());
230 	  map.ruins = int(ruins_scale->get_value());
231 	  map.temples = int(temples_scale->get_value());
232 	  map.signposts = int(signposts_scale->get_value());
233 	  map.stones = int(stones_scale->get_value());
234           map.generate_roads = random_roads_switch->get_active();
235           map.random_names = random_names_switch->get_active();
236           map.stone_road_chance = int(stone_road_spinbutton->get_value());
237 	}
238       map.num_players = int(num_players_spinbutton->get_value());
239       map_set = true;
240     }
241   else
242     map_set = false;
243 }
244 
on_fill_style_changed()245 void NewMapDialog::on_fill_style_changed()
246 {
247   int row = fill_style_combobox->get_active_row_number();
248   assert(row >= 0 && row < int(fill_style.size()));
249   bool random_selected = fill_style[row] == -1;
250   random_map_container->set_sensitive(random_selected);
251   random_roads_switch->set_sensitive(random_selected);
252   random_names_switch->set_sensitive(random_selected);
253   update_button ();
254 }
255 
on_map_size_changed()256 void NewMapDialog::on_map_size_changed()
257 {
258   switch (map_size_combobox->get_active_row_number()) {
259   case MAP_SIZE_SMALL:
260     width_spinbutton->set_value (MAP_SIZE_SMALL_WIDTH);
261     height_spinbutton->set_value (MAP_SIZE_SMALL_HEIGHT);
262     cities_scale->set_value(15);
263     ruins_scale->set_value(20);
264     temples_scale->set_value(20);
265     width_spinbutton->set_sensitive (false);
266     height_spinbutton->set_sensitive (false);
267     break;
268 
269   case MAP_SIZE_TINY:
270     width_spinbutton->set_value (MAP_SIZE_TINY_WIDTH);
271     height_spinbutton->set_value (MAP_SIZE_TINY_HEIGHT);
272     cities_scale->set_value(10);
273     ruins_scale->set_value(15);
274     temples_scale->set_value(15);
275     width_spinbutton->set_sensitive (false);
276     height_spinbutton->set_sensitive (false);
277     break;
278 
279   case MAP_SIZE_NORMAL:
280   default:
281     width_spinbutton->set_value (MAP_SIZE_NORMAL_WIDTH);
282     height_spinbutton->set_value (MAP_SIZE_NORMAL_HEIGHT);
283     cities_scale->set_value(20);
284     ruins_scale->set_value(25);
285     temples_scale->set_value(25);
286     width_spinbutton->set_sensitive (false);
287     height_spinbutton->set_sensitive (false);
288     break;
289   case MAP_SIZE_CUSTOM:
290     width_spinbutton->set_value (MAP_SIZE_NORMAL_WIDTH);
291     height_spinbutton->set_value (MAP_SIZE_NORMAL_HEIGHT);
292     cities_scale->set_value(20);
293     ruins_scale->set_value(25);
294     temples_scale->set_value(25);
295     width_spinbutton->set_sensitive (true);
296     height_spinbutton->set_sensitive (true);
297     break;
298   }
299 }
300 
add_fill_style(Tile::Type tile_type)301 void NewMapDialog::add_fill_style(Tile::Type tile_type)
302 {
303   Tileset *tileset = GameMap::getTileset();
304   Tile *tile = (*tileset)[tileset->getIndex(tile_type)];
305   fill_style_combobox->append(tile->getName());
306   fill_style.push_back(tile_type);
307 }
308 
get_active_tile_size()309 guint32 NewMapDialog::get_active_tile_size()
310 {
311   return (guint32) atoi(tile_size_combobox->get_active_text().c_str());
312 }
313 
on_tile_size_changed()314 void NewMapDialog::on_tile_size_changed()
315 {
316   guint32 default_id = 0;
317   guint32 counter = 0;
318 
319   tile_theme_combobox->remove_all();
320   Tilesetlist *tl = Tilesetlist::getInstance();
321   std::list<Glib::ustring> tile_themes = tl->getValidNames(get_active_tile_size());
322   for (std::list<Glib::ustring>::iterator i = tile_themes.begin(),
323        end = tile_themes.end(); i != end; ++i)
324     {
325       if (*i == _("Default"))
326 	default_id = counter;
327       tile_theme_combobox->append(Glib::filename_to_utf8(*i));
328       counter++;
329     }
330 
331   tile_theme_combobox->set_active(default_id);
332 
333   army_theme_combobox->remove_all();
334   Armysetlist *al = Armysetlist::getInstance();
335   std::list<Glib::ustring> army_themes = al->getValidNames(get_active_tile_size());
336   counter = 0;
337   default_id = 0;
338   for (std::list<Glib::ustring>::iterator i = army_themes.begin(),
339        end = army_themes.end(); i != end; ++i)
340     {
341       if (*i == _("Default"))
342 	default_id = counter;
343       army_theme_combobox->append(Glib::filename_to_utf8(*i));
344       counter++;
345     }
346 
347   army_theme_combobox->set_active(default_id);
348 
349   city_theme_combobox->remove_all();
350   Citysetlist *cl = Citysetlist::getInstance();
351   std::list<Glib::ustring> city_themes = cl->getValidNames(get_active_tile_size());
352   counter = 0;
353   default_id = 0;
354   for (std::list<Glib::ustring>::iterator i = city_themes.begin(),
355        end = city_themes.end(); i != end; ++i)
356     {
357       if (*i == _("Default"))
358 	default_id = counter;
359       city_theme_combobox->append(Glib::filename_to_utf8(*i));
360       counter++;
361     }
362 
363   city_theme_combobox->set_active(default_id);
364   update_button ();
365 }
366 
update_button()367 void NewMapDialog::update_button ()
368 {
369   bool sens = true;
370   if (city_theme_combobox->get_model()->children().size() == 0 ||
371       army_theme_combobox->get_model()->children().size() == 0 ||
372       tile_theme_combobox->get_model()->children().size() == 0)
373     sens = false;
374 
375   if (fill_style_combobox)
376     {
377       int row = fill_style_combobox->get_active_row_number();
378       assert(row >= 0 && row < int(fill_style.size()));
379       bool random_selected = fill_style[row] == -1;
380       if (random_selected)
381         accept_button->set_label (_("Create Random Map"));
382       else
383         {
384           switch (Tile::Type (fill_style[row]))
385             {
386             case Tile::GRASS:
387               accept_button->set_label (_("Create Grass Map"));
388               break;
389             case Tile::WATER:
390               accept_button->set_label (_("Create Water Map"));
391               break;
392             case Tile::FOREST:
393               accept_button->set_label (_("Create Forest Map"));
394               break;
395             case Tile::HILLS:
396               accept_button->set_label (_("Create Hills Map"));
397               break;
398             case Tile::MOUNTAIN:
399               accept_button->set_label (_("Create Mountains Map"));
400               break;
401             case Tile::SWAMP:
402               accept_button->set_label (_("Create Swamp Map"));
403               break;
404             }
405         }
406     }
407   accept_button->set_sensitive(sens);
408 }
409 
on_random_roads_toggled()410 void NewMapDialog::on_random_roads_toggled ()
411 {
412   stone_road_spinbutton->set_sensitive (random_roads_switch->get_active ());
413 }
414 
setup_progress_bar()415 void NewMapDialog::setup_progress_bar ()
416 {
417   progress_treeview = Gtk::manage (new Gtk::TreeView ());
418   progress_treeview->property_headers_visible () = false;
419   progress_liststore = Gtk::ListStore::create(progress_columns);
420   progress_treeview->set_model (progress_liststore);
421   progress_row = *(progress_liststore->append());
422   auto cell = Gtk::manage(new Gtk::CellRendererProgress());
423   cell->property_text () = "";
424   int cols_count = progress_treeview->append_column ("progress", *cell);
425   auto pColumn = progress_treeview->get_column(cols_count -1);
426   if (pColumn)
427     pColumn->add_attribute(cell->property_value (), progress_columns.perc);
428 
429   dialog_vbox->pack_end (*progress_treeview, true, true);
430   dialog_vbox->show_all ();
431   while (g_main_context_iteration(NULL, FALSE)); //doEvents
432   dialog_vbox->set_sensitive(false);
433 }
434 
tick_progress(double p)435 void NewMapDialog::tick_progress (double p)
436 {
437   if (!progress_treeview)
438     return;
439   progress_row[progress_columns.perc] = p * 100.0;
440   while (g_main_context_iteration(NULL, FALSE)); //doEvents
441 }
442 
~NewMapDialog()443 NewMapDialog::~NewMapDialog()
444 {
445   notebook->property_show_tabs () = false;
446 }
447