1 /*************************************************************************/
2 /* theme_editor_plugin.cpp */
3 /*************************************************************************/
4 /* This file is part of: */
5 /* GODOT ENGINE */
6 /* https://godotengine.org */
7 /*************************************************************************/
8 /* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
9 /* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
10 /* */
11 /* Permission is hereby granted, free of charge, to any person obtaining */
12 /* a copy of this software and associated documentation files (the */
13 /* "Software"), to deal in the Software without restriction, including */
14 /* without limitation the rights to use, copy, modify, merge, publish, */
15 /* distribute, sublicense, and/or sell copies of the Software, and to */
16 /* permit persons to whom the Software is furnished to do so, subject to */
17 /* the following conditions: */
18 /* */
19 /* The above copyright notice and this permission notice shall be */
20 /* included in all copies or substantial portions of the Software. */
21 /* */
22 /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
23 /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
24 /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
25 /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
26 /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
27 /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
28 /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
29 /*************************************************************************/
30
31 #include "theme_editor_plugin.h"
32
33 #include "core/os/file_access.h"
34 #include "core/version.h"
35 #include "editor/editor_scale.h"
36 #include "scene/gui/progress_bar.h"
37
edit(const Ref<Theme> & p_theme)38 void ThemeEditor::edit(const Ref<Theme> &p_theme) {
39
40 theme = p_theme;
41 main_panel->set_theme(p_theme);
42 main_container->set_theme(p_theme);
43 }
44
_propagate_redraw(Control * p_at)45 void ThemeEditor::_propagate_redraw(Control *p_at) {
46
47 p_at->notification(NOTIFICATION_THEME_CHANGED);
48 p_at->minimum_size_changed();
49 p_at->update();
50 for (int i = 0; i < p_at->get_child_count(); i++) {
51 Control *a = Object::cast_to<Control>(p_at->get_child(i));
52 if (a)
53 _propagate_redraw(a);
54 }
55 }
56
_refresh_interval()57 void ThemeEditor::_refresh_interval() {
58
59 _propagate_redraw(main_panel);
60 _propagate_redraw(main_container);
61 }
62
_type_menu_cbk(int p_option)63 void ThemeEditor::_type_menu_cbk(int p_option) {
64
65 type_edit->set_text(type_menu->get_popup()->get_item_text(p_option));
66 }
67
_name_menu_about_to_show()68 void ThemeEditor::_name_menu_about_to_show() {
69
70 String fromtype = type_edit->get_text();
71 List<StringName> names;
72
73 if (popup_mode == POPUP_ADD) {
74
75 switch (type_select->get_selected()) {
76
77 case 0: Theme::get_default()->get_icon_list(fromtype, &names); break;
78 case 1: Theme::get_default()->get_stylebox_list(fromtype, &names); break;
79 case 2: Theme::get_default()->get_font_list(fromtype, &names); break;
80 case 3: Theme::get_default()->get_color_list(fromtype, &names); break;
81 case 4: Theme::get_default()->get_constant_list(fromtype, &names); break;
82 }
83 } else if (popup_mode == POPUP_REMOVE) {
84
85 theme->get_icon_list(fromtype, &names);
86 theme->get_stylebox_list(fromtype, &names);
87 theme->get_font_list(fromtype, &names);
88 theme->get_color_list(fromtype, &names);
89 theme->get_constant_list(fromtype, &names);
90 }
91
92 name_menu->get_popup()->clear();
93 name_menu->get_popup()->set_size(Size2());
94 for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
95
96 name_menu->get_popup()->add_item(E->get());
97 }
98 }
99
_name_menu_cbk(int p_option)100 void ThemeEditor::_name_menu_cbk(int p_option) {
101
102 name_edit->set_text(name_menu->get_popup()->get_item_text(p_option));
103 }
104
105 struct _TECategory {
106
107 template <class T>
108 struct RefItem {
109
110 Ref<T> item;
111 StringName name;
operator <_TECategory::RefItem112 bool operator<(const RefItem<T> &p) const { return item->get_instance_id() < p.item->get_instance_id(); }
113 };
114
115 template <class T>
116 struct Item {
117
118 T item;
119 String name;
operator <_TECategory::Item120 bool operator<(const Item<T> &p) const { return name < p.name; }
121 };
122
123 Set<RefItem<StyleBox> > stylebox_items;
124 Set<RefItem<Font> > font_items;
125 Set<RefItem<Texture> > icon_items;
126
127 Set<Item<Color> > color_items;
128 Set<Item<int> > constant_items;
129 };
130
_save_template_cbk(String fname)131 void ThemeEditor::_save_template_cbk(String fname) {
132
133 String filename = file_dialog->get_current_path();
134
135 Map<String, _TECategory> categories;
136
137 // Fill types.
138 List<StringName> type_list;
139 Theme::get_default()->get_type_list(&type_list);
140 for (List<StringName>::Element *E = type_list.front(); E; E = E->next()) {
141 categories.insert(E->get(), _TECategory());
142 }
143
144 // Fill default theme.
145 for (Map<String, _TECategory>::Element *E = categories.front(); E; E = E->next()) {
146
147 _TECategory &tc = E->get();
148
149 List<StringName> stylebox_list;
150 Theme::get_default()->get_stylebox_list(E->key(), &stylebox_list);
151 for (List<StringName>::Element *F = stylebox_list.front(); F; F = F->next()) {
152 _TECategory::RefItem<StyleBox> it;
153 it.name = F->get();
154 it.item = Theme::get_default()->get_stylebox(F->get(), E->key());
155 tc.stylebox_items.insert(it);
156 }
157
158 List<StringName> font_list;
159 Theme::get_default()->get_font_list(E->key(), &font_list);
160 for (List<StringName>::Element *F = font_list.front(); F; F = F->next()) {
161 _TECategory::RefItem<Font> it;
162 it.name = F->get();
163 it.item = Theme::get_default()->get_font(F->get(), E->key());
164 tc.font_items.insert(it);
165 }
166
167 List<StringName> icon_list;
168 Theme::get_default()->get_icon_list(E->key(), &icon_list);
169 for (List<StringName>::Element *F = icon_list.front(); F; F = F->next()) {
170 _TECategory::RefItem<Texture> it;
171 it.name = F->get();
172 it.item = Theme::get_default()->get_icon(F->get(), E->key());
173 tc.icon_items.insert(it);
174 }
175
176 List<StringName> color_list;
177 Theme::get_default()->get_color_list(E->key(), &color_list);
178 for (List<StringName>::Element *F = color_list.front(); F; F = F->next()) {
179 _TECategory::Item<Color> it;
180 it.name = F->get();
181 it.item = Theme::get_default()->get_color(F->get(), E->key());
182 tc.color_items.insert(it);
183 }
184
185 List<StringName> constant_list;
186 Theme::get_default()->get_constant_list(E->key(), &constant_list);
187 for (List<StringName>::Element *F = constant_list.front(); F; F = F->next()) {
188 _TECategory::Item<int> it;
189 it.name = F->get();
190 it.item = Theme::get_default()->get_constant(F->get(), E->key());
191 tc.constant_items.insert(it);
192 }
193 }
194
195 FileAccess *file = FileAccess::open(filename, FileAccess::WRITE);
196
197 ERR_FAIL_COND_MSG(!file, "Can't save theme to file '" + filename + "'.");
198
199 file->store_line("; ******************* ");
200 file->store_line("; Template Theme File ");
201 file->store_line("; ******************* ");
202 file->store_line("; ");
203 file->store_line("; Theme Syntax: ");
204 file->store_line("; ------------- ");
205 file->store_line("; ");
206 file->store_line("; Must be placed in section [theme]");
207 file->store_line("; ");
208 file->store_line("; Type.item = [value] ");
209 file->store_line("; ");
210 file->store_line("; [value] examples:");
211 file->store_line("; ");
212 file->store_line("; Type.item = 6 ; numeric constant. ");
213 file->store_line("; Type.item = #FF00FF ; HTML color ");
214 file->store_line("; Type.item = #55FF00FF ; HTML color with alpha 55.");
215 file->store_line("; Type.item = icon(image.png) ; icon in a png file (relative to theme file).");
216 file->store_line("; Type.item = font(font.xres) ; font in a resource (relative to theme file).");
217 file->store_line("; Type.item = sbox(stylebox.xres) ; stylebox in a resource (relative to theme file).");
218 file->store_line("; Type.item = sboxf(2,#FF00FF) ; flat stylebox with margin 2.");
219 file->store_line("; Type.item = sboxf(2,#FF00FF,#FFFFFF) ; flat stylebox with margin 2 and border.");
220 file->store_line("; Type.item = sboxf(2,#FF00FF,#FFFFFF,#000000) ; flat stylebox with margin 2, light & dark borders.");
221 file->store_line("; Type.item = sboxt(base.png,2,2,2,2) ; textured stylebox with 3x3 stretch and stretch margins.");
222 file->store_line("; -Additionally, 4 extra integers can be added to sboxf and sboxt to specify custom padding of contents:");
223 file->store_line("; Type.item = sboxt(base.png,2,2,2,2,5,4,2,4) ;");
224 file->store_line("; -Order for all is always left, top, right, bottom.");
225 file->store_line("; ");
226 file->store_line("; Special values:");
227 file->store_line("; Type.item = default ; use the value in the default theme (must exist there).");
228 file->store_line("; Type.item = @somebutton_color ; reference to a library value previously defined.");
229 file->store_line("; ");
230 file->store_line("; Library Syntax: ");
231 file->store_line("; --------------- ");
232 file->store_line("; ");
233 file->store_line("; Must be placed in section [library], but usage is optional.");
234 file->store_line("; ");
235 file->store_line("; item = [value] ; same as Theme, but assign to library.");
236 file->store_line("; ");
237 file->store_line("; examples:");
238 file->store_line("; ");
239 file->store_line("; [library]");
240 file->store_line("; ");
241 file->store_line("; default_button_color = #FF00FF");
242 file->store_line("; ");
243 file->store_line("; [theme]");
244 file->store_line("; ");
245 file->store_line("; Button.color = @default_button_color ; used reference.");
246 file->store_line("; ");
247 file->store_line("; ******************* ");
248 file->store_line("; ");
249 file->store_line("; Template Generated Using: " + String(VERSION_FULL_BUILD));
250 file->store_line("; ");
251 file->store_line("; ");
252 file->store_line("");
253 file->store_line("[library]");
254 file->store_line("");
255 file->store_line("; place library stuff here");
256 file->store_line("");
257 file->store_line("[theme]");
258 file->store_line("");
259 file->store_line("");
260
261 // Write default theme.
262 for (Map<String, _TECategory>::Element *E = categories.front(); E; E = E->next()) {
263
264 _TECategory &tc = E->get();
265
266 String underline = "; ";
267 for (int i = 0; i < E->key().length(); i++)
268 underline += "*";
269
270 file->store_line("");
271 file->store_line(underline);
272 file->store_line("; " + E->key());
273 file->store_line(underline);
274
275 if (tc.stylebox_items.size())
276 file->store_line("\n; StyleBox Items:\n");
277
278 for (Set<_TECategory::RefItem<StyleBox> >::Element *F = tc.stylebox_items.front(); F; F = F->next()) {
279
280 file->store_line(E->key() + "." + F->get().name + " = default");
281 }
282
283 if (tc.font_items.size())
284 file->store_line("\n; Font Items:\n");
285
286 for (Set<_TECategory::RefItem<Font> >::Element *F = tc.font_items.front(); F; F = F->next()) {
287
288 file->store_line(E->key() + "." + F->get().name + " = default");
289 }
290
291 if (tc.icon_items.size())
292 file->store_line("\n; Icon Items:\n");
293
294 for (Set<_TECategory::RefItem<Texture> >::Element *F = tc.icon_items.front(); F; F = F->next()) {
295
296 file->store_line(E->key() + "." + F->get().name + " = default");
297 }
298
299 if (tc.color_items.size())
300 file->store_line("\n; Color Items:\n");
301
302 for (Set<_TECategory::Item<Color> >::Element *F = tc.color_items.front(); F; F = F->next()) {
303
304 file->store_line(E->key() + "." + F->get().name + " = default");
305 }
306
307 if (tc.constant_items.size())
308 file->store_line("\n; Constant Items:\n");
309
310 for (Set<_TECategory::Item<int> >::Element *F = tc.constant_items.front(); F; F = F->next()) {
311
312 file->store_line(E->key() + "." + F->get().name + " = default");
313 }
314 }
315
316 file->close();
317 memdelete(file);
318 }
319
_dialog_cbk()320 void ThemeEditor::_dialog_cbk() {
321
322 switch (popup_mode) {
323 case POPUP_ADD: {
324
325 switch (type_select->get_selected()) {
326
327 case 0: theme->set_icon(name_edit->get_text(), type_edit->get_text(), Ref<Texture>()); break;
328 case 1: theme->set_stylebox(name_edit->get_text(), type_edit->get_text(), Ref<StyleBox>()); break;
329 case 2: theme->set_font(name_edit->get_text(), type_edit->get_text(), Ref<Font>()); break;
330 case 3: theme->set_color(name_edit->get_text(), type_edit->get_text(), Color()); break;
331 case 4: theme->set_constant(name_edit->get_text(), type_edit->get_text(), 0); break;
332 }
333
334 } break;
335 case POPUP_CLASS_ADD: {
336
337 StringName fromtype = type_edit->get_text();
338 List<StringName> names;
339
340 {
341 names.clear();
342 Theme::get_default()->get_icon_list(fromtype, &names);
343 for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
344 theme->set_icon(E->get(), fromtype, Ref<Texture>());
345 }
346 }
347 {
348 names.clear();
349 Theme::get_default()->get_stylebox_list(fromtype, &names);
350 for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
351 theme->set_stylebox(E->get(), fromtype, Ref<StyleBox>());
352 }
353 }
354 {
355 names.clear();
356 Theme::get_default()->get_font_list(fromtype, &names);
357 for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
358 theme->set_font(E->get(), fromtype, Ref<Font>());
359 }
360 }
361 {
362 names.clear();
363 Theme::get_default()->get_color_list(fromtype, &names);
364 for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
365 theme->set_color(E->get(), fromtype, Theme::get_default()->get_color(E->get(), fromtype));
366 }
367 }
368 {
369 names.clear();
370 Theme::get_default()->get_constant_list(fromtype, &names);
371 for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
372 theme->set_constant(E->get(), fromtype, Theme::get_default()->get_constant(E->get(), fromtype));
373 }
374 }
375 } break;
376 case POPUP_REMOVE: {
377 switch (type_select->get_selected()) {
378
379 case 0: theme->clear_icon(name_edit->get_text(), type_edit->get_text()); break;
380 case 1: theme->clear_stylebox(name_edit->get_text(), type_edit->get_text()); break;
381 case 2: theme->clear_font(name_edit->get_text(), type_edit->get_text()); break;
382 case 3: theme->clear_color(name_edit->get_text(), type_edit->get_text()); break;
383 case 4: theme->clear_constant(name_edit->get_text(), type_edit->get_text()); break;
384 }
385
386 } break;
387 case POPUP_CLASS_REMOVE: {
388 StringName fromtype = type_edit->get_text();
389 List<StringName> names;
390
391 {
392 names.clear();
393 Theme::get_default()->get_icon_list(fromtype, &names);
394 for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
395 theme->clear_icon(E->get(), fromtype);
396 }
397 }
398 {
399 names.clear();
400 Theme::get_default()->get_stylebox_list(fromtype, &names);
401 for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
402 theme->clear_stylebox(E->get(), fromtype);
403 }
404 }
405 {
406 names.clear();
407 Theme::get_default()->get_font_list(fromtype, &names);
408 for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
409 theme->clear_font(E->get(), fromtype);
410 }
411 }
412 {
413 names.clear();
414 Theme::get_default()->get_color_list(fromtype, &names);
415 for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
416 theme->clear_color(E->get(), fromtype);
417 }
418 }
419 {
420 names.clear();
421 Theme::get_default()->get_constant_list(fromtype, &names);
422 for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
423 theme->clear_constant(E->get(), fromtype);
424 }
425 }
426
427 } break;
428 }
429 }
430
_theme_menu_cbk(int p_option)431 void ThemeEditor::_theme_menu_cbk(int p_option) {
432
433 if (p_option == POPUP_CREATE_EMPTY || p_option == POPUP_CREATE_EDITOR_EMPTY || p_option == POPUP_IMPORT_EDITOR_THEME) {
434
435 bool import = (p_option == POPUP_IMPORT_EDITOR_THEME);
436
437 Ref<Theme> base_theme;
438
439 if (p_option == POPUP_CREATE_EMPTY) {
440 base_theme = Theme::get_default();
441 } else {
442 base_theme = EditorNode::get_singleton()->get_theme_base()->get_theme();
443 }
444
445 {
446
447 List<StringName> types;
448 base_theme->get_type_list(&types);
449
450 for (List<StringName>::Element *T = types.front(); T; T = T->next()) {
451 StringName type = T->get();
452
453 List<StringName> icons;
454 base_theme->get_icon_list(type, &icons);
455
456 for (List<StringName>::Element *E = icons.front(); E; E = E->next()) {
457 theme->set_icon(E->get(), type, import ? base_theme->get_icon(E->get(), type) : Ref<Texture>());
458 }
459
460 List<StringName> shaders;
461 base_theme->get_shader_list(type, &shaders);
462
463 for (List<StringName>::Element *E = shaders.front(); E; E = E->next()) {
464 theme->set_shader(E->get(), type, import ? base_theme->get_shader(E->get(), type) : Ref<Shader>());
465 }
466
467 List<StringName> styleboxs;
468 base_theme->get_stylebox_list(type, &styleboxs);
469
470 for (List<StringName>::Element *E = styleboxs.front(); E; E = E->next()) {
471 theme->set_stylebox(E->get(), type, import ? base_theme->get_stylebox(E->get(), type) : Ref<StyleBox>());
472 }
473
474 List<StringName> fonts;
475 base_theme->get_font_list(type, &fonts);
476
477 for (List<StringName>::Element *E = fonts.front(); E; E = E->next()) {
478 theme->set_font(E->get(), type, Ref<Font>());
479 }
480
481 List<StringName> colors;
482 base_theme->get_color_list(type, &colors);
483
484 for (List<StringName>::Element *E = colors.front(); E; E = E->next()) {
485 theme->set_color(E->get(), type, import ? base_theme->get_color(E->get(), type) : Color());
486 }
487
488 List<StringName> constants;
489 base_theme->get_constant_list(type, &constants);
490
491 for (List<StringName>::Element *E = constants.front(); E; E = E->next()) {
492 theme->set_constant(E->get(), type, base_theme->get_constant(E->get(), type));
493 }
494 }
495 }
496 return;
497 }
498
499 Ref<Theme> base_theme;
500
501 name_select_label->show();
502 name_hbc->show();
503 type_select_label->show();
504 type_select->show();
505
506 if (p_option == POPUP_ADD) { // Add.
507
508 add_del_dialog->set_title(TTR("Add Item"));
509 add_del_dialog->get_ok()->set_text(TTR("Add"));
510 add_del_dialog->popup_centered(Size2(490, 85) * EDSCALE);
511
512 base_theme = Theme::get_default();
513
514 } else if (p_option == POPUP_CLASS_ADD) { // Add.
515
516 add_del_dialog->set_title(TTR("Add All Items"));
517 add_del_dialog->get_ok()->set_text(TTR("Add All"));
518 add_del_dialog->popup_centered(Size2(240, 85) * EDSCALE);
519
520 base_theme = Theme::get_default();
521
522 name_select_label->hide();
523 name_hbc->hide();
524 type_select_label->hide();
525 type_select->hide();
526
527 } else if (p_option == POPUP_REMOVE) {
528
529 add_del_dialog->set_title(TTR("Remove Item"));
530 add_del_dialog->get_ok()->set_text(TTR("Remove"));
531 add_del_dialog->popup_centered(Size2(490, 85) * EDSCALE);
532
533 base_theme = theme;
534
535 } else if (p_option == POPUP_CLASS_REMOVE) {
536
537 add_del_dialog->set_title(TTR("Remove All Items"));
538 add_del_dialog->get_ok()->set_text(TTR("Remove All"));
539 add_del_dialog->popup_centered(Size2(240, 85) * EDSCALE);
540
541 base_theme = Theme::get_default();
542
543 name_select_label->hide();
544 name_hbc->hide();
545 type_select_label->hide();
546 type_select->hide();
547 }
548 popup_mode = p_option;
549
550 ERR_FAIL_COND(theme.is_null());
551
552 List<StringName> types;
553 base_theme->get_type_list(&types);
554
555 type_menu->get_popup()->clear();
556
557 if (p_option == 0 || p_option == 1) { // Add.
558
559 List<StringName> new_types;
560 theme->get_type_list(&new_types);
561 for (List<StringName>::Element *F = new_types.front(); F; F = F->next()) {
562
563 bool found = false;
564 for (List<StringName>::Element *E = types.front(); E; E = E->next()) {
565
566 if (E->get() == F->get()) {
567 found = true;
568 break;
569 }
570 }
571
572 if (!found)
573 types.push_back(F->get());
574 }
575 }
576
577 types.sort_custom<StringName::AlphCompare>();
578 for (List<StringName>::Element *E = types.front(); E; E = E->next()) {
579
580 type_menu->get_popup()->add_item(E->get());
581 }
582 }
583
_notification(int p_what)584 void ThemeEditor::_notification(int p_what) {
585
586 switch (p_what) {
587 case NOTIFICATION_PROCESS: {
588 time_left -= get_process_delta_time();
589 if (time_left < 0) {
590 time_left = 1.5;
591 _refresh_interval();
592 }
593 } break;
594 case NOTIFICATION_THEME_CHANGED: {
595 theme_menu->set_icon(get_icon("Theme", "EditorIcons"));
596 } break;
597 }
598 }
599
_bind_methods()600 void ThemeEditor::_bind_methods() {
601
602 ClassDB::bind_method("_type_menu_cbk", &ThemeEditor::_type_menu_cbk);
603 ClassDB::bind_method("_name_menu_about_to_show", &ThemeEditor::_name_menu_about_to_show);
604 ClassDB::bind_method("_name_menu_cbk", &ThemeEditor::_name_menu_cbk);
605 ClassDB::bind_method("_theme_menu_cbk", &ThemeEditor::_theme_menu_cbk);
606 ClassDB::bind_method("_dialog_cbk", &ThemeEditor::_dialog_cbk);
607 ClassDB::bind_method("_save_template_cbk", &ThemeEditor::_save_template_cbk);
608 }
609
ThemeEditor()610 ThemeEditor::ThemeEditor() {
611
612 time_left = 0;
613
614 HBoxContainer *top_menu = memnew(HBoxContainer);
615 add_child(top_menu);
616
617 top_menu->add_child(memnew(Label(TTR("Preview:"))));
618 top_menu->add_spacer(false);
619
620 theme_menu = memnew(MenuButton);
621 theme_menu->set_text(TTR("Edit Theme"));
622 theme_menu->set_tooltip(TTR("Theme editing menu."));
623 theme_menu->get_popup()->add_item(TTR("Add Item"), POPUP_ADD);
624 theme_menu->get_popup()->add_item(TTR("Add Class Items"), POPUP_CLASS_ADD);
625 theme_menu->get_popup()->add_item(TTR("Remove Item"), POPUP_REMOVE);
626 theme_menu->get_popup()->add_item(TTR("Remove Class Items"), POPUP_CLASS_REMOVE);
627 theme_menu->get_popup()->add_separator();
628 theme_menu->get_popup()->add_item(TTR("Create Empty Template"), POPUP_CREATE_EMPTY);
629 theme_menu->get_popup()->add_item(TTR("Create Empty Editor Template"), POPUP_CREATE_EDITOR_EMPTY);
630 theme_menu->get_popup()->add_item(TTR("Create From Current Editor Theme"), POPUP_IMPORT_EDITOR_THEME);
631 top_menu->add_child(theme_menu);
632 theme_menu->get_popup()->connect("id_pressed", this, "_theme_menu_cbk");
633
634 ScrollContainer *scroll = memnew(ScrollContainer);
635 add_child(scroll);
636 scroll->set_enable_v_scroll(true);
637 scroll->set_enable_h_scroll(true);
638 scroll->set_v_size_flags(SIZE_EXPAND_FILL);
639
640 MarginContainer *root_container = memnew(MarginContainer);
641 scroll->add_child(root_container);
642 root_container->set_theme(Theme::get_default());
643 root_container->set_clip_contents(true);
644 root_container->set_custom_minimum_size(Size2(700, 0) * EDSCALE);
645 root_container->set_v_size_flags(SIZE_EXPAND_FILL);
646 root_container->set_h_size_flags(SIZE_EXPAND_FILL);
647
648 //// Preview Controls ////
649
650 main_panel = memnew(Panel);
651 root_container->add_child(main_panel);
652
653 main_container = memnew(MarginContainer);
654 root_container->add_child(main_container);
655 main_container->add_constant_override("margin_right", 4 * EDSCALE);
656 main_container->add_constant_override("margin_top", 4 * EDSCALE);
657 main_container->add_constant_override("margin_left", 4 * EDSCALE);
658 main_container->add_constant_override("margin_bottom", 4 * EDSCALE);
659
660 HBoxContainer *main_hb = memnew(HBoxContainer);
661 main_container->add_child(main_hb);
662
663 VBoxContainer *first_vb = memnew(VBoxContainer);
664 main_hb->add_child(first_vb);
665 first_vb->set_h_size_flags(SIZE_EXPAND_FILL);
666 first_vb->add_constant_override("separation", 10 * EDSCALE);
667
668 first_vb->add_child(memnew(Label("Label")));
669
670 first_vb->add_child(memnew(Button("Button")));
671 Button *bt = memnew(Button);
672 bt->set_text(TTR("Toggle Button"));
673 bt->set_toggle_mode(true);
674 bt->set_pressed(true);
675 first_vb->add_child(bt);
676 bt = memnew(Button);
677 bt->set_text(TTR("Disabled Button"));
678 bt->set_disabled(true);
679 first_vb->add_child(bt);
680 ToolButton *tb = memnew(ToolButton);
681 tb->set_text("ToolButton");
682 first_vb->add_child(tb);
683
684 CheckButton *cb = memnew(CheckButton);
685 cb->set_text("CheckButton");
686 first_vb->add_child(cb);
687 CheckBox *cbx = memnew(CheckBox);
688 cbx->set_text("CheckBox");
689 first_vb->add_child(cbx);
690
691 MenuButton *test_menu_button = memnew(MenuButton);
692 test_menu_button->set_text("MenuButton");
693 test_menu_button->get_popup()->add_item(TTR("Item"));
694 test_menu_button->get_popup()->add_item(TTR("Disabled Item"));
695 test_menu_button->get_popup()->set_item_disabled(1, true);
696 test_menu_button->get_popup()->add_separator();
697 test_menu_button->get_popup()->add_check_item(TTR("Check Item"));
698 test_menu_button->get_popup()->add_check_item(TTR("Checked Item"));
699 test_menu_button->get_popup()->set_item_checked(4, true);
700 test_menu_button->get_popup()->add_separator();
701 test_menu_button->get_popup()->add_radio_check_item(TTR("Radio Item"));
702 test_menu_button->get_popup()->add_radio_check_item(TTR("Checked Radio Item"));
703 test_menu_button->get_popup()->set_item_checked(7, true);
704 test_menu_button->get_popup()->add_separator(TTR("Named Sep."));
705
706 PopupMenu *test_submenu = memnew(PopupMenu);
707 test_menu_button->get_popup()->add_child(test_submenu);
708 test_submenu->set_name("submenu");
709 test_menu_button->get_popup()->add_submenu_item(TTR("Submenu"), "submenu");
710 test_submenu->add_item(TTR("Subitem 1"));
711 test_submenu->add_item(TTR("Subitem 2"));
712 first_vb->add_child(test_menu_button);
713
714 OptionButton *test_option_button = memnew(OptionButton);
715 test_option_button->add_item("OptionButton");
716 test_option_button->add_separator();
717 test_option_button->add_item(TTR("Has"));
718 test_option_button->add_item(TTR("Many"));
719 test_option_button->add_item(TTR("Options"));
720 first_vb->add_child(test_option_button);
721 first_vb->add_child(memnew(ColorPickerButton));
722
723 VBoxContainer *second_vb = memnew(VBoxContainer);
724 second_vb->set_h_size_flags(SIZE_EXPAND_FILL);
725 main_hb->add_child(second_vb);
726 second_vb->add_constant_override("separation", 10 * EDSCALE);
727 LineEdit *le = memnew(LineEdit);
728 le->set_text("LineEdit");
729 second_vb->add_child(le);
730 le = memnew(LineEdit);
731 le->set_text(TTR("Disabled LineEdit"));
732 le->set_editable(false);
733 second_vb->add_child(le);
734 TextEdit *te = memnew(TextEdit);
735 te->set_text("TextEdit");
736 te->set_custom_minimum_size(Size2(0, 100) * EDSCALE);
737 second_vb->add_child(te);
738 second_vb->add_child(memnew(SpinBox));
739
740 HBoxContainer *vhb = memnew(HBoxContainer);
741 second_vb->add_child(vhb);
742 vhb->set_custom_minimum_size(Size2(0, 100) * EDSCALE);
743 vhb->add_child(memnew(VSlider));
744 VScrollBar *vsb = memnew(VScrollBar);
745 vsb->set_page(25);
746 vhb->add_child(vsb);
747 vhb->add_child(memnew(VSeparator));
748 VBoxContainer *hvb = memnew(VBoxContainer);
749 vhb->add_child(hvb);
750 hvb->set_alignment(ALIGN_CENTER);
751 hvb->set_h_size_flags(SIZE_EXPAND_FILL);
752 hvb->add_child(memnew(HSlider));
753 HScrollBar *hsb = memnew(HScrollBar);
754 hsb->set_page(25);
755 hvb->add_child(hsb);
756 HSlider *hs = memnew(HSlider);
757 hs->set_editable(false);
758 hvb->add_child(hs);
759 hvb->add_child(memnew(HSeparator));
760 ProgressBar *pb = memnew(ProgressBar);
761 pb->set_value(50);
762 hvb->add_child(pb);
763
764 VBoxContainer *third_vb = memnew(VBoxContainer);
765 third_vb->set_h_size_flags(SIZE_EXPAND_FILL);
766 third_vb->add_constant_override("separation", 10 * EDSCALE);
767 main_hb->add_child(third_vb);
768
769 TabContainer *tc = memnew(TabContainer);
770 third_vb->add_child(tc);
771 tc->set_custom_minimum_size(Size2(0, 135) * EDSCALE);
772 Control *tcc = memnew(Control);
773 tcc->set_name(TTR("Tab 1"));
774 tc->add_child(tcc);
775 tcc = memnew(Control);
776 tcc->set_name(TTR("Tab 2"));
777 tc->add_child(tcc);
778 tcc = memnew(Control);
779 tcc->set_name(TTR("Tab 3"));
780 tc->add_child(tcc);
781 tc->set_tab_disabled(2, true);
782
783 Tree *test_tree = memnew(Tree);
784 third_vb->add_child(test_tree);
785 test_tree->set_custom_minimum_size(Size2(0, 175) * EDSCALE);
786 test_tree->add_constant_override("draw_relationship_lines", 1);
787
788 TreeItem *item = test_tree->create_item();
789 item->set_text(0, "Tree");
790 item = test_tree->create_item(test_tree->get_root());
791 item->set_text(0, "Item");
792 item = test_tree->create_item(test_tree->get_root());
793 item->set_editable(0, true);
794 item->set_text(0, TTR("Editable Item"));
795 TreeItem *sub_tree = test_tree->create_item(test_tree->get_root());
796 sub_tree->set_text(0, TTR("Subtree"));
797 item = test_tree->create_item(sub_tree);
798 item->set_cell_mode(0, TreeItem::CELL_MODE_CHECK);
799 item->set_editable(0, true);
800 item->set_text(0, "Check Item");
801 item = test_tree->create_item(sub_tree);
802 item->set_cell_mode(0, TreeItem::CELL_MODE_RANGE);
803 item->set_editable(0, true);
804 item->set_range_config(0, 0, 20, 0.1);
805 item->set_range(0, 2);
806 item = test_tree->create_item(sub_tree);
807 item->set_cell_mode(0, TreeItem::CELL_MODE_RANGE);
808 item->set_editable(0, true);
809 item->set_text(0, TTR("Has,Many,Options"));
810 item->set_range(0, 2);
811
812 main_hb->add_constant_override("separation", 20 * EDSCALE);
813
814 ////////
815
816 add_del_dialog = memnew(ConfirmationDialog);
817 add_del_dialog->hide();
818 add_child(add_del_dialog);
819
820 VBoxContainer *dialog_vbc = memnew(VBoxContainer);
821 add_del_dialog->add_child(dialog_vbc);
822
823 Label *l = memnew(Label);
824 l->set_text(TTR("Type:"));
825 dialog_vbc->add_child(l);
826
827 type_hbc = memnew(HBoxContainer);
828 dialog_vbc->add_child(type_hbc);
829
830 type_edit = memnew(LineEdit);
831 type_edit->set_h_size_flags(SIZE_EXPAND_FILL);
832 type_hbc->add_child(type_edit);
833 type_menu = memnew(MenuButton);
834 type_menu->set_flat(false);
835 type_menu->set_text("..");
836 type_hbc->add_child(type_menu);
837
838 type_menu->get_popup()->connect("id_pressed", this, "_type_menu_cbk");
839
840 l = memnew(Label);
841 l->set_text(TTR("Name:"));
842 dialog_vbc->add_child(l);
843 name_select_label = l;
844
845 name_hbc = memnew(HBoxContainer);
846 dialog_vbc->add_child(name_hbc);
847
848 name_edit = memnew(LineEdit);
849 name_edit->set_h_size_flags(SIZE_EXPAND_FILL);
850 name_hbc->add_child(name_edit);
851 name_menu = memnew(MenuButton);
852 type_menu->set_flat(false);
853 name_menu->set_text("..");
854 name_hbc->add_child(name_menu);
855
856 name_menu->get_popup()->connect("about_to_show", this, "_name_menu_about_to_show");
857 name_menu->get_popup()->connect("id_pressed", this, "_name_menu_cbk");
858
859 type_select_label = memnew(Label);
860 type_select_label->set_text(TTR("Data Type:"));
861 dialog_vbc->add_child(type_select_label);
862
863 type_select = memnew(OptionButton);
864 type_select->add_item(TTR("Icon"));
865 type_select->add_item(TTR("Style"));
866 type_select->add_item(TTR("Font"));
867 type_select->add_item(TTR("Color"));
868 type_select->add_item(TTR("Constant"));
869
870 dialog_vbc->add_child(type_select);
871
872 add_del_dialog->get_ok()->connect("pressed", this, "_dialog_cbk");
873
874 file_dialog = memnew(EditorFileDialog);
875 file_dialog->add_filter("*.theme ; " + TTR("Theme File"));
876 add_child(file_dialog);
877 file_dialog->connect("file_selected", this, "_save_template_cbk");
878 }
879
edit(Object * p_node)880 void ThemeEditorPlugin::edit(Object *p_node) {
881
882 if (Object::cast_to<Theme>(p_node)) {
883 theme_editor->edit(Object::cast_to<Theme>(p_node));
884 } else {
885 theme_editor->edit(Ref<Theme>());
886 }
887 }
888
handles(Object * p_node) const889 bool ThemeEditorPlugin::handles(Object *p_node) const {
890
891 return p_node->is_class("Theme");
892 }
893
make_visible(bool p_visible)894 void ThemeEditorPlugin::make_visible(bool p_visible) {
895
896 if (p_visible) {
897 theme_editor->set_process(true);
898 button->show();
899 editor->make_bottom_panel_item_visible(theme_editor);
900 } else {
901 theme_editor->set_process(false);
902 if (theme_editor->is_visible_in_tree())
903 editor->hide_bottom_panel();
904
905 button->hide();
906 }
907 }
908
ThemeEditorPlugin(EditorNode * p_node)909 ThemeEditorPlugin::ThemeEditorPlugin(EditorNode *p_node) {
910
911 editor = p_node;
912 theme_editor = memnew(ThemeEditor);
913 theme_editor->set_custom_minimum_size(Size2(0, 200) * EDSCALE);
914
915 button = editor->add_bottom_panel_item(TTR("Theme"), theme_editor);
916 button->hide();
917 }
918