1 //  SuperTux
2 //  Copyright (C) 2015 Hume2 <teratux.mail@gmail.com>
3 //
4 //  This program is free software: you can redistribute it and/or modify
5 //  it under the terms of the GNU General Public License as published by
6 //  the Free Software Foundation, either version 3 of the License, or
7 //  (at your option) any later version.
8 //
9 //  This program is distributed in the hope that it will be useful,
10 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
11 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 //  GNU General Public License for more details.
13 //
14 //  You should have received a copy of the GNU General Public License
15 //  along with this program.  If not, see <http://www.gnu.org/licenses/>.
16 
17 #include "editor/object_option.hpp"
18 
19 #include <string>
20 #include <utility>
21 
22 #include <vector>
23 #include <sstream>
24 
25 #include "editor/object_menu.hpp"
26 #include "gui/menu.hpp"
27 #include "object/tilemap.hpp"
28 #include "util/gettext.hpp"
29 #include "util/writer.hpp"
30 #include "video/color.hpp"
31 
32 namespace {
33 
34 template<typename T>
fmt_to_string(const T & v)35 std::string fmt_to_string(const T& v)
36 {
37   std::ostringstream out;
38   out << v;
39   return out.str();
40 }
41 
42 } // namespace
43 
ObjectOption(const std::string & text,const std::string & key,unsigned int flags)44 ObjectOption::ObjectOption(const std::string& text, const std::string& key, unsigned int flags) :
45   m_text(text),
46   m_key(key),
47   m_flags(flags)
48 {
49 }
50 
~ObjectOption()51 ObjectOption::~ObjectOption()
52 {
53 }
54 
BoolObjectOption(const std::string & text,bool * pointer,const std::string & key,boost::optional<bool> default_value,unsigned int flags)55 BoolObjectOption::BoolObjectOption(const std::string& text, bool* pointer, const std::string& key,
56                                    boost::optional<bool> default_value,
57                                    unsigned int flags) :
58   ObjectOption(text, key, flags),
59   m_pointer(pointer),
60   m_default_value(std::move(default_value))
61 {
62 }
63 
64 void
add_to_menu(Menu & menu) const65 BoolObjectOption::add_to_menu(Menu& menu) const
66 {
67   menu.add_toggle(-1, get_text(), m_pointer);
68 }
69 
70 void
save(Writer & writer) const71 BoolObjectOption::save(Writer& writer) const
72 {
73   if (!get_key().empty()) {
74     if (m_default_value && *m_default_value == *m_pointer) {
75       // skip
76     } else {
77       writer.write(get_key(), *m_pointer);
78     }
79   }
80 }
81 
82 std::string
to_string() const83 BoolObjectOption::to_string() const
84 {
85   return *m_pointer ? _("true") : _("false");
86 }
87 
IntObjectOption(const std::string & text,int * pointer,const std::string & key,boost::optional<int> default_value,unsigned int flags)88 IntObjectOption::IntObjectOption(const std::string& text, int* pointer, const std::string& key,
89                                  boost::optional<int> default_value,
90                                  unsigned int flags) :
91   ObjectOption(text, key, flags),
92   m_pointer(pointer),
93   m_default_value(std::move(default_value))
94 {
95 }
96 
97 void
save(Writer & writer) const98 IntObjectOption::save(Writer& writer) const
99 {
100   if (!get_key().empty()) {
101     if (m_default_value && *m_default_value == *m_pointer) {
102       // skip
103     } else {
104       writer.write(get_key(), *m_pointer);
105     }
106   }
107 }
108 
109 std::string
to_string() const110 IntObjectOption::to_string() const
111 {
112   return fmt_to_string(*m_pointer);
113 }
114 
115 void
add_to_menu(Menu & menu) const116 IntObjectOption::add_to_menu(Menu& menu) const
117 {
118   menu.add_intfield(get_text(), m_pointer);
119 }
120 
LabelObjectOption(const std::string & text,unsigned int flags)121 LabelObjectOption::LabelObjectOption(const std::string& text,
122                                  unsigned int flags) :
123   ObjectOption(text, "", flags)
124 {
125 }
126 
127 void
save(Writer & writer) const128 LabelObjectOption::save(Writer& writer) const
129 {
130 }
131 
132 std::string
to_string() const133 LabelObjectOption::to_string() const
134 {
135   return "";
136 }
137 
138 void
add_to_menu(Menu & menu) const139 LabelObjectOption::add_to_menu(Menu& menu) const
140 {
141   menu.add_label(m_text);
142 }
143 
RectfObjectOption(const std::string & text,Rectf * pointer,const std::string & key,unsigned int flags)144 RectfObjectOption::RectfObjectOption(const std::string& text, Rectf* pointer, const std::string& key,
145                                      unsigned int flags) :
146   ObjectOption(text, key, flags),
147   m_pointer(pointer),
148   m_width(m_pointer->get_width()),
149   m_height(m_pointer->get_height())
150 {
151 }
152 
153 void
save(Writer & write) const154 RectfObjectOption::save(Writer& write) const
155 {
156   write.write("width", m_width);
157   write.write("height", m_height);
158   // write.write("x", &pointer->p1.x);
159   // write.write("y", &pointer->p1.y);
160 }
161 
162 std::string
to_string() const163 RectfObjectOption::to_string() const
164 {
165   std::ostringstream out;
166   out << *m_pointer;
167   return out.str();
168 }
169 
170 void
add_to_menu(Menu & menu) const171 RectfObjectOption::add_to_menu(Menu& menu) const
172 {
173   menu.add_floatfield(_("Width"), const_cast<float*>(&m_width));
174   menu.add_floatfield(_("Height"), const_cast<float*>(&m_height));
175 }
176 
FloatObjectOption(const std::string & text,float * pointer,const std::string & key,boost::optional<float> default_value,unsigned int flags)177 FloatObjectOption::FloatObjectOption(const std::string& text, float* pointer, const std::string& key,
178                                      boost::optional<float> default_value,
179                                      unsigned int flags) :
180   ObjectOption(text, key, flags),
181   m_pointer(pointer),
182   m_default_value(std::move(default_value))
183 {
184 }
185 
186 void
save(Writer & writer) const187 FloatObjectOption::save(Writer& writer) const
188 {
189   if (!get_key().empty()) {
190     if (m_default_value && *m_default_value == *m_pointer) {
191       // skip
192     } else {
193       writer.write(get_key(), *m_pointer);
194     }
195   }
196 }
197 
198 std::string
to_string() const199 FloatObjectOption::to_string() const
200 {
201   return fmt_to_string(*m_pointer);
202 }
203 
204 void
add_to_menu(Menu & menu) const205 FloatObjectOption::add_to_menu(Menu& menu) const
206 {
207   menu.add_floatfield(get_text(), m_pointer);
208 }
209 
StringObjectOption(const std::string & text,std::string * pointer,const std::string & key,boost::optional<std::string> default_value,unsigned int flags)210 StringObjectOption::StringObjectOption(const std::string& text, std::string* pointer, const std::string& key,
211                                        boost::optional<std::string> default_value,
212                                        unsigned int flags) :
213   ObjectOption(text, key, flags),
214   m_pointer(pointer),
215   m_default_value(std::move(default_value))
216 {
217 }
218 
219 void
save(Writer & writer) const220 StringObjectOption::save(Writer& writer) const
221 {
222   if (!get_key().empty()) {
223     if ((m_default_value && *m_default_value == *m_pointer) || m_pointer->empty()) {
224       // skip
225     } else {
226       writer.write(get_key(), *m_pointer, (get_flags() & OPTION_TRANSLATABLE));
227     }
228   }
229 }
230 
231 std::string
to_string() const232 StringObjectOption::to_string() const
233 {
234   return *m_pointer;
235 }
236 
237 void
add_to_menu(Menu & menu) const238 StringObjectOption::add_to_menu(Menu& menu) const
239 {
240   menu.add_textfield(get_text(), m_pointer);
241 }
242 
StringSelectObjectOption(const std::string & text,int * pointer,const std::vector<std::string> & select,boost::optional<int> default_value,const std::string & key,unsigned int flags)243 StringSelectObjectOption::StringSelectObjectOption(const std::string& text, int* pointer,
244                                                    const std::vector<std::string>& select,
245                                                    boost::optional<int> default_value,
246                                                    const std::string& key, unsigned int flags) :
247   ObjectOption(text, key, flags),
248   m_pointer(pointer),
249   m_select(select),
250   m_default_value(std::move(default_value))
251 {
252 }
253 
254 void
save(Writer & writer) const255 StringSelectObjectOption::save(Writer& writer) const
256 {
257   if (!get_key().empty()) {
258     if (m_default_value && *m_default_value == *m_pointer) {
259       // skip
260     } else {
261       writer.write(get_key(), *m_pointer);
262     }
263   }
264 }
265 
266 std::string
to_string() const267 StringSelectObjectOption::to_string() const
268 {
269   int* selected_id = static_cast<int*>(m_pointer);
270   if (*selected_id >= int(m_select.size()) || *selected_id < 0) {
271     return _("invalid"); //Test whether the selected ID is valid
272   } else {
273     return m_select[*selected_id];
274   }
275 }
276 
277 void
add_to_menu(Menu & menu) const278 StringSelectObjectOption::add_to_menu(Menu& menu) const
279 {
280   int& selected_id = *m_pointer;
281   if ( selected_id >= static_cast<int>(m_select.size()) || selected_id < 0 ) {
282     selected_id = 0; // Set the option to zero when not selectable
283   }
284   menu.add_string_select(-1, get_text(), m_pointer, m_select);
285 }
286 
EnumObjectOption(const std::string & text,int * pointer,const std::vector<std::string> & labels,const std::vector<std::string> & symbols,boost::optional<int> default_value,const std::string & key,unsigned int flags)287 EnumObjectOption::EnumObjectOption(const std::string& text, int* pointer,
288                                    const std::vector<std::string>& labels,
289                                    const std::vector<std::string>& symbols,
290                                    boost::optional<int> default_value,
291                                    const std::string& key, unsigned int flags) :
292   ObjectOption(text, key, flags),
293   m_pointer(pointer),
294   m_labels(labels),
295   m_symbols(symbols),
296   m_default_value(std::move(default_value))
297 {
298 }
299 
300 void
save(Writer & writer) const301 EnumObjectOption::save(Writer& writer) const
302 {
303   if (0 <= *m_pointer && *m_pointer < int(m_symbols.size()) &&
304       !get_key().empty())
305   {
306     if (m_default_value && *m_default_value == *m_pointer) {
307       // skip
308     } else {
309       writer.write(get_key(), m_symbols[*m_pointer]);
310     }
311   }
312 }
313 
314 std::string
to_string() const315 EnumObjectOption::to_string() const
316 {
317   if (0 <= *m_pointer && *m_pointer < int(m_labels.size())) {
318     return m_labels[*m_pointer];
319   } else {
320     return _("invalid");
321   }
322 }
323 
324 void
add_to_menu(Menu & menu) const325 EnumObjectOption::add_to_menu(Menu& menu) const
326 {
327   if (*m_pointer >= static_cast<int>(m_labels.size()) || *m_pointer < 0 ) {
328     *m_pointer = 0; // Set the option to zero when not selectable
329   }
330   menu.add_string_select(-1, get_text(), m_pointer, m_labels);
331 }
332 
333 
ScriptObjectOption(const std::string & text,std::string * pointer,const std::string & key,unsigned int flags)334 ScriptObjectOption::ScriptObjectOption(const std::string& text, std::string* pointer, const std::string& key,
335                                        unsigned int flags) :
336   ObjectOption(text, key, flags),
337   m_pointer(pointer)
338 {
339 }
340 
341 void
save(Writer & writer) const342 ScriptObjectOption::save(Writer& writer) const
343 {
344   auto& value = *m_pointer;
345   if (!value.empty())
346   {
347     if (!get_key().empty()) {
348       writer.write(get_key(), value);
349     }
350   }
351 }
352 
353 std::string
to_string() const354 ScriptObjectOption::to_string() const
355 {
356   if (!m_pointer->empty()) {
357     return "...";
358   }
359   return "";
360 }
361 
362 void
add_to_menu(Menu & menu) const363 ScriptObjectOption::add_to_menu(Menu& menu) const
364 {
365   menu.add_script(get_text(), m_pointer);
366 }
367 
FileObjectOption(const std::string & text,std::string * pointer,boost::optional<std::string> default_value,const std::string & key,std::vector<std::string> filter,const std::string & basedir,unsigned int flags)368 FileObjectOption::FileObjectOption(const std::string& text, std::string* pointer,
369                                    boost::optional<std::string> default_value,
370                                    const std::string& key,
371                                    std::vector<std::string> filter,
372                                    const std::string& basedir,
373                                    unsigned int flags) :
374   ObjectOption(text, key, flags),
375   m_pointer(pointer),
376   m_default_value(std::move(default_value)),
377   m_filter(std::move(filter)),
378   m_basedir(basedir)
379 {
380 }
381 
382 void
save(Writer & writer) const383 FileObjectOption::save(Writer& writer) const
384 {
385   if (m_default_value && *m_default_value == *m_pointer) {
386     // skip
387   } else {
388     auto& value = *m_pointer;
389     if (!value.empty())
390     {
391       if (!get_key().empty()) {
392         writer.write(get_key(), value);
393       }
394     }
395   }
396 }
397 
398 std::string
to_string() const399 FileObjectOption::to_string() const
400 {
401   return *m_pointer;
402 }
403 
404 void
add_to_menu(Menu & menu) const405 FileObjectOption::add_to_menu(Menu& menu) const
406 {
407   menu.add_file(get_text(), m_pointer, m_filter, m_basedir);
408 }
409 
ColorObjectOption(const std::string & text,Color * pointer,const std::string & key,boost::optional<Color> default_value,bool use_alpha,unsigned int flags)410 ColorObjectOption::ColorObjectOption(const std::string& text, Color* pointer, const std::string& key,
411                                      boost::optional<Color> default_value, bool use_alpha,
412                                      unsigned int flags) :
413   ObjectOption(text, key, flags),
414   m_pointer(pointer),
415   m_default_value(std::move(default_value)),
416   m_use_alpha(use_alpha)
417 {
418 }
419 
420 void
save(Writer & writer) const421 ColorObjectOption::save(Writer& writer) const
422 {
423   if (!get_key().empty()) {
424     if (m_default_value && *m_default_value == *m_pointer) {
425       // skip
426     } else {
427       auto vec = m_pointer->toVector();
428       if (!m_use_alpha || vec.back() == 1.0f) {
429         vec.pop_back();
430       }
431       writer.write(get_key(), vec);
432     }
433   }
434 }
435 
436 std::string
to_string() const437 ColorObjectOption::to_string() const
438 {
439   return m_pointer->to_string();
440 }
441 
442 void
add_to_menu(Menu & menu) const443 ColorObjectOption::add_to_menu(Menu& menu) const
444 {
445   menu.add_color(get_text(), m_pointer);
446 }
447 
BadGuySelectObjectOption(const std::string & text,std::vector<std::string> * pointer,const std::string & key,unsigned int flags)448 BadGuySelectObjectOption::BadGuySelectObjectOption(const std::string& text, std::vector<std::string>* pointer, const std::string& key,
449                                                    unsigned int flags) :
450   ObjectOption(text, key, flags),
451   m_pointer(pointer)
452 {
453 }
454 
455 void
save(Writer & writer) const456 BadGuySelectObjectOption::save(Writer& writer) const
457 {
458   if (!get_key().empty()) {
459     writer.write(get_key(), *m_pointer);
460   }
461 }
462 
463 std::string
to_string() const464 BadGuySelectObjectOption::to_string() const
465 {
466   return fmt_to_string(m_pointer->size());
467 }
468 
469 void
add_to_menu(Menu & menu) const470 BadGuySelectObjectOption::add_to_menu(Menu& menu) const
471 {
472   menu.add_badguy_select(get_text(), m_pointer);
473 }
474 
TilesObjectOption(const std::string & text,TileMap * tilemap,const std::string & key,unsigned int flags)475 TilesObjectOption::TilesObjectOption(const std::string& text, TileMap* tilemap, const std::string& key,
476                                      unsigned int flags) :
477   ObjectOption(text, key, flags),
478   m_tilemap(tilemap)
479 {
480 }
481 
482 void
save(Writer & write) const483 TilesObjectOption::save(Writer& write) const
484 {
485   write.write("width", m_tilemap->get_width());
486   write.write("height", m_tilemap->get_height());
487   write.write("tiles", m_tilemap->get_tiles(), m_tilemap->get_width());
488 }
489 
490 std::string
to_string() const491 TilesObjectOption::to_string() const
492 {
493   return {};
494 }
495 
496 void
add_to_menu(Menu & menu) const497 TilesObjectOption::add_to_menu(Menu& menu) const
498 {
499 }
500 
PathObjectOption(const std::string & text,Path * path,const std::string & key,unsigned int flags)501 PathObjectOption::PathObjectOption(const std::string& text, Path* path, const std::string& key,
502                                    unsigned int flags) :
503   ObjectOption(text, key, flags),
504   m_path(path)
505 {
506 }
507 
508 void
save(Writer & write) const509 PathObjectOption::save(Writer& write) const
510 {
511   m_path->save(write);
512 }
513 
514 std::string
to_string() const515 PathObjectOption::to_string() const
516 {
517   return {};
518 }
519 
520 void
add_to_menu(Menu & menu) const521 PathObjectOption::add_to_menu(Menu& menu) const
522 {
523 }
524 
PathRefObjectOption(const std::string & text,PathObject & target,const std::string & path_ref,const std::string & key,unsigned int flags)525 PathRefObjectOption::PathRefObjectOption(const std::string& text, PathObject& target, const std::string& path_ref,
526                                          const std::string& key, unsigned int flags) :
527   ObjectOption(text, key, flags),
528   m_path_ref(path_ref),
529   m_target(target)
530 {
531 }
532 
533 void
save(Writer & writer) const534 PathRefObjectOption::save(Writer& writer) const
535 {
536   if (!m_path_ref.empty()) {
537     writer.write(get_key(), m_path_ref);
538   }
539 }
540 
541 std::string
to_string() const542 PathRefObjectOption::to_string() const
543 {
544   return m_path_ref;
545 }
546 
547 void
add_to_menu(Menu & menu) const548 PathRefObjectOption::add_to_menu(Menu& menu) const
549 {
550   menu.add_path_settings(m_text, m_target, m_path_ref);
551 }
552 
SExpObjectOption(const std::string & text,const std::string & key,sexp::Value & value,unsigned int flags)553 SExpObjectOption::SExpObjectOption(const std::string& text, const std::string& key, sexp::Value& value,
554                                    unsigned int flags) :
555   ObjectOption(text, key, flags),
556   m_sx(value)
557 {
558 }
559 
560 void
save(Writer & writer) const561 SExpObjectOption::save(Writer& writer) const
562 {
563   if (!m_sx.is_nil()) {
564     writer.write(get_key(), m_sx);
565   }
566 }
567 
568 std::string
to_string() const569 SExpObjectOption::to_string() const
570 {
571   return m_sx.str();
572 }
573 
574 void
add_to_menu(Menu & menu) const575 SExpObjectOption::add_to_menu(Menu& menu) const
576 {
577 }
578 
RemoveObjectOption()579 RemoveObjectOption::RemoveObjectOption() :
580   ObjectOption(_("Remove"), "", 0)
581 {
582 }
583 
584 std::string
to_string() const585 RemoveObjectOption::to_string() const
586 {
587   return {};
588 }
589 
590 void
add_to_menu(Menu & menu) const591 RemoveObjectOption::add_to_menu(Menu& menu) const
592 {
593   menu.add_entry(ObjectMenu::MNID_REMOVE, get_text());
594 }
595 
TestFromHereOption()596 TestFromHereOption::TestFromHereOption() :
597   ObjectOption(_("Test from here"), "", 0)
598 {
599 }
600 
601 std::string
to_string() const602 TestFromHereOption::to_string() const
603 {
604   return {};
605 }
606 
607 void
add_to_menu(Menu & menu) const608 TestFromHereOption::add_to_menu(Menu& menu) const
609 {
610   menu.add_entry(ObjectMenu::MNID_TEST_FROM_HERE, get_text());
611 }
612 
ParticleEditorOption()613 ParticleEditorOption::ParticleEditorOption() :
614   ObjectOption(_("Open Particle Editor"), "", 0)
615 {
616 }
617 
618 std::string
to_string() const619 ParticleEditorOption::to_string() const
620 {
621   return {};
622 }
623 
624 void
add_to_menu(Menu & menu) const625 ParticleEditorOption::add_to_menu(Menu& menu) const
626 {
627   menu.add_entry(ObjectMenu::MNID_OPEN_PARTICLE_EDITOR, get_text());
628 }
629 
ButtonOption(const std::string & text,std::function<void ()> callback)630 ButtonOption::ButtonOption(const std::string& text, std::function<void()> callback) :
631   ObjectOption(text, "", 0),
632   m_callback(std::move(callback))
633 {
634 }
635 
636 std::string
to_string() const637 ButtonOption::to_string() const
638 {
639   return {};
640 }
641 
642 void
add_to_menu(Menu & menu) const643 ButtonOption::add_to_menu(Menu& menu) const
644 {
645   menu.add_entry(get_text(), m_callback);
646 }
647 
648 /* EOF */
649