1 // Copyright (C) 2008, 2009, 2010, 2012, 2014, 2020 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 <gtkmm.h>
21 #include <sigc++/functors/mem_fun.h>
22
23 #include "tileset-selector-editor-dialog.h"
24
25 #include "ucompose.hpp"
26 #include "defs.h"
27 #include "File.h"
28 #include "shieldsetlist.h"
29 #include "ImageCache.h"
30 #include "tileset-window.h"
31 #include "past-chooser.h"
32 #include "font-size.h"
33 #include "image-file-filter.h"
34 #include "timed-message-dialog.h"
35
36 #define method(x) sigc::mem_fun(*this, &TilesetSelectorEditorDialog::x)
37
TilesetSelectorEditorDialog(Gtk::Window & parent,Tileset * tileset)38 TilesetSelectorEditorDialog::TilesetSelectorEditorDialog(Gtk::Window &parent, Tileset *tileset)
39 : LwEditorDialog(parent, "tileset-selector-editor-dialog.ui")
40 {
41 d_changed = false;
42 bool broken = false;
43 d_tileset = tileset;
44 Glib::ustring imgname = d_tileset->getSmallSelectorFilename();
45 if (imgname.empty() == false)
46 {
47 Glib::ustring f = d_tileset->getFileFromConfigurationFile(imgname);
48 small_selector = PixMask::create (f, broken);
49 }
50 else
51 small_selector = NULL;
52 imgname = d_tileset->getLargeSelectorFilename();
53 if (imgname.empty() == false)
54 {
55 Glib::ustring f = d_tileset->getFileFromConfigurationFile(imgname);
56 large_selector = PixMask::create (f, broken);
57 }
58 else
59 large_selector = NULL;
60
61 Gtk::Box *box;
62 xml->get_widget("shieldset_box", box);
63 setup_shield_theme_combobox(box);
64 xml->get_widget("preview_table", preview_table);
65
66 xml->get_widget("large_selector_radiobutton", large_selector_radiobutton);
67 large_selector_radiobutton->signal_toggled().connect (method(on_button_toggle));
68 xml->get_widget("small_selector_radiobutton", small_selector_radiobutton);
69 small_selector_radiobutton->signal_toggled().connect (method(on_button_toggle));
70 xml->get_widget("selector_imagebutton", selector_imagebutton);
71 selector_imagebutton->signal_clicked().connect (method(on_selector_imagebutton_clicked));
72
73 show_preview_selectors();
74 update_selector_panel();
75 }
76
on_button_toggle()77 void TilesetSelectorEditorDialog::on_button_toggle ()
78 {
79 show_preview_selectors();
80 update_selector_panel();
81 }
82
run()83 bool TilesetSelectorEditorDialog::run()
84 {
85 dialog->show_all();
86 dialog->run();
87 dialog->hide ();
88 return d_changed;
89 }
90
setup_shield_theme_combobox(Gtk::Box * box)91 void TilesetSelectorEditorDialog::setup_shield_theme_combobox(Gtk::Box *box)
92 {
93 // fill in shield themes combobox
94 shield_theme_combobox = manage(new Gtk::ComboBoxText);
95
96 Shieldsetlist *sl = Shieldsetlist::getInstance();
97 std::list<Glib::ustring> shield_themes = sl->getValidNames();
98 int counter = 0;
99 int default_id = 0;
100 for (std::list<Glib::ustring>::iterator i = shield_themes.begin(),
101 end = shield_themes.end(); i != end; ++i)
102 {
103 if (*i == _("Default"))
104 default_id = counter;
105 shield_theme_combobox->append(Glib::filename_to_utf8(*i));
106 counter++;
107 }
108
109 shield_theme_combobox->set_active(default_id);
110 shield_theme_combobox->signal_changed().connect (method(on_shieldset_changed));
111
112 box->set_center_widget (*shield_theme_combobox);
113 }
114
on_shieldset_changed()115 void TilesetSelectorEditorDialog::on_shieldset_changed()
116 {
117 show_preview_selectors();
118 }
119
load_selector_image(Glib::ustring filename)120 bool TilesetSelectorEditorDialog::load_selector_image (Glib::ustring filename)
121 {
122 bool broken = false;
123 if (large_selector_radiobutton->get_active() == true)
124 {
125 if (large_selector)
126 delete large_selector;
127 large_selector = PixMask::create (filename, broken);
128 }
129 else if (small_selector_radiobutton->get_active() == true)
130 {
131 if (small_selector)
132 delete small_selector;
133 small_selector = PixMask::create (filename, broken);
134 }
135 return false;
136 }
137
on_image_chosen(Gtk::FileChooserDialog * d)138 bool TilesetSelectorEditorDialog::on_image_chosen (Gtk::FileChooserDialog *d)
139 {
140 bool broken = load_selector_image (d->get_filename ());
141 if (!broken)
142 {
143 Glib::ustring imgname = get_selector_filename ();
144 Glib::ustring newname = "";
145 bool success = false;
146 if (imgname.empty() == true)
147 success =
148 d_tileset->addFileInCfgFile(d->get_filename(), newname);
149 else
150 success =
151 d_tileset->replaceFileInCfgFile(imgname, d->get_filename(), newname);
152 if (success)
153 {
154 set_selector_filename (newname);
155 d_changed = true;
156 show_preview_selectors ();
157 update_selector_panel();
158 }
159 else
160 {
161 Glib::ustring errmsg = Glib::strerror(errno);
162 TimedMessageDialog
163 td(*d, String::ucompose(_("Couldn't add %1 to :\n%2\n%3"),
164 d->get_filename (),
165 d_tileset->getConfigurationFile(),
166 errmsg), 0);
167 td.run_and_hide ();
168 broken = true;
169 }
170 }
171 else
172 {
173 TimedMessageDialog
174 td(*d, String::ucompose(_("Couldn't make sense of the image:\n%1"),
175 d->get_filename ()), 0);
176 td.run_and_hide ();
177 broken = true;
178 }
179 return broken;
180 }
181
show_preview_selectors()182 void TilesetSelectorEditorDialog::show_preview_selectors()
183 {
184 //load it up and show in the colours of the selected shield theme
185 clearSelector();
186 if (loadSelector () == true)
187 {
188 on_heartbeat ();
189 heartbeat = Glib::signal_timeout().connect
190 (sigc::bind_return (method (on_heartbeat), true),
191 TIMER_BIGMAP_SELECTOR);
192 }
193 }
194
clearSelector()195 void TilesetSelectorEditorDialog::clearSelector()
196 {
197 if (heartbeat.connected())
198 heartbeat.disconnect();
199
200 for (std::map< guint32, std::list<Glib::RefPtr<Gdk::Pixbuf> >* >::iterator it = selectors.begin();
201 it != selectors.end(); it++)
202 {
203 for (std::list<Glib::RefPtr<Gdk::Pixbuf> >::iterator lit =
204 (*it).second->begin(); lit != (*it).second->end(); lit++)
205 {
206 (*lit).clear();
207 }
208 (*it).second->clear();
209 delete ((*it).second);
210 }
211 selectors.clear();
212 preview_table->foreach(sigc::mem_fun(preview_table, &Gtk::Container::remove));
213 }
214
loadSelector()215 bool TilesetSelectorEditorDialog::loadSelector()
216 {
217 std::vector<PixMask *> images;
218 std::vector<PixMask *> masks;
219 PixMask *p = NULL;
220 if (large_selector_radiobutton->get_active() == true)
221 p = large_selector;
222 else if (small_selector_radiobutton->get_active() == true)
223 p = small_selector;
224 if (!p)
225 return false;
226 if (p->get_unscaled_height () == 0)
227 return false;
228 bool success =
229 SelectorPixMaskCacheItem::loadSelectors(p, d_tileset->getTileSize(),
230 images, masks, false);
231 if (success)
232 {
233 Glib::ustring n = shield_theme_combobox->get_active_text();
234 Shieldset *shieldset = Shieldsetlist::getInstance()->get(n, 0);
235
236 for (unsigned int i = 0; i < MAX_PLAYERS; i++)
237 {
238 std::list<Glib::RefPtr<Gdk::Pixbuf> > *mylist =
239 new std::list<Glib::RefPtr<Gdk::Pixbuf> >();
240 selectors[i] = mylist;
241 }
242
243 for (std::vector<PixMask*>::iterator it = images.begin(),
244 mit = masks.begin(); it != images.end(); it++, mit++)
245 {
246 for (Shieldset::iterator sit = shieldset->begin();
247 sit != shieldset->end(); sit++)
248 {
249 if ((*sit)->getOwner() == 8) //ignore neutral
250 continue;
251 PixMask *q =
252 ImageCache::applyMask(*it, *mit, (*sit)->getColor());
253 double ratio = EDITOR_DIALOG_TILE_PIC_FONTSIZE_MULTIPLE;
254 int font_size = FontSize::getInstance()->get_height ();
255 double new_height = font_size * ratio;
256 int new_width =
257 ImageCache::calculate_width_from_adjusted_height
258 (q, new_height);
259 PixMask::scale (q, new_width, new_height);
260 selectors[(*sit)->getOwner()]->push_back (q->to_pixbuf ());
261
262 frame[(*sit)->getOwner()] =
263 selectors[(*sit)->getOwner()]->begin();
264 }
265 }
266
267 for (std::vector<PixMask*>::iterator it = images.begin();
268 it != images.end(); it++)
269 delete *it;
270 for (std::vector<PixMask*>::iterator it = masks.begin();
271 it != masks.end(); it++)
272 delete *it;
273 }
274
275 return success;
276 }
277
on_heartbeat()278 void TilesetSelectorEditorDialog::on_heartbeat()
279 {
280 preview_table->foreach(sigc::mem_fun(preview_table, &Gtk::Container::remove));
281 for (int i = 0; i < 4; i++)
282 preview_table->insert_row (i);
283 for (int i = 0; i < 2; i++)
284 preview_table->insert_column (i);
285
286 int x = 0;
287 int y = 0;
288 int count = 0;
289 for (std::map< guint32, std::list<Glib::RefPtr<Gdk::Pixbuf> >* >::iterator it = selectors.begin();
290 it != selectors.end(); it++)
291 {
292 //make a pixbuf and attach it
293 switch (count)
294 {
295 case 0: x = 0; y = 0; break;
296 case 1: x = 0; y = 1; break;
297 case 2: x = 0; y = 2; break;
298 case 3: x = 0; y = 3; break;
299 case 4: x = 1; y = 0; break;
300 case 5: x = 1; y = 1; break;
301 case 6: x = 1; y = 2; break;
302 case 7: x = 1; y = 3; break;
303 }
304 preview_table->attach(*manage(new Gtk::Image(*frame[count])), y, x, 1, 1);
305
306 frame[count]++;
307 if (frame[count] == selectors[count]->end())
308 frame[count] = selectors[count]->begin();
309 count++;
310 }
311 preview_table->show_all();
312 }
313
update_selector_panel()314 void TilesetSelectorEditorDialog::update_selector_panel()
315 {
316 Glib::ustring f = get_selector_filename ();
317 if (f.empty () == false)
318 selector_imagebutton->set_label (f);
319 else
320 {
321 selector_imagebutton->set_label (_("no image set"));
322 clearSelector();
323 }
324 }
325
image_filechooser(bool clear)326 Gtk::FileChooserDialog* TilesetSelectorEditorDialog::image_filechooser(bool clear)
327 {
328 Glib::ustring filename = "";
329 Glib::ustring title = "";
330 if (large_selector_radiobutton->get_active() == true)
331 title = _("Choose a large selector image");
332 else if (small_selector_radiobutton->get_active() == true)
333 title = _("Choose a small selector image");
334 Gtk::FileChooserDialog *d = new Gtk::FileChooserDialog(*dialog, title);
335 ImageFileFilter::getInstance ()->add (d);
336 d->add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
337 d->add_button(Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
338 if (clear)
339 d->add_button(Gtk::Stock::CLEAR, Gtk::RESPONSE_REJECT);
340 d->set_default_response(Gtk::RESPONSE_ACCEPT);
341 d->set_current_folder(PastChooser::getInstance()->get_dir(d));
342 return d;
343 }
344
get_selector_filename()345 Glib::ustring TilesetSelectorEditorDialog::get_selector_filename ()
346 {
347 if (large_selector_radiobutton->get_active() == true)
348 return d_tileset->getLargeSelectorFilename ();
349 else if (small_selector_radiobutton->get_active() == true)
350 return d_tileset->getSmallSelectorFilename ();
351 return "";
352 }
353
set_selector_filename(Glib::ustring f)354 void TilesetSelectorEditorDialog::set_selector_filename (Glib::ustring f)
355 {
356 if (large_selector_radiobutton->get_active() == true)
357 {
358 d_tileset->setLargeSelectorFilename (f);
359 if (f.empty () == false)
360 d_tileset->instantiateLargeSelectorImages();
361 }
362 else if (small_selector_radiobutton->get_active() == true)
363 {
364 d_tileset->setSmallSelectorFilename (f);
365 if (f.empty () == false)
366 d_tileset->instantiateSmallSelectorImages();
367 }
368 return ;
369 }
370
clear_selector_image()371 void TilesetSelectorEditorDialog::clear_selector_image ()
372 {
373 if (large_selector_radiobutton->get_active() == true)
374 {
375 if (large_selector)
376 delete large_selector;
377 large_selector = NULL;
378 d_tileset->clearLargeSelectorImage();
379 }
380 else if (small_selector_radiobutton->get_active() == true)
381 {
382 if (small_selector)
383 delete small_selector;
384 small_selector = NULL;
385 d_tileset->clearSmallSelectorImage();
386 }
387 return;
388 }
389
on_selector_imagebutton_clicked()390 void TilesetSelectorEditorDialog::on_selector_imagebutton_clicked ()
391 {
392 Glib::ustring f = get_selector_filename ();
393 Glib::ustring filename = "";
394 Gtk::FileChooserDialog *d = image_filechooser(f != "");
395 if (f != "")
396 filename = d_tileset->getFileFromConfigurationFile(f);
397 int response = d->run();
398 if (filename != "")
399 File::erase(filename);
400 if (response == Gtk::RESPONSE_ACCEPT && d->get_filename() != "")
401 {
402 if (ImageFileFilter::getInstance ()->hasInvalidExt (d->get_filename ()))
403 ImageFileFilter::getInstance ()->showErrorDialog (d);
404 else
405 {
406 if (d->get_filename() != filename)
407 {
408 PastChooser::getInstance()->set_dir(d);
409 on_image_chosen (d);
410 }
411 }
412 }
413 else if (response == Gtk::RESPONSE_REJECT && f != "")
414 {
415 if (d_tileset->removeFileInCfgFile(f))
416 {
417 d_changed = true;
418 d_tileset->uninstantiateSameNamedImages (f);
419 update_selector_panel ();
420 }
421 else
422 {
423 Glib::ustring errmsg = Glib::strerror(errno);
424 TimedMessageDialog
425 td(*d, String::ucompose(_("Couldn't remove %1 from:\n%2\n%3"),
426 f, d_tileset->getConfigurationFile(),
427 errmsg), 0);
428 td.run_and_hide ();
429 }
430 }
431 d->hide();
432 delete d;
433 }
434
~TilesetSelectorEditorDialog()435 TilesetSelectorEditorDialog::~TilesetSelectorEditorDialog()
436 {
437 if (small_selector)
438 delete small_selector;
439 if (large_selector)
440 delete large_selector;
441 }
442