From 9d9a394af6ab8d2ddf09f5cc6db7bc1746678940 Mon Sep 17 00:00:00 2001 From: Relintai Date: Mon, 25 Jul 2022 23:46:08 +0200 Subject: [PATCH] Ported: Add an explicit way to remove a theme type. - timothyqiu and YuriSizov https://github.com/godotengine/godot/commit/f6251724af1e234a38c09f4b7580e309778bb1d4 --- doc/classes/Theme.xml | 15 +++ editor/plugins/theme_editor_plugin.cpp | 98 +++++++++++++----- editor/plugins/theme_editor_plugin.h | 15 ++- scene/resources/theme.cpp | 133 +++++++++++++++++++++++++ scene/resources/theme.h | 8 ++ 5 files changed, 241 insertions(+), 28 deletions(-) diff --git a/doc/classes/Theme.xml b/doc/classes/Theme.xml index 2ebefd5ad..165817d85 100644 --- a/doc/classes/Theme.xml +++ b/doc/classes/Theme.xml @@ -11,6 +11,14 @@ $DOCS_URL/tutorials/ui/gui_skinning.html + + + + + 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. + + @@ -288,6 +296,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. + + + + + 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. + + diff --git a/editor/plugins/theme_editor_plugin.cpp b/editor/plugins/theme_editor_plugin.cpp index 86ff6bebb..c5963b720 100644 --- a/editor/plugins/theme_editor_plugin.cpp +++ b/editor/plugins/theme_editor_plugin.cpp @@ -30,10 +30,6 @@ #include "theme_editor_plugin.h" -#include "core/os/keyboard.h" -#include "editor/editor_resource_picker.h" -#include "editor/editor_scale.h" -#include "editor/progress_dialog.h" #include "core/array.h" #include "core/class_db.h" #include "core/color.h" @@ -41,12 +37,16 @@ #include "core/io/resource_loader.h" #include "core/math/vector2.h" #include "core/os/input_event.h" +#include "core/os/keyboard.h" #include "core/os/memory.h" #include "core/typedefs.h" #include "core/variant.h" #include "editor/editor_file_dialog.h" #include "editor/editor_node.h" +#include "editor/editor_resource_picker.h" +#include "editor/editor_scale.h" #include "editor/plugins/theme_editor_preview.h" +#include "editor/progress_dialog.h" #include "scene/2d/canvas_item.h" #include "scene/gui/button.h" #include "scene/gui/check_button.h" @@ -1211,7 +1211,9 @@ 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 (List::Element *E = theme_types.front(); E; E = E->next()) { Ref item_icon; if (E->get() == "") { @@ -1219,19 +1221,24 @@ void ThemeItemEditorDialog::_update_edit_types() { } else { item_icon = EditorNode::get_singleton()->get_class_icon(E->get(), "NodeDisabled"); } - edit_type_list->add_item(E->get(), item_icon); + + TreeItem *list_item = edit_type_list->create_item(list_root); + list_item->set_text(0, E->get()); + list_item->set_icon(0, item_icon); + list_item->add_button(0, get_icon("Remove", "EditorIcons"), TYPES_TREE_REMOVE_ITEM, false, TTR("Remove Type")); if (E->get() == 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); + TreeItem *ci = list_root->get_children(); + if (ci) { + ci->select(0); } } @@ -1240,9 +1247,9 @@ void ThemeItemEditorDialog::_update_edit_types() { default_types.sort_custom(); String selected_type = ""; - Vector 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); @@ -1273,11 +1280,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(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; @@ -1403,8 +1425,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 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(); @@ -1445,15 +1467,38 @@ 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_color_type(new_type); - edited_theme->add_constant_type(new_type); - _update_edit_types(); + UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo(); + + ur->create_action(TTR("Add Theme Type")); + 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"); + + ur->commit_action(); +} + +void ThemeItemEditorDialog::_remove_theme_type(const String &p_theme_type) { + Ref old_snapshot = edited_theme->duplicate(); + Ref 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"); // Force emit a change so that other parts of the editor can update. 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) { @@ -1714,6 +1759,7 @@ void ThemeItemEditorDialog::_notification(int p_what) { void ThemeItemEditorDialog::_bind_methods() { // Internal binds. ClassDB::bind_method("_edited_type_selected", &ThemeItemEditorDialog::_edited_type_selected); + ClassDB::bind_method("_edited_type_button_pressed", &ThemeItemEditorDialog::_edited_type_button_pressed); ClassDB::bind_method("_add_theme_type", &ThemeItemEditorDialog::_add_theme_type); ClassDB::bind_method("_open_add_theme_item_dialog", &ThemeItemEditorDialog::_open_add_theme_item_dialog); ClassDB::bind_method("_remove_class_items", &ThemeItemEditorDialog::_remove_class_items); @@ -1755,10 +1801,14 @@ ThemeItemEditorDialog::ThemeItemEditorDialog() { 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", this, "_edited_type_selected"); + edit_type_list->connect("button_pressed", this, "_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 b284ab61c..9420176eb 100644 --- a/editor/plugins/theme_editor_plugin.h +++ b/editor/plugins/theme_editor_plugin.h @@ -30,13 +30,13 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ +#include "editor/editor_plugin.h" #include "scene/gui/box_container.h" #include "scene/gui/dialogs.h" #include "scene/gui/margin_container.h" -#include "editor/editor_plugin.h" -#include "scene/resources/theme.h" #include "scene/resources/style_box.h" +#include "scene/resources/theme.h" #include "core/list.h" #include "core/map.h" @@ -205,7 +205,12 @@ 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; @@ -256,13 +261,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 e189e4872..c5af9c791 100644 --- a/scene/resources/theme.cpp +++ b/scene/resources/theme.cpp @@ -319,6 +319,26 @@ void Theme::add_icon_type(const StringName &p_theme_type) { icon_map[p_theme_type] = HashMap>(); } +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 icon = icon_map[p_theme_type][*L]; + if (icon.is_valid()) { + icon->disconnect("changed", this, "_emit_theme_changed"); + } + } + + icon_map.erase(p_theme_type); + + _unfreeze_and_propagate_changes(); +} + void Theme::get_icon_types(List *p_list) const { ERR_FAIL_NULL(p_list); @@ -449,6 +469,26 @@ void Theme::add_stylebox_type(const StringName &p_theme_type) { style_map[p_theme_type] = HashMap>(); } +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 style = style_map[p_theme_type][*L]; + if (style.is_valid()) { + style->disconnect("changed", this, "_emit_theme_changed"); + } + } + + style_map.erase(p_theme_type); + + _unfreeze_and_propagate_changes(); +} + void Theme::get_stylebox_types(List *p_list) const { ERR_FAIL_NULL(p_list); @@ -538,6 +578,26 @@ void Theme::add_font_type(const StringName &p_theme_type) { font_map[p_theme_type] = HashMap>(); } +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_map[p_theme_type][*L]; + if (font.is_valid()) { + font->disconnect("changed", this, "_emit_theme_changed"); + } + } + + font_map.erase(p_theme_type); + + _unfreeze_and_propagate_changes(); +} + void Theme::get_font_types(List *p_list) const { ERR_FAIL_NULL(p_list); @@ -612,6 +672,14 @@ void Theme::add_color_type(const StringName &p_theme_type) { color_map[p_theme_type] = HashMap(); } +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_types(List *p_list) const { ERR_FAIL_NULL(p_list); @@ -686,6 +754,14 @@ void Theme::add_constant_type(const StringName &p_theme_type) { constant_map[p_theme_type] = HashMap(); } +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_types(List *p_list) const { ERR_FAIL_NULL(p_list); @@ -878,6 +954,28 @@ 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_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_types(DataType p_data_type, List *p_list) const { switch (p_data_type) { case DATA_TYPE_COLOR: @@ -959,6 +1057,39 @@ void Theme::get_type_variation_list(const StringName &p_base_type, List names; + get_type_variation_list(p_theme_type, &names); + for (List::Element *E = names.front(); E; E = E->next()) { + clear_type_variation(E->get()); + } + + _emit_theme_changed(true); +} + void Theme::get_type_list(List *p_list) const { ERR_FAIL_NULL(p_list); @@ -1512,6 +1643,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_type"), &Theme::_get_type_list); ClassDB::bind_method(D_METHOD("_emit_theme_changed", "notify_list_changed"), &Theme::_emit_theme_changed, DEFVAL(false)); diff --git a/scene/resources/theme.h b/scene/resources/theme.h index 768486e78..060833cc3 100644 --- a/scene/resources/theme.h +++ b/scene/resources/theme.h @@ -133,6 +133,7 @@ public: void clear_icon(const StringName &p_name, const StringName &p_theme_type); void get_icon_list(StringName p_theme_type, List *p_list) const; void add_icon_type(const StringName &p_theme_type); + void remove_icon_type(const StringName &p_theme_type); void get_icon_types(List *p_list) const; void set_shader(const StringName &p_name, const StringName &p_theme_type, const Ref &p_shader); @@ -149,6 +150,7 @@ public: void clear_stylebox(const StringName &p_name, const StringName &p_theme_type); void get_stylebox_list(StringName p_theme_type, List *p_list) const; void add_stylebox_type(const StringName &p_theme_type); + void remove_stylebox_type(const StringName &p_theme_type); void get_stylebox_types(List *p_list) const; void set_font(const StringName &p_name, const StringName &p_theme_type, const Ref &p_font); @@ -159,6 +161,7 @@ public: void clear_font(const StringName &p_name, const StringName &p_theme_type); void get_font_list(StringName p_theme_type, List *p_list) const; void add_font_type(const StringName &p_theme_type); + void remove_font_type(const StringName &p_theme_type); void get_font_types(List *p_list) const; void set_color(const StringName &p_name, const StringName &p_theme_type, const Color &p_color); @@ -169,6 +172,7 @@ public: void clear_color(const StringName &p_name, const StringName &p_theme_type); void get_color_list(StringName p_theme_type, List *p_list) const; void add_color_type(const StringName &p_theme_type); + void remove_color_type(const StringName &p_theme_type); void get_color_types(List *p_list) const; void set_constant(const StringName &p_name, const StringName &p_theme_type, int p_constant); @@ -179,6 +183,7 @@ public: void clear_constant(const StringName &p_name, const StringName &p_theme_type); void get_constant_list(StringName p_theme_type, List *p_list) const; void add_constant_type(const StringName &p_theme_type); + void remove_constant_type(const StringName &p_theme_type); void get_constant_types(List *p_list) const; void set_theme_item(DataType p_data_type, const StringName &p_name, const StringName &p_theme_type, const Variant &p_value); @@ -189,6 +194,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 *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_types(DataType p_data_type, List *p_list) const; void set_type_variation(const StringName &p_theme_type, const StringName &p_base_type); @@ -197,6 +203,8 @@ public: StringName get_type_variation_base(const StringName &p_theme_type) const; void get_type_variation_list(const StringName &p_base_type, List *p_list) const; + void add_type(const StringName &p_theme_type); + void remove_type(const StringName &p_theme_type); void get_type_list(List *p_list) const; void get_type_dependencies(const StringName &p_base_type, const StringName &p_type_variant, List *p_list);