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