diff options
| -rw-r--r-- | doc/classes/Theme.xml | 15 | ||||
| -rw-r--r-- | editor/plugins/theme_editor_plugin.cpp | 86 | ||||
| -rw-r--r-- | editor/plugins/theme_editor_plugin.h | 10 | ||||
| -rw-r--r-- | scene/resources/theme.cpp | 143 | ||||
| -rw-r--r-- | scene/resources/theme.h | 9 | 
5 files changed, 239 insertions, 24 deletions
diff --git a/doc/classes/Theme.xml b/doc/classes/Theme.xml index b1367be263..f2775e60f3 100644 --- a/doc/classes/Theme.xml +++ b/doc/classes/Theme.xml @@ -13,6 +13,14 @@  		<link title="Using the theme editor">$DOCS_URL/tutorials/ui/gui_using_theme_editor.html</link>  	</tutorials>  	<methods> +		<method name="add_type"> +			<return type="void" /> +			<argument index="0" name="theme_type" type="StringName" /> +			<description> +				Adds an empty theme type for every valid data type. +				[b]Note:[/b] Empty types are not saved with the theme. This method only exists to perform in-memory changes to the resource. Use available [code]set_*[/code] methods to add theme items. +			</description> +		</method>  		<method name="clear">  			<return type="void" />  			<description> @@ -375,6 +383,13 @@  				[b]Note:[/b] This modifies the current theme. If you want to merge two themes together without modifying either one, create a new empty theme and merge the other two into it one after another.  			</description>  		</method> +		<method name="remove_type"> +			<return type="void" /> +			<argument index="0" name="theme_type" type="StringName" /> +			<description> +				Removes the theme type, gracefully discarding defined theme items. If the type is a variation, this information is also erased. If the type is a base for type variations, those variations lose their base. +			</description> +		</method>  		<method name="rename_color">  			<return type="void" />  			<argument index="0" name="old_name" type="StringName" /> diff --git a/editor/plugins/theme_editor_plugin.cpp b/editor/plugins/theme_editor_plugin.cpp index aaa09237cf..50ca20b2a5 100644 --- a/editor/plugins/theme_editor_plugin.cpp +++ b/editor/plugins/theme_editor_plugin.cpp @@ -1211,7 +1211,8 @@ void ThemeItemEditorDialog::_update_edit_types() {  	bool item_reselected = false;  	edit_type_list->clear(); -	int e_idx = 0; +	TreeItem *list_root = edit_type_list->create_item(); +  	for (const StringName &E : theme_types) {  		Ref<Texture2D> item_icon;  		if (E == "") { @@ -1219,19 +1220,21 @@ void ThemeItemEditorDialog::_update_edit_types() {  		} else {  			item_icon = EditorNode::get_singleton()->get_class_icon(E, "NodeDisabled");  		} -		edit_type_list->add_item(E, item_icon); +		TreeItem *list_item = edit_type_list->create_item(list_root); +		list_item->set_text(0, E); +		list_item->set_icon(0, item_icon); +		list_item->add_button(0, get_theme_icon(SNAME("Remove"), SNAME("EditorIcons")), TYPES_TREE_REMOVE_ITEM, false, TTR("Remove Type"));  		if (E == edited_item_type) { -			edit_type_list->select(e_idx); +			list_item->select(0);  			item_reselected = true;  		} -		e_idx++;  	}  	if (!item_reselected) {  		edited_item_type = ""; -		if (edit_type_list->get_item_count() > 0) { -			edit_type_list->select(0); +		if (list_root->get_child_count() > 0) { +			list_root->get_child(0)->select(0);  		}  	} @@ -1240,9 +1243,9 @@ void ThemeItemEditorDialog::_update_edit_types() {  	default_types.sort_custom<StringName::AlphCompare>();  	String selected_type = ""; -	Vector<int> selected_ids = edit_type_list->get_selected_items(); -	if (selected_ids.size() > 0) { -		selected_type = edit_type_list->get_item_text(selected_ids[0]); +	TreeItem *selected_item = edit_type_list->get_selected(); +	if (selected_item) { +		selected_type = selected_item->get_text(0);  		edit_items_add_color->set_disabled(false);  		edit_items_add_constant->set_disabled(false); @@ -1276,11 +1279,26 @@ void ThemeItemEditorDialog::_update_edit_types() {  	_update_edit_item_tree(selected_type);  } -void ThemeItemEditorDialog::_edited_type_selected(int p_item_idx) { -	String selected_type = edit_type_list->get_item_text(p_item_idx); +void ThemeItemEditorDialog::_edited_type_selected() { +	TreeItem *selected_item = edit_type_list->get_selected(); +	String selected_type = selected_item->get_text(0);  	_update_edit_item_tree(selected_type);  } +void ThemeItemEditorDialog::_edited_type_button_pressed(Object *p_item, int p_column, int p_id) { +	TreeItem *item = Object::cast_to<TreeItem>(p_item); +	if (!item) { +		return; +	} + +	switch (p_id) { +		case TYPES_TREE_REMOVE_ITEM: { +			String type_name = item->get_text(0); +			_remove_theme_type(type_name); +		} break; +	} +} +  void ThemeItemEditorDialog::_update_edit_item_tree(String p_item_type) {  	edited_item_type = p_item_type; @@ -1429,8 +1447,8 @@ void ThemeItemEditorDialog::_update_edit_item_tree(String p_item_type) {  	}  	// If some type is selected, but it doesn't seem to have any items, show a guiding message. -	Vector<int> selected_ids = edit_type_list->get_selected_items(); -	if (selected_ids.size() > 0) { +	TreeItem *selected_item = edit_type_list->get_selected(); +	if (selected_item) {  		if (!has_any_items) {  			edit_items_message->set_text(TTR("This theme type is empty.\nAdd more items to it manually or by importing from another theme."));  			edit_items_message->show(); @@ -1477,16 +1495,15 @@ void ThemeItemEditorDialog::_add_theme_type(const String &p_new_text) {  	const String new_type = edit_add_type_value->get_text().strip_edges();  	edit_add_type_value->clear(); -	edited_theme->add_icon_type(new_type); -	edited_theme->add_stylebox_type(new_type); -	edited_theme->add_font_type(new_type); -	edited_theme->add_font_size_type(new_type); -	edited_theme->add_color_type(new_type); -	edited_theme->add_constant_type(new_type); +	UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo(); +	ur->create_action(TTR("Add Theme Type")); -	_update_edit_types(); +	ur->add_do_method(*edited_theme, "add_type", new_type); +	ur->add_undo_method(*edited_theme, "remove_type", new_type); +	ur->add_do_method(this, "_update_edit_types"); +	ur->add_undo_method(this, "_update_edit_types"); -	edited_theme->emit_changed(); +	ur->commit_action();  }  void ThemeItemEditorDialog::_add_theme_item(Theme::DataType p_data_type, String p_item_name, String p_item_type) { @@ -1531,6 +1548,27 @@ void ThemeItemEditorDialog::_add_theme_item(Theme::DataType p_data_type, String  	ur->commit_action();  } +void ThemeItemEditorDialog::_remove_theme_type(const String &p_theme_type) { +	Ref<Theme> old_snapshot = edited_theme->duplicate(); +	Ref<Theme> new_snapshot = edited_theme->duplicate(); + +	UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo(); +	ur->create_action(TTR("Remove Theme Type")); + +	new_snapshot->remove_type(p_theme_type); + +	ur->add_do_method(*edited_theme, "clear"); +	ur->add_do_method(*edited_theme, "merge_with", new_snapshot); +	// If the type was empty, it cannot be restored with merge, but thankfully we can fake it. +	ur->add_undo_method(*edited_theme, "add_type", p_theme_type); +	ur->add_undo_method(*edited_theme, "merge_with", old_snapshot); + +	ur->add_do_method(this, "_update_edit_types"); +	ur->add_undo_method(this, "_update_edit_types"); + +	ur->commit_action(); +} +  void ThemeItemEditorDialog::_remove_data_type_items(Theme::DataType p_data_type, String p_item_type) {  	List<StringName> names; @@ -1863,10 +1901,14 @@ ThemeItemEditorDialog::ThemeItemEditorDialog(ThemeTypeEditor *p_theme_type_edito  	edit_type_label->set_text(TTR("Types:"));  	edit_dialog_side_vb->add_child(edit_type_label); -	edit_type_list = memnew(ItemList); +	edit_type_list = memnew(Tree); +	edit_type_list->set_hide_root(true); +	edit_type_list->set_hide_folding(true); +	edit_type_list->set_columns(1);  	edit_type_list->set_v_size_flags(Control::SIZE_EXPAND_FILL);  	edit_dialog_side_vb->add_child(edit_type_list);  	edit_type_list->connect("item_selected", callable_mp(this, &ThemeItemEditorDialog::_edited_type_selected)); +	edit_type_list->connect("button_pressed", callable_mp(this, &ThemeItemEditorDialog::_edited_type_button_pressed));  	Label *edit_add_type_label = memnew(Label);  	edit_add_type_label->set_text(TTR("Add Type:")); diff --git a/editor/plugins/theme_editor_plugin.h b/editor/plugins/theme_editor_plugin.h index c00ce3ae65..af54c3ce83 100644 --- a/editor/plugins/theme_editor_plugin.h +++ b/editor/plugins/theme_editor_plugin.h @@ -188,7 +188,11 @@ class ThemeItemEditorDialog : public AcceptDialog {  	TabContainer *tc; -	ItemList *edit_type_list; +	enum TypesTreeAction { +		TYPES_TREE_REMOVE_ITEM, +	}; + +	Tree *edit_type_list;  	LineEdit *edit_add_type_value;  	String edited_item_type; @@ -240,13 +244,15 @@ class ThemeItemEditorDialog : public AcceptDialog {  	void _dialog_about_to_show();  	void _update_edit_types(); -	void _edited_type_selected(int p_item_idx); +	void _edited_type_selected(); +	void _edited_type_button_pressed(Object *p_item, int p_column, int p_id);  	void _update_edit_item_tree(String p_item_type);  	void _item_tree_button_pressed(Object *p_item, int p_column, int p_id);  	void _add_theme_type(const String &p_new_text);  	void _add_theme_item(Theme::DataType p_data_type, String p_item_name, String p_item_type); +	void _remove_theme_type(const String &p_theme_type);  	void _remove_data_type_items(Theme::DataType p_data_type, String p_item_type);  	void _remove_class_items();  	void _remove_custom_items(); diff --git a/scene/resources/theme.cpp b/scene/resources/theme.cpp index f962e55666..901ff22252 100644 --- a/scene/resources/theme.cpp +++ b/scene/resources/theme.cpp @@ -401,6 +401,26 @@ void Theme::add_icon_type(const StringName &p_theme_type) {  	icon_map[p_theme_type] = HashMap<StringName, Ref<Texture2D>>();  } +void Theme::remove_icon_type(const StringName &p_theme_type) { +	if (!icon_map.has(p_theme_type)) { +		return; +	} + +	_freeze_change_propagation(); + +	const StringName *L = nullptr; +	while ((L = icon_map[p_theme_type].next(L))) { +		Ref<Texture2D> icon = icon_map[p_theme_type][*L]; +		if (icon.is_valid()) { +			icon->disconnect("changed", callable_mp(this, &Theme::_emit_theme_changed)); +		} +	} + +	icon_map.erase(p_theme_type); + +	_unfreeze_and_propagate_changes(); +} +  void Theme::get_icon_type_list(List<StringName> *p_list) const {  	ERR_FAIL_NULL(p_list); @@ -488,6 +508,26 @@ void Theme::add_stylebox_type(const StringName &p_theme_type) {  	style_map[p_theme_type] = HashMap<StringName, Ref<StyleBox>>();  } +void Theme::remove_stylebox_type(const StringName &p_theme_type) { +	if (!style_map.has(p_theme_type)) { +		return; +	} + +	_freeze_change_propagation(); + +	const StringName *L = nullptr; +	while ((L = style_map[p_theme_type].next(L))) { +		Ref<StyleBox> style = style_map[p_theme_type][*L]; +		if (style.is_valid()) { +			style->disconnect("changed", callable_mp(this, &Theme::_emit_theme_changed)); +		} +	} + +	style_map.erase(p_theme_type); + +	_unfreeze_and_propagate_changes(); +} +  void Theme::get_stylebox_type_list(List<StringName> *p_list) const {  	ERR_FAIL_NULL(p_list); @@ -577,6 +617,26 @@ void Theme::add_font_type(const StringName &p_theme_type) {  	font_map[p_theme_type] = HashMap<StringName, Ref<Font>>();  } +void Theme::remove_font_type(const StringName &p_theme_type) { +	if (!font_map.has(p_theme_type)) { +		return; +	} + +	_freeze_change_propagation(); + +	const StringName *L = nullptr; +	while ((L = font_map[p_theme_type].next(L))) { +		Ref<Font> font = font_map[p_theme_type][*L]; +		if (font.is_valid()) { +			font->disconnect("changed", callable_mp(this, &Theme::_emit_theme_changed)); +		} +	} + +	font_map.erase(p_theme_type); + +	_unfreeze_and_propagate_changes(); +} +  void Theme::get_font_type_list(List<StringName> *p_list) const {  	ERR_FAIL_NULL(p_list); @@ -653,6 +713,14 @@ void Theme::add_font_size_type(const StringName &p_theme_type) {  	font_size_map[p_theme_type] = HashMap<StringName, int>();  } +void Theme::remove_font_size_type(const StringName &p_theme_type) { +	if (!font_size_map.has(p_theme_type)) { +		return; +	} + +	font_size_map.erase(p_theme_type); +} +  void Theme::get_font_size_type_list(List<StringName> *p_list) const {  	ERR_FAIL_NULL(p_list); @@ -727,6 +795,14 @@ void Theme::add_color_type(const StringName &p_theme_type) {  	color_map[p_theme_type] = HashMap<StringName, Color>();  } +void Theme::remove_color_type(const StringName &p_theme_type) { +	if (!color_map.has(p_theme_type)) { +		return; +	} + +	color_map.erase(p_theme_type); +} +  void Theme::get_color_type_list(List<StringName> *p_list) const {  	ERR_FAIL_NULL(p_list); @@ -801,6 +877,14 @@ void Theme::add_constant_type(const StringName &p_theme_type) {  	constant_map[p_theme_type] = HashMap<StringName, int>();  } +void Theme::remove_constant_type(const StringName &p_theme_type) { +	if (!constant_map.has(p_theme_type)) { +		return; +	} + +	constant_map.erase(p_theme_type); +} +  void Theme::get_constant_type_list(List<StringName> *p_list) const {  	ERR_FAIL_NULL(p_list); @@ -1017,6 +1101,31 @@ void Theme::add_theme_item_type(DataType p_data_type, const StringName &p_theme_  	}  } +void Theme::remove_theme_item_type(DataType p_data_type, const StringName &p_theme_type) { +	switch (p_data_type) { +		case DATA_TYPE_COLOR: +			remove_color_type(p_theme_type); +			break; +		case DATA_TYPE_CONSTANT: +			remove_constant_type(p_theme_type); +			break; +		case DATA_TYPE_FONT: +			remove_font_type(p_theme_type); +			break; +		case DATA_TYPE_FONT_SIZE: +			remove_font_size_type(p_theme_type); +			break; +		case DATA_TYPE_ICON: +			remove_icon_type(p_theme_type); +			break; +		case DATA_TYPE_STYLEBOX: +			remove_stylebox_type(p_theme_type); +			break; +		case DATA_TYPE_MAX: +			break; // Can't happen, but silences warning. +	} +} +  void Theme::get_theme_item_type_list(DataType p_data_type, List<StringName> *p_list) const {  	switch (p_data_type) {  		case DATA_TYPE_COLOR: @@ -1101,6 +1210,38 @@ void Theme::get_type_variation_list(const StringName &p_base_type, List<StringNa  }  // Theme types. +void Theme::add_type(const StringName &p_theme_type) { +	// Add a record to every data type map. +	for (int i = 0; i < Theme::DATA_TYPE_MAX; i++) { +		Theme::DataType dt = (Theme::DataType)i; +		add_theme_item_type(dt, p_theme_type); +	} + +	_emit_theme_changed(true); +} + +void Theme::remove_type(const StringName &p_theme_type) { +	// Gracefully remove the record from every data type map. +	for (int i = 0; i < Theme::DATA_TYPE_MAX; i++) { +		Theme::DataType dt = (Theme::DataType)i; +		remove_theme_item_type(dt, p_theme_type); +	} + +	// If type is a variation, remove that connection. +	if (get_type_variation_base(p_theme_type) != StringName()) { +		clear_type_variation(p_theme_type); +	} + +	// If type is a variation base, remove all those connections. +	List<StringName> names; +	get_type_variation_list(p_theme_type, &names); +	for (const StringName &E : names) { +		clear_type_variation(E); +	} + +	_emit_theme_changed(true); +} +  void Theme::get_type_list(List<StringName> *p_list) const {  	ERR_FAIL_NULL(p_list); @@ -1668,6 +1809,8 @@ void Theme::_bind_methods() {  	ClassDB::bind_method(D_METHOD("get_type_variation_base", "theme_type"), &Theme::get_type_variation_base);  	ClassDB::bind_method(D_METHOD("get_type_variation_list", "base_type"), &Theme::_get_type_variation_list); +	ClassDB::bind_method(D_METHOD("add_type", "theme_type"), &Theme::add_type); +	ClassDB::bind_method(D_METHOD("remove_type", "theme_type"), &Theme::remove_type);  	ClassDB::bind_method(D_METHOD("get_type_list"), &Theme::_get_type_list);  	ClassDB::bind_method(D_METHOD("merge_with", "other"), &Theme::merge_with); diff --git a/scene/resources/theme.h b/scene/resources/theme.h index 822743a1fe..7a61ccf8af 100644 --- a/scene/resources/theme.h +++ b/scene/resources/theme.h @@ -158,6 +158,7 @@ public:  	void clear_icon(const StringName &p_name, const StringName &p_theme_type);  	void get_icon_list(StringName p_theme_type, List<StringName> *p_list) const;  	void add_icon_type(const StringName &p_theme_type); +	void remove_icon_type(const StringName &p_theme_type);  	void get_icon_type_list(List<StringName> *p_list) const;  	void set_stylebox(const StringName &p_name, const StringName &p_theme_type, const Ref<StyleBox> &p_style); @@ -168,6 +169,7 @@ public:  	void clear_stylebox(const StringName &p_name, const StringName &p_theme_type);  	void get_stylebox_list(StringName p_theme_type, List<StringName> *p_list) const;  	void add_stylebox_type(const StringName &p_theme_type); +	void remove_stylebox_type(const StringName &p_theme_type);  	void get_stylebox_type_list(List<StringName> *p_list) const;  	void set_font(const StringName &p_name, const StringName &p_theme_type, const Ref<Font> &p_font); @@ -178,6 +180,7 @@ public:  	void clear_font(const StringName &p_name, const StringName &p_theme_type);  	void get_font_list(StringName p_theme_type, List<StringName> *p_list) const;  	void add_font_type(const StringName &p_theme_type); +	void remove_font_type(const StringName &p_theme_type);  	void get_font_type_list(List<StringName> *p_list) const;  	void set_font_size(const StringName &p_name, const StringName &p_theme_type, int p_font_size); @@ -188,6 +191,7 @@ public:  	void clear_font_size(const StringName &p_name, const StringName &p_theme_type);  	void get_font_size_list(StringName p_theme_type, List<StringName> *p_list) const;  	void add_font_size_type(const StringName &p_theme_type); +	void remove_font_size_type(const StringName &p_theme_type);  	void get_font_size_type_list(List<StringName> *p_list) const;  	void set_color(const StringName &p_name, const StringName &p_theme_type, const Color &p_color); @@ -198,6 +202,7 @@ public:  	void clear_color(const StringName &p_name, const StringName &p_theme_type);  	void get_color_list(StringName p_theme_type, List<StringName> *p_list) const;  	void add_color_type(const StringName &p_theme_type); +	void remove_color_type(const StringName &p_theme_type);  	void get_color_type_list(List<StringName> *p_list) const;  	void set_constant(const StringName &p_name, const StringName &p_theme_type, int p_constant); @@ -208,6 +213,7 @@ public:  	void clear_constant(const StringName &p_name, const StringName &p_theme_type);  	void get_constant_list(StringName p_theme_type, List<StringName> *p_list) const;  	void add_constant_type(const StringName &p_theme_type); +	void remove_constant_type(const StringName &p_theme_type);  	void get_constant_type_list(List<StringName> *p_list) const;  	void set_theme_item(DataType p_data_type, const StringName &p_name, const StringName &p_theme_type, const Variant &p_value); @@ -218,6 +224,7 @@ public:  	void clear_theme_item(DataType p_data_type, const StringName &p_name, const StringName &p_theme_type);  	void get_theme_item_list(DataType p_data_type, StringName p_theme_type, List<StringName> *p_list) const;  	void add_theme_item_type(DataType p_data_type, const StringName &p_theme_type); +	void remove_theme_item_type(DataType p_data_type, const StringName &p_theme_type);  	void get_theme_item_type_list(DataType p_data_type, List<StringName> *p_list) const;  	void set_type_variation(const StringName &p_theme_type, const StringName &p_base_type); @@ -226,6 +233,8 @@ public:  	StringName get_type_variation_base(const StringName &p_theme_type) const;  	void get_type_variation_list(const StringName &p_base_type, List<StringName> *p_list) const; +	void add_type(const StringName &p_theme_type); +	void remove_type(const StringName &p_theme_type);  	void get_type_list(List<StringName> *p_list) const;  	void get_type_dependencies(const StringName &p_base_type, const StringName &p_type_variant, List<StringName> *p_list);  |