summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/classes/Theme.xml15
-rw-r--r--editor/plugins/theme_editor_plugin.cpp86
-rw-r--r--editor/plugins/theme_editor_plugin.h10
-rw-r--r--scene/resources/theme.cpp143
-rw-r--r--scene/resources/theme.h9
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);