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