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