From 912420b078fe1727c58cee5de435b3ee6e79fcb6 Mon Sep 17 00:00:00 2001 From: Yuri Sizov Date: Sat, 24 Apr 2021 03:53:09 +0300 Subject: [PATCH] Refactor Create Theme menu in Theme Editor --- editor/icons/CollapseTree.svg | 1 + editor/icons/ExpandTree.svg | 1 + editor/icons/FontSize.svg | 2 +- editor/icons/ThemeDeselectAll.svg | 1 + editor/icons/ThemeRemoveAllItems.svg | 2 +- editor/icons/ThemeRemoveCustomItems.svg | 2 +- editor/icons/ThemeSelectAll.svg | 1 + editor/icons/ThemeSelectFull.svg | 1 + editor/plugins/theme_editor_plugin.cpp | 1696 +++++++++++++++++------ editor/plugins/theme_editor_plugin.h | 172 ++- 10 files changed, 1451 insertions(+), 428 deletions(-) create mode 100644 editor/icons/CollapseTree.svg create mode 100644 editor/icons/ExpandTree.svg create mode 100644 editor/icons/ThemeDeselectAll.svg create mode 100644 editor/icons/ThemeSelectAll.svg create mode 100644 editor/icons/ThemeSelectFull.svg diff --git a/editor/icons/CollapseTree.svg b/editor/icons/CollapseTree.svg new file mode 100644 index 0000000000..ece9071e03 --- /dev/null +++ b/editor/icons/CollapseTree.svg @@ -0,0 +1 @@ + diff --git a/editor/icons/ExpandTree.svg b/editor/icons/ExpandTree.svg new file mode 100644 index 0000000000..abdc1f9458 --- /dev/null +++ b/editor/icons/ExpandTree.svg @@ -0,0 +1 @@ + diff --git a/editor/icons/FontSize.svg b/editor/icons/FontSize.svg index e608d89b6a..3e148009ce 100644 --- a/editor/icons/FontSize.svg +++ b/editor/icons/FontSize.svg @@ -1 +1 @@ - + diff --git a/editor/icons/ThemeDeselectAll.svg b/editor/icons/ThemeDeselectAll.svg new file mode 100644 index 0000000000..d43ca85163 --- /dev/null +++ b/editor/icons/ThemeDeselectAll.svg @@ -0,0 +1 @@ + diff --git a/editor/icons/ThemeRemoveAllItems.svg b/editor/icons/ThemeRemoveAllItems.svg index 47ed624d04..652274a0e7 100644 --- a/editor/icons/ThemeRemoveAllItems.svg +++ b/editor/icons/ThemeRemoveAllItems.svg @@ -1 +1 @@ - + diff --git a/editor/icons/ThemeRemoveCustomItems.svg b/editor/icons/ThemeRemoveCustomItems.svg index bb8a8bd026..839f584fce 100644 --- a/editor/icons/ThemeRemoveCustomItems.svg +++ b/editor/icons/ThemeRemoveCustomItems.svg @@ -1 +1 @@ - + diff --git a/editor/icons/ThemeSelectAll.svg b/editor/icons/ThemeSelectAll.svg new file mode 100644 index 0000000000..59d9fb3387 --- /dev/null +++ b/editor/icons/ThemeSelectAll.svg @@ -0,0 +1 @@ + diff --git a/editor/icons/ThemeSelectFull.svg b/editor/icons/ThemeSelectFull.svg new file mode 100644 index 0000000000..0fabb9961a --- /dev/null +++ b/editor/icons/ThemeSelectFull.svg @@ -0,0 +1 @@ + diff --git a/editor/plugins/theme_editor_plugin.cpp b/editor/plugins/theme_editor_plugin.cpp index c765aa0319..36c1bf3a09 100644 --- a/editor/plugins/theme_editor_plugin.cpp +++ b/editor/plugins/theme_editor_plugin.cpp @@ -34,12 +34,1187 @@ #include "core/os/keyboard.h" #include "core/version.h" #include "editor/editor_scale.h" +#include "editor/progress_dialog.h" #include "scene/gui/progress_bar.h" +void ThemeItemImportTree::_update_items_tree() { + import_items_tree->clear(); + TreeItem *root = import_items_tree->create_item(); + + if (base_theme.is_null()) { + return; + } + + String filter_text = import_items_filter->get_text(); + + List types; + List names; + List filtered_names; + base_theme->get_type_list(&types); + types.sort_custom(); + + int color_amount = 0; + int constant_amount = 0; + int font_amount = 0; + int font_size_amount = 0; + int icon_amount = 0; + int stylebox_amount = 0; + + tree_color_items.clear(); + tree_constant_items.clear(); + tree_font_items.clear(); + tree_font_size_items.clear(); + tree_icon_items.clear(); + tree_stylebox_items.clear(); + + for (List::Element *E = types.front(); E; E = E->next()) { + String type_name = (String)E->get(); + + TreeItem *type_node = import_items_tree->create_item(root); + type_node->set_meta("_can_be_imported", false); + type_node->set_collapsed(true); + type_node->set_text(0, type_name); + type_node->set_cell_mode(IMPORT_ITEM, TreeItem::CELL_MODE_CHECK); + type_node->set_checked(IMPORT_ITEM, false); + type_node->set_editable(IMPORT_ITEM, true); + type_node->set_cell_mode(IMPORT_ITEM_DATA, TreeItem::CELL_MODE_CHECK); + type_node->set_checked(IMPORT_ITEM_DATA, false); + type_node->set_editable(IMPORT_ITEM_DATA, true); + + bool is_matching_filter = (filter_text.is_empty() || type_name.findn(filter_text) > -1); + bool has_filtered_items = false; + bool any_checked = false; + bool any_checked_with_data = false; + + for (int i = 0; i < Theme::DATA_TYPE_MAX; i++) { + Theme::DataType dt = (Theme::DataType)i; + + names.clear(); + filtered_names.clear(); + base_theme->get_theme_item_list(dt, E->get(), &names); + + bool data_type_has_filtered_items = false; + + for (List::Element *F = names.front(); F; F = F->next()) { + String item_name = (String)F->get(); + bool is_item_matching_filter = (item_name.findn(filter_text) > -1); + if (!filter_text.is_empty() && !is_matching_filter && !is_item_matching_filter) { + continue; + } + + // Only mark this if actual items match the filter and not just the type group. + if (!filter_text.is_empty() && is_item_matching_filter) { + has_filtered_items = true; + data_type_has_filtered_items = true; + } + filtered_names.push_back(F->get()); + } + + if (filtered_names.size() == 0) { + continue; + } + + TreeItem *data_type_node = import_items_tree->create_item(type_node); + data_type_node->set_meta("_can_be_imported", false); + data_type_node->set_metadata(0, i); + data_type_node->set_collapsed(!data_type_has_filtered_items); + data_type_node->set_cell_mode(IMPORT_ITEM, TreeItem::CELL_MODE_CHECK); + data_type_node->set_checked(IMPORT_ITEM, false); + data_type_node->set_editable(IMPORT_ITEM, true); + data_type_node->set_cell_mode(IMPORT_ITEM_DATA, TreeItem::CELL_MODE_CHECK); + data_type_node->set_checked(IMPORT_ITEM_DATA, false); + data_type_node->set_editable(IMPORT_ITEM_DATA, true); + + List *item_list; + + switch (dt) { + case Theme::DATA_TYPE_COLOR: + data_type_node->set_icon(0, get_theme_icon("Color", "EditorIcons")); + data_type_node->set_text(0, TTR("Colors")); + + item_list = &tree_color_items; + color_amount += filtered_names.size(); + break; + + case Theme::DATA_TYPE_CONSTANT: + data_type_node->set_icon(0, get_theme_icon("MemberConstant", "EditorIcons")); + data_type_node->set_text(0, TTR("Constants")); + + item_list = &tree_constant_items; + constant_amount += filtered_names.size(); + break; + + case Theme::DATA_TYPE_FONT: + data_type_node->set_icon(0, get_theme_icon("Font", "EditorIcons")); + data_type_node->set_text(0, TTR("Fonts")); + + item_list = &tree_font_items; + font_amount += filtered_names.size(); + break; + + case Theme::DATA_TYPE_FONT_SIZE: + data_type_node->set_icon(0, get_theme_icon("FontSize", "EditorIcons")); + data_type_node->set_text(0, TTR("Font Sizes")); + + item_list = &tree_font_size_items; + font_size_amount += filtered_names.size(); + break; + + case Theme::DATA_TYPE_ICON: + data_type_node->set_icon(0, get_theme_icon("ImageTexture", "EditorIcons")); + data_type_node->set_text(0, TTR("Icons")); + + item_list = &tree_icon_items; + icon_amount += filtered_names.size(); + break; + + case Theme::DATA_TYPE_STYLEBOX: + data_type_node->set_icon(0, get_theme_icon("StyleBoxFlat", "EditorIcons")); + data_type_node->set_text(0, TTR("Styleboxes")); + + item_list = &tree_stylebox_items; + stylebox_amount += filtered_names.size(); + break; + + case Theme::DATA_TYPE_MAX: + break; // Can't happen, but silences warning. + } + + bool data_type_any_checked = false; + bool data_type_any_checked_with_data = false; + + filtered_names.sort_custom(); + for (List::Element *F = filtered_names.front(); F; F = F->next()) { + TreeItem *item_node = import_items_tree->create_item(data_type_node); + item_node->set_meta("_can_be_imported", true); + item_node->set_text(0, F->get()); + item_node->set_cell_mode(IMPORT_ITEM, TreeItem::CELL_MODE_CHECK); + item_node->set_checked(IMPORT_ITEM, false); + item_node->set_editable(IMPORT_ITEM, true); + item_node->set_cell_mode(IMPORT_ITEM_DATA, TreeItem::CELL_MODE_CHECK); + item_node->set_checked(IMPORT_ITEM_DATA, false); + item_node->set_editable(IMPORT_ITEM_DATA, true); + + _restore_selected_item(item_node); + if (item_node->is_checked(IMPORT_ITEM)) { + data_type_any_checked = true; + any_checked = true; + } + if (item_node->is_checked(IMPORT_ITEM_DATA)) { + data_type_any_checked_with_data = true; + any_checked_with_data = true; + } + + item_list->push_back(item_node); + } + + data_type_node->set_checked(IMPORT_ITEM, data_type_any_checked); + data_type_node->set_checked(IMPORT_ITEM_DATA, data_type_any_checked && data_type_any_checked_with_data); + } + + // Remove the item if it doesn't match the filter in any way. + if (!is_matching_filter && !has_filtered_items) { + root->remove_child(type_node); + memdelete(type_node); + continue; + } + + // Show one level inside of a type group if there are matches in items. + if (!filter_text.is_empty() && has_filtered_items) { + type_node->set_collapsed(false); + } + + type_node->set_checked(IMPORT_ITEM, any_checked); + type_node->set_checked(IMPORT_ITEM_DATA, any_checked && any_checked_with_data); + } + + if (color_amount > 0) { + Array arr; + arr.push_back(color_amount); + select_colors_label->set_text(TTRN("One color", "{num} colors", color_amount).format(arr, "{num}")); + select_all_colors_button->set_visible(true); + select_full_colors_button->set_visible(true); + deselect_all_colors_button->set_visible(true); + } else { + select_colors_label->set_text(TTR("No colors found.")); + select_all_colors_button->set_visible(false); + select_full_colors_button->set_visible(false); + deselect_all_colors_button->set_visible(false); + } + + if (constant_amount > 0) { + Array arr; + arr.push_back(constant_amount); + select_constants_label->set_text(TTRN("One constant", "{num} constants", constant_amount).format(arr, "{num}")); + select_all_constants_button->set_visible(true); + select_full_constants_button->set_visible(true); + deselect_all_constants_button->set_visible(true); + } else { + select_constants_label->set_text(TTR("No constants found.")); + select_all_constants_button->set_visible(false); + select_full_constants_button->set_visible(false); + deselect_all_constants_button->set_visible(false); + } + + if (font_amount > 0) { + Array arr; + arr.push_back(font_amount); + select_fonts_label->set_text(TTRN("One font", "{num} fonts", font_amount).format(arr, "{num}")); + select_all_fonts_button->set_visible(true); + select_full_fonts_button->set_visible(true); + deselect_all_fonts_button->set_visible(true); + } else { + select_fonts_label->set_text(TTR("No fonts found.")); + select_all_fonts_button->set_visible(false); + select_full_fonts_button->set_visible(false); + deselect_all_fonts_button->set_visible(false); + } + + if (font_size_amount > 0) { + Array arr; + arr.push_back(font_size_amount); + select_font_sizes_label->set_text(TTRN("One font size", "{num} font sizes", font_size_amount).format(arr, "{num}")); + select_all_font_sizes_button->set_visible(true); + select_full_font_sizes_button->set_visible(true); + deselect_all_font_sizes_button->set_visible(true); + } else { + select_font_sizes_label->set_text(TTR("No font sizes found.")); + select_all_font_sizes_button->set_visible(false); + select_full_font_sizes_button->set_visible(false); + deselect_all_font_sizes_button->set_visible(false); + } + + if (icon_amount > 0) { + Array arr; + arr.push_back(icon_amount); + select_icons_label->set_text(TTRN("One icon", "{num} icons", icon_amount).format(arr, "{num}")); + select_all_icons_button->set_visible(true); + select_full_icons_button->set_visible(true); + deselect_all_icons_button->set_visible(true); + select_icons_warning_hb->set_visible(true); + } else { + select_icons_label->set_text(TTR("No icons found.")); + select_all_icons_button->set_visible(false); + select_full_icons_button->set_visible(false); + deselect_all_icons_button->set_visible(false); + select_icons_warning_hb->set_visible(false); + } + + if (stylebox_amount > 0) { + Array arr; + arr.push_back(stylebox_amount); + select_styleboxes_label->set_text(TTRN("One stylebox", "{num} styleboxes", stylebox_amount).format(arr, "{num}")); + select_all_styleboxes_button->set_visible(true); + select_full_styleboxes_button->set_visible(true); + deselect_all_styleboxes_button->set_visible(true); + } else { + select_styleboxes_label->set_text(TTR("No styleboxes found.")); + select_all_styleboxes_button->set_visible(false); + select_full_styleboxes_button->set_visible(false); + deselect_all_styleboxes_button->set_visible(false); + } +} + +void ThemeItemImportTree::_toggle_type_items(bool p_collapse) { + TreeItem *root = import_items_tree->get_root(); + if (!root) { + return; + } + + TreeItem *type_node = root->get_children(); + while (type_node) { + type_node->set_collapsed(p_collapse); + type_node = type_node->get_next(); + } +} + +void ThemeItemImportTree::_filter_text_changed(const String &p_value) { + _update_items_tree(); +} + +void ThemeItemImportTree::_store_selected_item(TreeItem *p_tree_item) { + if (!p_tree_item->get_meta("_can_be_imported")) { + return; + } + + TreeItem *data_type_node = p_tree_item->get_parent(); + if (!data_type_node || data_type_node == import_items_tree->get_root()) { + return; + } + + TreeItem *type_node = data_type_node->get_parent(); + if (!type_node || type_node == import_items_tree->get_root()) { + return; + } + + ThemeItem ti; + ti.item_name = p_tree_item->get_text(0); + ti.data_type = (Theme::DataType)(int)data_type_node->get_metadata(0); + ti.type_name = type_node->get_text(0); + + bool import = p_tree_item->is_checked(IMPORT_ITEM); + bool with_data = p_tree_item->is_checked(IMPORT_ITEM_DATA); + + if (import && with_data) { + selected_items[ti] = SELECT_IMPORT_FULL; + } else if (import) { + selected_items[ti] = SELECT_IMPORT_DEFINITION; + } else { + selected_items.erase(ti); + } + + _update_total_selected(ti.data_type); +} + +void ThemeItemImportTree::_restore_selected_item(TreeItem *p_tree_item) { + if (!p_tree_item->get_meta("_can_be_imported")) { + return; + } + + TreeItem *data_type_node = p_tree_item->get_parent(); + if (!data_type_node || data_type_node == import_items_tree->get_root()) { + return; + } + + TreeItem *type_node = data_type_node->get_parent(); + if (!type_node || type_node == import_items_tree->get_root()) { + return; + } + + ThemeItem ti; + ti.item_name = p_tree_item->get_text(0); + ti.data_type = (Theme::DataType)(int)data_type_node->get_metadata(0); + ti.type_name = type_node->get_text(0); + + if (!selected_items.has(ti)) { + p_tree_item->set_checked(IMPORT_ITEM, false); + p_tree_item->set_checked(IMPORT_ITEM_DATA, false); + return; + } + + if (selected_items[ti] == SELECT_IMPORT_FULL) { + p_tree_item->set_checked(IMPORT_ITEM, true); + p_tree_item->set_checked(IMPORT_ITEM_DATA, true); + } else if (selected_items[ti] == SELECT_IMPORT_DEFINITION) { + p_tree_item->set_checked(IMPORT_ITEM, true); + p_tree_item->set_checked(IMPORT_ITEM_DATA, false); + } +} + +void ThemeItemImportTree::_update_total_selected(Theme::DataType p_data_type) { + ERR_FAIL_INDEX_MSG(p_data_type, Theme::DATA_TYPE_MAX, "Theme item data type is out of bounds."); + + Label *total_selected_items_label; + switch (p_data_type) { + case Theme::DATA_TYPE_COLOR: + total_selected_items_label = total_selected_colors_label; + break; + + case Theme::DATA_TYPE_CONSTANT: + total_selected_items_label = total_selected_constants_label; + break; + + case Theme::DATA_TYPE_FONT: + total_selected_items_label = total_selected_fonts_label; + break; + + case Theme::DATA_TYPE_FONT_SIZE: + total_selected_items_label = total_selected_font_sizes_label; + break; + + case Theme::DATA_TYPE_ICON: + total_selected_items_label = total_selected_icons_label; + break; + + case Theme::DATA_TYPE_STYLEBOX: + total_selected_items_label = total_selected_styleboxes_label; + break; + + case Theme::DATA_TYPE_MAX: + return; // Can't happen, but silences warning. + } + + if (!total_selected_items_label) { + return; + } + + int count = 0; + for (Map::Element *E = selected_items.front(); E; E = E->next()) { + ThemeItem ti = E->key(); + if (ti.data_type == p_data_type) { + count++; + } + } + + if (count == 0) { + total_selected_items_label->hide(); + } else { + Array arr; + arr.push_back(count); + total_selected_items_label->set_text(TTRN("{num} currently selected", "{num} currently selected", count).format(arr, "{num}")); + total_selected_items_label->show(); + } +} + +void ThemeItemImportTree::_tree_item_edited() { + if (updating_tree) { + return; + } + + TreeItem *edited_item = import_items_tree->get_edited(); + if (!edited_item) { + return; + } + + updating_tree = true; + + int edited_column = import_items_tree->get_edited_column(); + bool is_checked = edited_item->is_checked(edited_column); + if (is_checked) { + if (edited_column == IMPORT_ITEM_DATA) { + edited_item->set_checked(IMPORT_ITEM, true); + } + + _select_all_subitems(edited_item, (edited_column == IMPORT_ITEM_DATA)); + } else { + if (edited_column == IMPORT_ITEM) { + edited_item->set_checked(IMPORT_ITEM_DATA, false); + } + + _deselect_all_subitems(edited_item, (edited_column == IMPORT_ITEM)); + } + + _update_parent_items(edited_item); + _store_selected_item(edited_item); + + updating_tree = false; +} + +void ThemeItemImportTree::_select_all_subitems(TreeItem *p_root_item, bool p_select_with_data) { + TreeItem *child_item = p_root_item->get_children(); + while (child_item) { + child_item->set_checked(IMPORT_ITEM, true); + if (p_select_with_data) { + child_item->set_checked(IMPORT_ITEM_DATA, true); + } + _store_selected_item(child_item); + + _select_all_subitems(child_item, p_select_with_data); + child_item = child_item->get_next(); + } +} + +void ThemeItemImportTree::_deselect_all_subitems(TreeItem *p_root_item, bool p_deselect_completely) { + TreeItem *child_item = p_root_item->get_children(); + while (child_item) { + child_item->set_checked(IMPORT_ITEM_DATA, false); + if (p_deselect_completely) { + child_item->set_checked(IMPORT_ITEM, false); + } + _store_selected_item(child_item); + + _deselect_all_subitems(child_item, p_deselect_completely); + child_item = child_item->get_next(); + } +} + +void ThemeItemImportTree::_update_parent_items(TreeItem *p_root_item) { + TreeItem *parent_item = p_root_item->get_parent(); + if (!parent_item) { + return; + } + + bool any_checked = false; + bool any_checked_with_data = false; + + TreeItem *child_item = parent_item->get_children(); + while (child_item) { + if (child_item->is_checked(IMPORT_ITEM)) { + any_checked = true; + } + if (child_item->is_checked(IMPORT_ITEM_DATA)) { + any_checked_with_data = true; + } + + child_item = child_item->get_next(); + } + + parent_item->set_checked(IMPORT_ITEM, any_checked); + parent_item->set_checked(IMPORT_ITEM_DATA, any_checked && any_checked_with_data); + _update_parent_items(parent_item); +} + +void ThemeItemImportTree::_select_all_items_pressed() { + if (updating_tree) { + return; + } + + updating_tree = true; + + TreeItem *root = import_items_tree->get_root(); + _select_all_subitems(root, false); + + updating_tree = false; +} + +void ThemeItemImportTree::_select_full_items_pressed() { + if (updating_tree) { + return; + } + + updating_tree = true; + + TreeItem *root = import_items_tree->get_root(); + _select_all_subitems(root, true); + + updating_tree = false; +} + +void ThemeItemImportTree::_deselect_all_items_pressed() { + if (updating_tree) { + return; + } + + updating_tree = true; + + TreeItem *root = import_items_tree->get_root(); + _deselect_all_subitems(root, true); + + updating_tree = false; +} + +void ThemeItemImportTree::_select_all_data_type_pressed(int p_data_type) { + ERR_FAIL_INDEX_MSG(p_data_type, Theme::DATA_TYPE_MAX, "Theme item data type is out of bounds."); + + if (updating_tree) { + return; + } + + Theme::DataType data_type = (Theme::DataType)p_data_type; + List *item_list; + + switch (data_type) { + case Theme::DATA_TYPE_COLOR: + item_list = &tree_color_items; + break; + + case Theme::DATA_TYPE_CONSTANT: + item_list = &tree_constant_items; + break; + + case Theme::DATA_TYPE_FONT: + item_list = &tree_font_items; + break; + + case Theme::DATA_TYPE_FONT_SIZE: + item_list = &tree_font_size_items; + break; + + case Theme::DATA_TYPE_ICON: + item_list = &tree_icon_items; + break; + + case Theme::DATA_TYPE_STYLEBOX: + item_list = &tree_stylebox_items; + break; + + case Theme::DATA_TYPE_MAX: + return; // Can't happen, but silences warning. + } + + updating_tree = true; + + for (List::Element *E = item_list->front(); E; E = E->next()) { + TreeItem *child_item = E->get(); + if (!child_item) { + continue; + } + + child_item->set_checked(IMPORT_ITEM, true); + _update_parent_items(child_item); + _store_selected_item(child_item); + } + + updating_tree = false; +} + +void ThemeItemImportTree::_select_full_data_type_pressed(int p_data_type) { + ERR_FAIL_INDEX_MSG(p_data_type, Theme::DATA_TYPE_MAX, "Theme item data type is out of bounds."); + + if (updating_tree) { + return; + } + + Theme::DataType data_type = (Theme::DataType)p_data_type; + List *item_list; + + switch (data_type) { + case Theme::DATA_TYPE_COLOR: + item_list = &tree_color_items; + break; + + case Theme::DATA_TYPE_CONSTANT: + item_list = &tree_constant_items; + break; + + case Theme::DATA_TYPE_FONT: + item_list = &tree_font_items; + break; + + case Theme::DATA_TYPE_FONT_SIZE: + item_list = &tree_font_size_items; + break; + + case Theme::DATA_TYPE_ICON: + item_list = &tree_icon_items; + break; + + case Theme::DATA_TYPE_STYLEBOX: + item_list = &tree_stylebox_items; + break; + + case Theme::DATA_TYPE_MAX: + return; // Can't happen, but silences warning. + } + + updating_tree = true; + + for (List::Element *E = item_list->front(); E; E = E->next()) { + TreeItem *child_item = E->get(); + if (!child_item) { + continue; + } + + child_item->set_checked(IMPORT_ITEM, true); + child_item->set_checked(IMPORT_ITEM_DATA, true); + _update_parent_items(child_item); + _store_selected_item(child_item); + } + + updating_tree = false; +} + +void ThemeItemImportTree::_deselect_all_data_type_pressed(int p_data_type) { + ERR_FAIL_INDEX_MSG(p_data_type, Theme::DATA_TYPE_MAX, "Theme item data type is out of bounds."); + + if (updating_tree) { + return; + } + + Theme::DataType data_type = (Theme::DataType)p_data_type; + List *item_list; + + switch (data_type) { + case Theme::DATA_TYPE_COLOR: + item_list = &tree_color_items; + break; + + case Theme::DATA_TYPE_CONSTANT: + item_list = &tree_constant_items; + break; + + case Theme::DATA_TYPE_FONT: + item_list = &tree_font_items; + break; + + case Theme::DATA_TYPE_FONT_SIZE: + item_list = &tree_font_size_items; + break; + + case Theme::DATA_TYPE_ICON: + item_list = &tree_icon_items; + break; + + case Theme::DATA_TYPE_STYLEBOX: + item_list = &tree_stylebox_items; + break; + + case Theme::DATA_TYPE_MAX: + return; // Can't happen, but silences warning. + } + + updating_tree = true; + + for (List::Element *E = item_list->front(); E; E = E->next()) { + TreeItem *child_item = E->get(); + if (!child_item) { + continue; + } + + child_item->set_checked(IMPORT_ITEM, false); + child_item->set_checked(IMPORT_ITEM_DATA, false); + _update_parent_items(child_item); + _store_selected_item(child_item); + } + + updating_tree = false; +} + +void ThemeItemImportTree::_import_selected() { + if (selected_items.size() == 0) { + EditorNode::get_singleton()->show_accept(TTR("Nothing was selected for the import."), TTR("OK")); + return; + } + + ProgressDialog::get_singleton()->add_task("import_theme_items", TTR("Importing Theme Items"), selected_items.size()); + + int idx = 0; + for (Map::Element *E = selected_items.front(); E; E = E->next()) { + // Arbitrary number of items to skip from reporting. + // Reduces the number of UI updates that this causes when copying large themes. + if (idx % 10 == 0) { + Array arr; + arr.push_back(idx + 1); + arr.push_back(selected_items.size()); + ProgressDialog::get_singleton()->task_step("import_theme_items", TTR("Importing items {n}/{n}").format(arr, "{n}"), idx); + } + + ItemCheckedState cs = E->get(); + ThemeItem ti = E->key(); + + if (cs == SELECT_IMPORT_DEFINITION || cs == SELECT_IMPORT_FULL) { + Variant item_value = Variant(); + + if (cs == SELECT_IMPORT_FULL) { + item_value = base_theme->get_theme_item(ti.data_type, ti.item_name, ti.type_name); + } else { + switch (ti.data_type) { + case Theme::DATA_TYPE_COLOR: + item_value = Color(); + break; + + case Theme::DATA_TYPE_CONSTANT: + item_value = 0; + break; + + case Theme::DATA_TYPE_FONT: + item_value = Ref(); + break; + + case Theme::DATA_TYPE_FONT_SIZE: + item_value = -1; + break; + + case Theme::DATA_TYPE_ICON: + item_value = Ref(); + break; + + case Theme::DATA_TYPE_STYLEBOX: + item_value = Ref(); + break; + + case Theme::DATA_TYPE_MAX: + break; // Can't happen, but silences warning. + } + } + + edited_theme->set_theme_item(ti.data_type, ti.item_name, ti.type_name, item_value); + } + + idx++; + } + + ProgressDialog::get_singleton()->end_task("import_theme_items"); + emit_signal("items_imported"); +} + +void ThemeItemImportTree::set_edited_theme(const Ref &p_theme) { + edited_theme = p_theme; +} + +void ThemeItemImportTree::set_base_theme(const Ref &p_theme) { + base_theme = p_theme; +} + +void ThemeItemImportTree::reset_item_tree() { + import_items_filter->clear(); + selected_items.clear(); + + total_selected_colors_label->hide(); + total_selected_constants_label->hide(); + total_selected_fonts_label->hide(); + total_selected_font_sizes_label->hide(); + total_selected_icons_label->hide(); + total_selected_styleboxes_label->hide(); + + _update_items_tree(); +} + +bool ThemeItemImportTree::has_selected_items() const { + return (selected_items.size() > 0); +} + +void ThemeItemImportTree::_notification(int p_what) { + switch (p_what) { + case NOTIFICATION_ENTER_TREE: + case NOTIFICATION_THEME_CHANGED: { + select_icons_warning_icon->set_texture(get_theme_icon("StatusWarning", "EditorIcons")); + select_icons_warning->add_theme_color_override("font_color", get_theme_color("disabled_font_color", "Editor")); + + // Bottom panel buttons. + import_collapse_types_button->set_icon(get_theme_icon("CollapseTree", "EditorIcons")); + import_expand_types_button->set_icon(get_theme_icon("ExpandTree", "EditorIcons")); + + import_select_all_button->set_icon(get_theme_icon("ThemeSelectAll", "EditorIcons")); + import_select_full_button->set_icon(get_theme_icon("ThemeSelectFull", "EditorIcons")); + import_deselect_all_button->set_icon(get_theme_icon("ThemeDeselectAll", "EditorIcons")); + + // Side panel buttons. + select_colors_icon->set_texture(get_theme_icon("Color", "EditorIcons")); + deselect_all_colors_button->set_icon(get_theme_icon("ThemeDeselectAll", "EditorIcons")); + select_all_colors_button->set_icon(get_theme_icon("ThemeSelectAll", "EditorIcons")); + select_full_colors_button->set_icon(get_theme_icon("ThemeSelectFull", "EditorIcons")); + + select_constants_icon->set_texture(get_theme_icon("MemberConstant", "EditorIcons")); + deselect_all_constants_button->set_icon(get_theme_icon("ThemeDeselectAll", "EditorIcons")); + select_all_constants_button->set_icon(get_theme_icon("ThemeSelectAll", "EditorIcons")); + select_full_constants_button->set_icon(get_theme_icon("ThemeSelectFull", "EditorIcons")); + + select_fonts_icon->set_texture(get_theme_icon("Font", "EditorIcons")); + deselect_all_fonts_button->set_icon(get_theme_icon("ThemeDeselectAll", "EditorIcons")); + select_all_fonts_button->set_icon(get_theme_icon("ThemeSelectAll", "EditorIcons")); + select_full_fonts_button->set_icon(get_theme_icon("ThemeSelectFull", "EditorIcons")); + + select_font_sizes_icon->set_texture(get_theme_icon("FontSize", "EditorIcons")); + deselect_all_font_sizes_button->set_icon(get_theme_icon("ThemeDeselectAll", "EditorIcons")); + select_all_font_sizes_button->set_icon(get_theme_icon("ThemeSelectAll", "EditorIcons")); + select_full_font_sizes_button->set_icon(get_theme_icon("ThemeSelectFull", "EditorIcons")); + + select_icons_icon->set_texture(get_theme_icon("ImageTexture", "EditorIcons")); + deselect_all_icons_button->set_icon(get_theme_icon("ThemeDeselectAll", "EditorIcons")); + select_all_icons_button->set_icon(get_theme_icon("ThemeSelectAll", "EditorIcons")); + select_full_icons_button->set_icon(get_theme_icon("ThemeSelectFull", "EditorIcons")); + + select_styleboxes_icon->set_texture(get_theme_icon("StyleBoxFlat", "EditorIcons")); + deselect_all_styleboxes_button->set_icon(get_theme_icon("ThemeDeselectAll", "EditorIcons")); + select_all_styleboxes_button->set_icon(get_theme_icon("ThemeSelectAll", "EditorIcons")); + select_full_styleboxes_button->set_icon(get_theme_icon("ThemeSelectFull", "EditorIcons")); + } break; + } +} + +void ThemeItemImportTree::_bind_methods() { + ADD_SIGNAL(MethodInfo("items_imported")); +} + +ThemeItemImportTree::ThemeItemImportTree() { + HBoxContainer *import_items_filter_hb = memnew(HBoxContainer); + add_child(import_items_filter_hb); + Label *import_items_filter_label = memnew(Label); + import_items_filter_label->set_text(TTR("Filter:")); + import_items_filter_hb->add_child(import_items_filter_label); + import_items_filter = memnew(LineEdit); + import_items_filter->set_clear_button_enabled(true); + import_items_filter->set_h_size_flags(Control::SIZE_EXPAND_FILL); + import_items_filter_hb->add_child(import_items_filter); + import_items_filter->connect("text_changed", callable_mp(this, &ThemeItemImportTree::_filter_text_changed)); + + HBoxContainer *import_main_hb = memnew(HBoxContainer); + import_main_hb->set_v_size_flags(Control::SIZE_EXPAND_FILL); + add_child(import_main_hb); + + import_items_tree = memnew(Tree); + import_items_tree->set_hide_root(true); + import_items_tree->set_h_size_flags(Control::SIZE_EXPAND_FILL); + import_main_hb->add_child(import_items_tree); + import_items_tree->connect("item_edited", callable_mp(this, &ThemeItemImportTree::_tree_item_edited)); + + import_items_tree->set_columns(3); + import_items_tree->set_column_titles_visible(true); + import_items_tree->set_column_title(IMPORT_ITEM, TTR("Import")); + import_items_tree->set_column_title(IMPORT_ITEM_DATA, TTR("With Data")); + import_items_tree->set_column_expand(0, true); + import_items_tree->set_column_expand(IMPORT_ITEM, false); + import_items_tree->set_column_expand(IMPORT_ITEM_DATA, false); + import_items_tree->set_column_min_width(0, 160 * EDSCALE); + import_items_tree->set_column_min_width(IMPORT_ITEM, 80 * EDSCALE); + import_items_tree->set_column_min_width(IMPORT_ITEM_DATA, 80 * EDSCALE); + + ScrollContainer *import_bulk_sc = memnew(ScrollContainer); + import_bulk_sc->set_custom_minimum_size(Size2(260.0, 0.0) * EDSCALE); + import_bulk_sc->set_enable_h_scroll(false); + import_main_hb->add_child(import_bulk_sc); + VBoxContainer *import_bulk_vb = memnew(VBoxContainer); + import_bulk_vb->set_h_size_flags(Control::SIZE_EXPAND_FILL); + import_bulk_sc->add_child(import_bulk_vb); + + Label *import_bulk_label = memnew(Label); + import_bulk_label->set_text(TTR("Select by data type:")); + import_bulk_vb->add_child(import_bulk_label); + + select_colors_icon = memnew(TextureRect); + select_colors_label = memnew(Label); + deselect_all_colors_button = memnew(Button); + select_all_colors_button = memnew(Button); + select_full_colors_button = memnew(Button); + total_selected_colors_label = memnew(Label); + + select_constants_icon = memnew(TextureRect); + select_constants_label = memnew(Label); + deselect_all_constants_button = memnew(Button); + select_all_constants_button = memnew(Button); + select_full_constants_button = memnew(Button); + total_selected_constants_label = memnew(Label); + + select_fonts_icon = memnew(TextureRect); + select_fonts_label = memnew(Label); + deselect_all_fonts_button = memnew(Button); + select_all_fonts_button = memnew(Button); + select_full_fonts_button = memnew(Button); + total_selected_fonts_label = memnew(Label); + + select_font_sizes_icon = memnew(TextureRect); + select_font_sizes_label = memnew(Label); + deselect_all_font_sizes_button = memnew(Button); + select_all_font_sizes_button = memnew(Button); + select_full_font_sizes_button = memnew(Button); + total_selected_font_sizes_label = memnew(Label); + + select_icons_icon = memnew(TextureRect); + select_icons_label = memnew(Label); + deselect_all_icons_button = memnew(Button); + select_all_icons_button = memnew(Button); + select_full_icons_button = memnew(Button); + total_selected_icons_label = memnew(Label); + + select_styleboxes_icon = memnew(TextureRect); + select_styleboxes_label = memnew(Label); + deselect_all_styleboxes_button = memnew(Button); + select_all_styleboxes_button = memnew(Button); + select_full_styleboxes_button = memnew(Button); + total_selected_styleboxes_label = memnew(Label); + + for (int i = 0; i < Theme::DATA_TYPE_MAX; i++) { + Theme::DataType dt = (Theme::DataType)i; + + TextureRect *select_items_icon; + Label *select_items_label; + Button *deselect_all_items_button; + Button *select_all_items_button; + Button *select_full_items_button; + Label *total_selected_items_label; + + String items_title = ""; + String select_all_items_tooltip = ""; + String select_full_items_tooltip = ""; + String deselect_all_items_tooltip = ""; + + switch (dt) { + case Theme::DATA_TYPE_COLOR: + select_items_icon = select_colors_icon; + select_items_label = select_colors_label; + deselect_all_items_button = deselect_all_colors_button; + select_all_items_button = select_all_colors_button; + select_full_items_button = select_full_colors_button; + total_selected_items_label = total_selected_colors_label; + + items_title = TTR("Colors"); + select_all_items_tooltip = TTR("Select all visible color items."); + select_full_items_tooltip = TTR("Select all visible color items and their data."); + deselect_all_items_tooltip = TTR("Deselect all visible color items."); + break; + + case Theme::DATA_TYPE_CONSTANT: + select_items_icon = select_constants_icon; + select_items_label = select_constants_label; + deselect_all_items_button = deselect_all_constants_button; + select_all_items_button = select_all_constants_button; + select_full_items_button = select_full_constants_button; + total_selected_items_label = total_selected_constants_label; + + items_title = TTR("Constants"); + select_all_items_tooltip = TTR("Select all visible constant items."); + select_full_items_tooltip = TTR("Select all visible constant items and their data."); + deselect_all_items_tooltip = TTR("Deselect all visible constant items."); + break; + + case Theme::DATA_TYPE_FONT: + select_items_icon = select_fonts_icon; + select_items_label = select_fonts_label; + deselect_all_items_button = deselect_all_fonts_button; + select_all_items_button = select_all_fonts_button; + select_full_items_button = select_full_fonts_button; + total_selected_items_label = total_selected_fonts_label; + + items_title = TTR("Fonts"); + select_all_items_tooltip = TTR("Select all visible font items."); + select_full_items_tooltip = TTR("Select all visible font items and their data."); + deselect_all_items_tooltip = TTR("Deselect all visible font items."); + break; + + case Theme::DATA_TYPE_FONT_SIZE: + select_items_icon = select_font_sizes_icon; + select_items_label = select_font_sizes_label; + deselect_all_items_button = deselect_all_font_sizes_button; + select_all_items_button = select_all_font_sizes_button; + select_full_items_button = select_full_font_sizes_button; + total_selected_items_label = total_selected_font_sizes_label; + + items_title = TTR("Font sizes"); + select_all_items_tooltip = TTR("Select all visible font size items."); + select_full_items_tooltip = TTR("Select all visible font size items and their data."); + deselect_all_items_tooltip = TTR("Deselect all visible font size items."); + break; + + case Theme::DATA_TYPE_ICON: + select_items_icon = select_icons_icon; + select_items_label = select_icons_label; + deselect_all_items_button = deselect_all_icons_button; + select_all_items_button = select_all_icons_button; + select_full_items_button = select_full_icons_button; + total_selected_items_label = total_selected_icons_label; + + items_title = TTR("Icons"); + select_all_items_tooltip = TTR("Select all visible icon items."); + select_full_items_tooltip = TTR("Select all visible icon items and their data."); + deselect_all_items_tooltip = TTR("Deselect all visible icon items."); + break; + + case Theme::DATA_TYPE_STYLEBOX: + select_items_icon = select_styleboxes_icon; + select_items_label = select_styleboxes_label; + deselect_all_items_button = deselect_all_styleboxes_button; + select_all_items_button = select_all_styleboxes_button; + select_full_items_button = select_full_styleboxes_button; + total_selected_items_label = total_selected_styleboxes_label; + + items_title = TTR("Styleboxes"); + select_all_items_tooltip = TTR("Select all visible stylebox items."); + select_full_items_tooltip = TTR("Select all visible stylebox items and their data."); + deselect_all_items_tooltip = TTR("Deselect all visible stylebox items."); + break; + + case Theme::DATA_TYPE_MAX: + continue; // Can't happen, but silences warning. + } + + if (i > 0) { + import_bulk_vb->add_child(memnew(HSeparator)); + } + + HBoxContainer *all_set = memnew(HBoxContainer); + import_bulk_vb->add_child(all_set); + + HBoxContainer *label_set = memnew(HBoxContainer); + label_set->set_h_size_flags(Control::SIZE_EXPAND_FILL); + all_set->add_child(label_set); + select_items_icon->set_v_size_flags(Control::SIZE_SHRINK_CENTER); + label_set->add_child(select_items_icon); + select_items_label->set_h_size_flags(Control::SIZE_EXPAND_FILL); + select_items_label->set_clip_text(true); + select_items_label->set_text(items_title); + label_set->add_child(select_items_label); + + HBoxContainer *button_set = memnew(HBoxContainer); + button_set->set_alignment(BoxContainer::ALIGN_END); + all_set->add_child(button_set); + select_all_items_button->set_flat(true); + select_all_items_button->set_tooltip(select_all_items_tooltip); + button_set->add_child(select_all_items_button); + select_all_items_button->connect("pressed", callable_mp(this, &ThemeItemImportTree::_select_all_data_type_pressed), varray(i)); + select_full_items_button->set_flat(true); + select_full_items_button->set_tooltip(select_full_items_tooltip); + button_set->add_child(select_full_items_button); + select_full_items_button->connect("pressed", callable_mp(this, &ThemeItemImportTree::_select_full_data_type_pressed), varray(i)); + deselect_all_items_button->set_flat(true); + deselect_all_items_button->set_tooltip(deselect_all_items_tooltip); + button_set->add_child(deselect_all_items_button); + deselect_all_items_button->connect("pressed", callable_mp(this, &ThemeItemImportTree::_deselect_all_data_type_pressed), varray(i)); + + total_selected_items_label->set_align(Label::ALIGN_RIGHT); + total_selected_items_label->hide(); + import_bulk_vb->add_child(total_selected_items_label); + + if (dt == Theme::DATA_TYPE_ICON) { + select_icons_warning_hb = memnew(HBoxContainer); + import_bulk_vb->add_child(select_icons_warning_hb); + + select_icons_warning_icon = memnew(TextureRect); + select_icons_warning_icon->set_v_size_flags(Control::SIZE_SHRINK_CENTER); + select_icons_warning_hb->add_child(select_icons_warning_icon); + + select_icons_warning = memnew(Label); + select_icons_warning->set_text(TTR("Caution: Adding icon data may considerably increase the size of your Theme resource.")); + select_icons_warning->set_autowrap(true); + select_icons_warning->set_h_size_flags(Control::SIZE_EXPAND_FILL); + select_icons_warning_hb->add_child(select_icons_warning); + } + } + + add_child(memnew(HSeparator)); + + HBoxContainer *import_buttons = memnew(HBoxContainer); + add_child(import_buttons); + + import_collapse_types_button = memnew(Button); + import_collapse_types_button->set_flat(true); + import_collapse_types_button->set_tooltip(TTR("Collapse types.")); + import_buttons->add_child(import_collapse_types_button); + import_collapse_types_button->connect("pressed", callable_mp(this, &ThemeItemImportTree::_toggle_type_items), varray(true)); + import_expand_types_button = memnew(Button); + import_expand_types_button->set_flat(true); + import_expand_types_button->set_tooltip(TTR("Expand types.")); + import_buttons->add_child(import_expand_types_button); + import_expand_types_button->connect("pressed", callable_mp(this, &ThemeItemImportTree::_toggle_type_items), varray(false)); + + import_buttons->add_child(memnew(VSeparator)); + + import_select_all_button = memnew(Button); + import_select_all_button->set_flat(true); + import_select_all_button->set_text(TTR("Select All")); + import_select_all_button->set_tooltip(TTR("Select all Theme items.")); + import_buttons->add_child(import_select_all_button); + import_select_all_button->connect("pressed", callable_mp(this, &ThemeItemImportTree::_select_all_items_pressed)); + import_select_full_button = memnew(Button); + import_select_full_button->set_flat(true); + import_select_full_button->set_text(TTR("Select With Data")); + import_select_full_button->set_tooltip(TTR("Select all Theme items with item data.")); + import_buttons->add_child(import_select_full_button); + import_select_full_button->connect("pressed", callable_mp(this, &ThemeItemImportTree::_select_full_items_pressed)); + import_deselect_all_button = memnew(Button); + import_deselect_all_button->set_flat(true); + import_deselect_all_button->set_text(TTR("Deselect All")); + import_deselect_all_button->set_tooltip(TTR("Deselect all Theme items.")); + import_buttons->add_child(import_deselect_all_button); + import_deselect_all_button->connect("pressed", callable_mp(this, &ThemeItemImportTree::_deselect_all_items_pressed)); + + import_buttons->add_spacer(); + + Button *import_add_selected_button = memnew(Button); + import_add_selected_button->set_text(TTR("Import Selected")); + import_buttons->add_child(import_add_selected_button); + import_add_selected_button->connect("pressed", callable_mp(this, &ThemeItemImportTree::_import_selected)); +} + +void ThemeItemEditorDialog::ok_pressed() { + if (import_default_theme_items->has_selected_items() || import_editor_theme_items->has_selected_items() || import_other_theme_items->has_selected_items()) { + confirm_closing_dialog->set_text(TTR("Import Items tab has some items selected. Selection will be lost upon closing this window.\nClose anyway?")); + confirm_closing_dialog->popup_centered(Size2i(380, 120) * EDSCALE); + return; + } + + hide(); +} + +void ThemeItemEditorDialog::_close_dialog() { + hide(); +} + void ThemeItemEditorDialog::_dialog_about_to_show() { ERR_FAIL_COND(edited_theme.is_null()); _update_edit_types(); + + import_default_theme_items->set_edited_theme(edited_theme); + import_default_theme_items->set_base_theme(Theme::get_default()); + import_default_theme_items->reset_item_tree(); + + import_editor_theme_items->set_edited_theme(edited_theme); + import_editor_theme_items->set_base_theme(EditorNode::get_singleton()->get_theme_base()->get_theme()); + import_editor_theme_items->reset_item_tree(); + + import_other_theme_items->set_edited_theme(edited_theme); + import_other_theme_items->reset_item_tree(); } void ThemeItemEditorDialog::_update_edit_types() { @@ -79,11 +1254,6 @@ void ThemeItemEditorDialog::_update_edit_types() { base_theme->get_type_list(&default_types); default_types.sort_custom(); - edit_add_class_options->clear(); - for (List::Element *E = default_types.front(); E; E = E->next()) { - edit_add_class_options->add_item(E->get()); - } - String selected_type = ""; Vector selected_ids = edit_type_list->get_selected_items(); if (selected_ids.size() > 0) { @@ -127,7 +1297,7 @@ void ThemeItemEditorDialog::_update_edit_item_tree(String p_item_type) { List names; - { + { // Colors. names.clear(); edited_theme->get_color_list(p_item_type, &names); @@ -148,7 +1318,7 @@ void ThemeItemEditorDialog::_update_edit_item_tree(String p_item_type) { } } - { + { // Constants. names.clear(); edited_theme->get_constant_list(p_item_type, &names); @@ -169,7 +1339,7 @@ void ThemeItemEditorDialog::_update_edit_item_tree(String p_item_type) { } } - { + { // Fonts. names.clear(); edited_theme->get_font_list(p_item_type, &names); @@ -190,7 +1360,7 @@ void ThemeItemEditorDialog::_update_edit_item_tree(String p_item_type) { } } - { + { // Font sizes. names.clear(); edited_theme->get_font_size_list(p_item_type, &names); @@ -211,7 +1381,7 @@ void ThemeItemEditorDialog::_update_edit_item_tree(String p_item_type) { } } - { + { // Icons. names.clear(); edited_theme->get_icon_list(p_item_type, &names); @@ -232,7 +1402,7 @@ void ThemeItemEditorDialog::_update_edit_item_tree(String p_item_type) { } } - { + { // Styleboxes. names.clear(); edited_theme->get_stylebox_list(p_item_type, &names); @@ -280,64 +1450,13 @@ void ThemeItemEditorDialog::_item_tree_button_pressed(Object *p_item, int p_colu _update_edit_item_tree(edited_item_type); } -void ThemeItemEditorDialog::_add_class_type_items() { - int selected_idx = edit_add_class_options->get_selected(); - String type_name = edit_add_class_options->get_item_text(selected_idx); - List names; - - { - names.clear(); - Theme::get_default()->get_icon_list(type_name, &names); - for (List::Element *E = names.front(); E; E = E->next()) { - edited_theme->set_icon(E->get(), type_name, Ref()); - } - } - { - names.clear(); - Theme::get_default()->get_stylebox_list(type_name, &names); - for (List::Element *E = names.front(); E; E = E->next()) { - edited_theme->set_stylebox(E->get(), type_name, Ref()); - } - } - { - names.clear(); - Theme::get_default()->get_font_list(type_name, &names); - for (List::Element *E = names.front(); E; E = E->next()) { - edited_theme->set_font(E->get(), type_name, Ref()); - } - } - { - names.clear(); - Theme::get_default()->get_font_size_list(type_name, &names); - for (List::Element *E = names.front(); E; E = E->next()) { - edited_theme->set_font_size(E->get(), type_name, Theme::get_default()->get_font_size(E->get(), type_name)); - } - } - { - names.clear(); - Theme::get_default()->get_color_list(type_name, &names); - for (List::Element *E = names.front(); E; E = E->next()) { - edited_theme->set_color(E->get(), type_name, Theme::get_default()->get_color(E->get(), type_name)); - } - } - { - names.clear(); - Theme::get_default()->get_constant_list(type_name, &names); - for (List::Element *E = names.front(); E; E = E->next()) { - edited_theme->set_constant(E->get(), type_name, Theme::get_default()->get_constant(E->get(), type_name)); - } - } - - _update_edit_types(); -} - -void ThemeItemEditorDialog::_add_custom_type() { - edited_theme->add_icon_type(edit_add_custom_value->get_text()); - edited_theme->add_stylebox_type(edit_add_custom_value->get_text()); - edited_theme->add_font_type(edit_add_custom_value->get_text()); - edited_theme->add_font_size_type(edit_add_custom_value->get_text()); - edited_theme->add_color_type(edit_add_custom_value->get_text()); - edited_theme->add_constant_type(edit_add_custom_value->get_text()); +void ThemeItemEditorDialog::_add_theme_type() { + edited_theme->add_icon_type(edit_add_type_value->get_text()); + edited_theme->add_stylebox_type(edit_add_type_value->get_text()); + edited_theme->add_font_type(edit_add_type_value->get_text()); + edited_theme->add_font_size_type(edit_add_type_value->get_text()); + edited_theme->add_color_type(edit_add_type_value->get_text()); + edited_theme->add_constant_type(edit_add_type_value->get_text()); _update_edit_types(); } @@ -536,6 +1655,26 @@ void ThemeItemEditorDialog::_edit_theme_item_gui_input(const Ref &p_ } } +void ThemeItemEditorDialog::_open_select_another_theme() { + import_another_theme_dialog->popup_file_dialog(); +} + +void ThemeItemEditorDialog::_select_another_theme_cbk(const String &p_path) { + Ref loaded_theme = ResourceLoader::load(p_path); + if (loaded_theme.is_null()) { + EditorNode::get_singleton()->show_warning(TTR("Invalid file, not a Theme resource.")); + return; + } + if (loaded_theme == edited_theme) { + EditorNode::get_singleton()->show_warning(TTR("Invalid file, same as the edited Theme resource.")); + return; + } + + import_another_theme_value->set_text(p_path); + import_other_theme_items->set_base_theme(loaded_theme); + import_other_theme_items->reset_item_tree(); +} + void ThemeItemEditorDialog::_notification(int p_what) { switch (p_what) { case NOTIFICATION_ENTER_TREE: { @@ -553,6 +1692,8 @@ void ThemeItemEditorDialog::_notification(int p_what) { edit_items_remove_class->set_icon(get_theme_icon("Control", "EditorIcons")); edit_items_remove_custom->set_icon(get_theme_icon("ThemeRemoveCustomItems", "EditorIcons")); edit_items_remove_all->set_icon(get_theme_icon("ThemeRemoveAllItems", "EditorIcons")); + + import_another_theme_button->set_icon(get_theme_icon("Folder", "EditorIcons")); } break; } } @@ -562,10 +1703,18 @@ void ThemeItemEditorDialog::set_edited_theme(const Ref &p_theme) { } ThemeItemEditorDialog::ThemeItemEditorDialog() { - set_title(TTR("Edit Theme Items")); + set_title(TTR("Manage Theme Items")); + get_ok_button()->set_text(TTR("Close")); + set_hide_on_ok(false); // Closing may require a confirmation in some cases. + TabContainer *tc = memnew(TabContainer); + tc->set_tab_align(TabContainer::TabAlign::ALIGN_LEFT); + add_child(tc); + + // Edit Items tab. HSplitContainer *edit_dialog_hs = memnew(HSplitContainer); - add_child(edit_dialog_hs); + tc->add_child(edit_dialog_hs); + tc->set_tab_title(0, TTR("Edit Items")); VBoxContainer *edit_dialog_side_vb = memnew(VBoxContainer); edit_dialog_side_vb->set_custom_minimum_size(Size2(200.0, 0.0) * EDSCALE); @@ -580,33 +1729,19 @@ ThemeItemEditorDialog::ThemeItemEditorDialog() { edit_dialog_side_vb->add_child(edit_type_list); edit_type_list->connect("item_selected", callable_mp(this, &ThemeItemEditorDialog::_edited_type_selected)); - Label *edit_add_class_label = memnew(Label); - edit_add_class_label->set_text(TTR("Add Type from Class:")); - edit_dialog_side_vb->add_child(edit_add_class_label); + Label *edit_add_type_label = memnew(Label); + edit_add_type_label->set_text(TTR("Add Type:")); + edit_dialog_side_vb->add_child(edit_add_type_label); - HBoxContainer *edit_add_class = memnew(HBoxContainer); - edit_dialog_side_vb->add_child(edit_add_class); - edit_add_class_options = memnew(OptionButton); - edit_add_class_options->set_h_size_flags(Control::SIZE_EXPAND_FILL); - edit_add_class->add_child(edit_add_class_options); - Button *edit_add_class_button = memnew(Button); - edit_add_class_button->set_text(TTR("Add")); - edit_add_class->add_child(edit_add_class_button); - edit_add_class_button->connect("pressed", callable_mp(this, &ThemeItemEditorDialog::_add_class_type_items)); - - Label *edit_add_custom_label = memnew(Label); - edit_add_custom_label->set_text(TTR("Add Custom Type:")); - edit_dialog_side_vb->add_child(edit_add_custom_label); - - HBoxContainer *edit_add_custom = memnew(HBoxContainer); - edit_dialog_side_vb->add_child(edit_add_custom); - edit_add_custom_value = memnew(LineEdit); - edit_add_custom_value->set_h_size_flags(Control::SIZE_EXPAND_FILL); - edit_add_custom->add_child(edit_add_custom_value); - Button *edit_add_custom_button = memnew(Button); - edit_add_custom_button->set_text(TTR("Add")); - edit_add_custom->add_child(edit_add_custom_button); - edit_add_custom_button->connect("pressed", callable_mp(this, &ThemeItemEditorDialog::_add_custom_type)); + HBoxContainer *edit_add_type_hb = memnew(HBoxContainer); + edit_dialog_side_vb->add_child(edit_add_type_hb); + edit_add_type_value = memnew(LineEdit); + edit_add_type_value->set_h_size_flags(Control::SIZE_EXPAND_FILL); + edit_add_type_hb->add_child(edit_add_type_value); + Button *edit_add_type_button = memnew(Button); + edit_add_type_button->set_text(TTR("Add")); + edit_add_type_hb->add_child(edit_add_type_button); + edit_add_type_button->connect("pressed", callable_mp(this, &ThemeItemEditorDialog::_add_theme_type)); VBoxContainer *edit_items_vb = memnew(VBoxContainer); edit_items_vb->set_h_size_flags(Control::SIZE_EXPAND_FILL); @@ -616,7 +1751,7 @@ ThemeItemEditorDialog::ThemeItemEditorDialog() { edit_items_vb->add_child(edit_items_toolbar); Label *edit_items_toolbar_add_label = memnew(Label); - edit_items_toolbar_add_label->set_text(TTR("Add:")); + edit_items_toolbar_add_label->set_text(TTR("Add Item:")); edit_items_toolbar->add_child(edit_items_toolbar_add_label); edit_items_add_color = memnew(Button); @@ -664,7 +1799,7 @@ ThemeItemEditorDialog::ThemeItemEditorDialog() { edit_items_toolbar->add_child(memnew(VSeparator)); Label *edit_items_toolbar_remove_label = memnew(Label); - edit_items_toolbar_remove_label->set_text(TTR("Remove:")); + edit_items_toolbar_remove_label->set_text(TTR("Remove Items:")); edit_items_toolbar->add_child(edit_items_toolbar_remove_label); edit_items_remove_class = memnew(Button); @@ -716,6 +1851,57 @@ ThemeItemEditorDialog::ThemeItemEditorDialog() { edit_theme_item_vb->add_child(theme_item_name); theme_item_name->connect("gui_input", callable_mp(this, &ThemeItemEditorDialog::_edit_theme_item_gui_input)); edit_theme_item_dialog->connect("confirmed", callable_mp(this, &ThemeItemEditorDialog::_confirm_edit_theme_item)); + + // Import Items tab. + TabContainer *import_tc = memnew(TabContainer); + tc->add_child(import_tc); + tc->set_tab_title(1, TTR("Import Items")); + + import_default_theme_items = memnew(ThemeItemImportTree); + import_tc->add_child(import_default_theme_items); + import_tc->set_tab_title(0, TTR("Default Theme")); + import_default_theme_items->connect("items_imported", callable_mp(this, &ThemeItemEditorDialog::_update_edit_types)); + + import_editor_theme_items = memnew(ThemeItemImportTree); + import_tc->add_child(import_editor_theme_items); + import_tc->set_tab_title(1, TTR("Editor Theme")); + import_editor_theme_items->connect("items_imported", callable_mp(this, &ThemeItemEditorDialog::_update_edit_types)); + + VBoxContainer *import_another_theme_vb = memnew(VBoxContainer); + + HBoxContainer *import_another_file_hb = memnew(HBoxContainer); + import_another_theme_vb->add_child(import_another_file_hb); + import_another_theme_value = memnew(LineEdit); + import_another_theme_value->set_h_size_flags(Control::SIZE_EXPAND_FILL); + import_another_theme_value->set_editable(false); + import_another_file_hb->add_child(import_another_theme_value); + import_another_theme_button = memnew(Button); + import_another_file_hb->add_child(import_another_theme_button); + import_another_theme_button->connect("pressed", callable_mp(this, &ThemeItemEditorDialog::_open_select_another_theme)); + + import_another_theme_dialog = memnew(EditorFileDialog); + import_another_theme_dialog->set_file_mode(EditorFileDialog::FILE_MODE_OPEN_FILE); + import_another_theme_dialog->set_title(TTR("Select Another Theme Resource:")); + List ext; + ResourceLoader::get_recognized_extensions_for_type("Theme", &ext); + for (List::Element *E = ext.front(); E; E = E->next()) { + import_another_theme_dialog->add_filter("*." + E->get() + "; Theme Resource"); + } + import_another_file_hb->add_child(import_another_theme_dialog); + import_another_theme_dialog->connect("file_selected", callable_mp(this, &ThemeItemEditorDialog::_select_another_theme_cbk)); + + import_other_theme_items = memnew(ThemeItemImportTree); + import_other_theme_items->set_v_size_flags(Control::SIZE_EXPAND_FILL); + import_another_theme_vb->add_child(import_other_theme_items); + + import_tc->add_child(import_another_theme_vb); + import_tc->set_tab_title(2, TTR("Another Theme")); + import_other_theme_items->connect("items_imported", callable_mp(this, &ThemeItemEditorDialog::_update_edit_types)); + + confirm_closing_dialog = memnew(ConfirmationDialog); + confirm_closing_dialog->set_autowrap(true); + add_child(confirm_closing_dialog); + confirm_closing_dialog->connect("confirmed", callable_mp(this, &ThemeItemEditorDialog::_close_dialog)); } void ThemeEditor::edit(const Ref &p_theme) { @@ -742,299 +1928,8 @@ void ThemeEditor::_refresh_interval() { _propagate_redraw(main_container); } -struct _TECategory { - template - struct RefItem { - Ref item; - StringName name; - bool operator<(const RefItem &p) const { return item->get_instance_id() < p.item->get_instance_id(); } - }; - - template - struct Item { - T item; - String name; - bool operator<(const Item &p) const { return name < p.name; } - }; - - Set> stylebox_items; - Set> font_items; - Set> font_size_items; - Set> icon_items; - - Set> color_items; - Set> constant_items; -}; - -void ThemeEditor::_save_template_cbk(String fname) { - String filename = file_dialog->get_current_path(); - - Map categories; - - // Fill types. - List type_list; - Theme::get_default()->get_type_list(&type_list); - for (List::Element *E = type_list.front(); E; E = E->next()) { - categories.insert(E->get(), _TECategory()); - } - - // Fill default theme. - for (Map::Element *E = categories.front(); E; E = E->next()) { - _TECategory &tc = E->get(); - - List stylebox_list; - Theme::get_default()->get_stylebox_list(E->key(), &stylebox_list); - for (List::Element *F = stylebox_list.front(); F; F = F->next()) { - _TECategory::RefItem it; - it.name = F->get(); - it.item = Theme::get_default()->get_stylebox(F->get(), E->key()); - tc.stylebox_items.insert(it); - } - - List font_list; - Theme::get_default()->get_font_list(E->key(), &font_list); - for (List::Element *F = font_list.front(); F; F = F->next()) { - _TECategory::RefItem it; - it.name = F->get(); - it.item = Theme::get_default()->get_font(F->get(), E->key()); - tc.font_items.insert(it); - } - - List font_size_list; - Theme::get_default()->get_font_size_list(E->key(), &font_list); - for (List::Element *F = font_size_list.front(); F; F = F->next()) { - _TECategory::Item it; - it.name = F->get(); - it.item = Theme::get_default()->get_font_size(F->get(), E->key()); - tc.font_size_items.insert(it); - } - - List icon_list; - Theme::get_default()->get_icon_list(E->key(), &icon_list); - for (List::Element *F = icon_list.front(); F; F = F->next()) { - _TECategory::RefItem it; - it.name = F->get(); - it.item = Theme::get_default()->get_icon(F->get(), E->key()); - tc.icon_items.insert(it); - } - - List color_list; - Theme::get_default()->get_color_list(E->key(), &color_list); - for (List::Element *F = color_list.front(); F; F = F->next()) { - _TECategory::Item it; - it.name = F->get(); - it.item = Theme::get_default()->get_color(F->get(), E->key()); - tc.color_items.insert(it); - } - - List constant_list; - Theme::get_default()->get_constant_list(E->key(), &constant_list); - for (List::Element *F = constant_list.front(); F; F = F->next()) { - _TECategory::Item it; - it.name = F->get(); - it.item = Theme::get_default()->get_constant(F->get(), E->key()); - tc.constant_items.insert(it); - } - } - - FileAccess *file = FileAccess::open(filename, FileAccess::WRITE); - - ERR_FAIL_COND_MSG(!file, "Can't save theme to file '" + filename + "'."); - - file->store_line("; ******************* "); - file->store_line("; Template Theme File "); - file->store_line("; ******************* "); - file->store_line("; "); - file->store_line("; Theme Syntax: "); - file->store_line("; ------------- "); - file->store_line("; "); - file->store_line("; Must be placed in section [theme]"); - file->store_line("; "); - file->store_line("; Type.item = [value] "); - file->store_line("; "); - file->store_line("; [value] examples:"); - file->store_line("; "); - file->store_line("; Type.item = 6 ; numeric constant. "); - file->store_line("; Type.item = #FF00FF ; HTML color (magenta)."); - file->store_line("; Type.item = #FF00FF55 ; HTML color (magenta with alpha 0x55)."); - file->store_line("; Type.item = icon(image.png) ; icon in a png file (relative to theme file)."); - file->store_line("; Type.item = font(font.xres) ; font in a resource (relative to theme file)."); - file->store_line("; Type.item = sbox(stylebox.xres) ; stylebox in a resource (relative to theme file)."); - file->store_line("; Type.item = sboxf(2,#FF00FF) ; flat stylebox with margin 2."); - file->store_line("; Type.item = sboxf(2,#FF00FF,#FFFFFF) ; flat stylebox with margin 2 and border."); - file->store_line("; Type.item = sboxf(2,#FF00FF,#FFFFFF,#000000) ; flat stylebox with margin 2, light & dark borders."); - file->store_line("; Type.item = sboxt(base.png,2,2,2,2) ; textured stylebox with 3x3 stretch and stretch margins."); - file->store_line("; -Additionally, 4 extra integers can be added to sboxf and sboxt to specify custom padding of contents:"); - file->store_line("; Type.item = sboxt(base.png,2,2,2,2,5,4,2,4) ;"); - file->store_line("; -Order for all is always left, top, right, bottom."); - file->store_line("; "); - file->store_line("; Special values:"); - file->store_line("; Type.item = default ; use the value in the default theme (must exist there)."); - file->store_line("; Type.item = @somebutton_color ; reference to a library value previously defined."); - file->store_line("; "); - file->store_line("; Library Syntax: "); - file->store_line("; --------------- "); - file->store_line("; "); - file->store_line("; Must be placed in section [library], but usage is optional."); - file->store_line("; "); - file->store_line("; item = [value] ; same as Theme, but assign to library."); - file->store_line("; "); - file->store_line("; examples:"); - file->store_line("; "); - file->store_line("; [library]"); - file->store_line("; "); - file->store_line("; default_button_color = #FF00FF"); - file->store_line("; "); - file->store_line("; [theme]"); - file->store_line("; "); - file->store_line("; Button.color = @default_button_color ; used reference."); - file->store_line("; "); - file->store_line("; ******************* "); - file->store_line("; "); - file->store_line("; Template Generated Using: " + String(VERSION_FULL_BUILD)); - file->store_line("; "); - file->store_line("; "); - file->store_line(""); - file->store_line("[library]"); - file->store_line(""); - file->store_line("; place library stuff here"); - file->store_line(""); - file->store_line("[theme]"); - file->store_line(""); - file->store_line(""); - - // Write default theme. - for (Map::Element *E = categories.front(); E; E = E->next()) { - _TECategory &tc = E->get(); - - String underline = "; "; - for (int i = 0; i < E->key().length(); i++) { - underline += "*"; - } - - file->store_line(""); - file->store_line(underline); - file->store_line("; " + E->key()); - file->store_line(underline); - - if (tc.stylebox_items.size()) { - file->store_line("\n; StyleBox Items:\n"); - } - - for (Set<_TECategory::RefItem>::Element *F = tc.stylebox_items.front(); F; F = F->next()) { - file->store_line(E->key() + "." + F->get().name + " = default"); - } - - if (tc.font_items.size()) { - file->store_line("\n; Font Items:\n"); - } - - for (Set<_TECategory::RefItem>::Element *F = tc.font_items.front(); F; F = F->next()) { - file->store_line(E->key() + "." + F->get().name + " = default"); - } - - if (tc.font_size_items.size()) { - file->store_line("\n; Font Size Items:\n"); - } - - for (Set<_TECategory::Item>::Element *F = tc.font_size_items.front(); F; F = F->next()) { - file->store_line(E->key() + "." + F->get().name + " = default"); - } - - if (tc.icon_items.size()) { - file->store_line("\n; Icon Items:\n"); - } - - for (Set<_TECategory::RefItem>::Element *F = tc.icon_items.front(); F; F = F->next()) { - file->store_line(E->key() + "." + F->get().name + " = default"); - } - - if (tc.color_items.size()) { - file->store_line("\n; Color Items:\n"); - } - - for (Set<_TECategory::Item>::Element *F = tc.color_items.front(); F; F = F->next()) { - file->store_line(E->key() + "." + F->get().name + " = default"); - } - - if (tc.constant_items.size()) { - file->store_line("\n; Constant Items:\n"); - } - - for (Set<_TECategory::Item>::Element *F = tc.constant_items.front(); F; F = F->next()) { - file->store_line(E->key() + "." + F->get().name + " = default"); - } - } - - file->close(); - memdelete(file); -} - -void ThemeEditor::_theme_create_menu_cbk(int p_option) { - bool import = (p_option == POPUP_IMPORT_EDITOR_THEME); - - Ref base_theme; - - if (p_option == POPUP_CREATE_EMPTY) { - base_theme = Theme::get_default(); - } else { - base_theme = EditorNode::get_singleton()->get_theme_base()->get_theme(); - } - - { - List types; - base_theme->get_type_list(&types); - - for (List::Element *T = types.front(); T; T = T->next()) { - StringName type = T->get(); - - List icons; - base_theme->get_icon_list(type, &icons); - - for (List::Element *E = icons.front(); E; E = E->next()) { - theme->set_icon(E->get(), type, import ? base_theme->get_icon(E->get(), type) : Ref()); - } - - List styleboxs; - base_theme->get_stylebox_list(type, &styleboxs); - - for (List::Element *E = styleboxs.front(); E; E = E->next()) { - theme->set_stylebox(E->get(), type, import ? base_theme->get_stylebox(E->get(), type) : Ref()); - } - - List fonts; - base_theme->get_font_list(type, &fonts); - - for (List::Element *E = fonts.front(); E; E = E->next()) { - theme->set_font(E->get(), type, Ref()); - } - - List font_sizes; - base_theme->get_font_size_list(type, &font_sizes); - - for (List::Element *E = font_sizes.front(); E; E = E->next()) { - theme->set_font_size(E->get(), type, base_theme->get_font_size(E->get(), type)); - } - - List colors; - base_theme->get_color_list(type, &colors); - - for (List::Element *E = colors.front(); E; E = E->next()) { - theme->set_color(E->get(), type, import ? base_theme->get_color(E->get(), type) : Color()); - } - - List constants; - base_theme->get_constant_list(type, &constants); - - for (List::Element *E = constants.front(); E; E = E->next()) { - theme->set_constant(E->get(), type, base_theme->get_constant(E->get(), type)); - } - } - } -} - void ThemeEditor::_theme_edit_button_cbk() { - theme_edit_dialog->popup_centered(Size2(800, 640) * EDSCALE); + theme_edit_dialog->popup_centered(Size2(850, 760) * EDSCALE); } void ThemeEditor::_notification(int p_what) { @@ -1059,19 +1954,9 @@ ThemeEditor::ThemeEditor() { top_menu->add_child(memnew(Label(TTR("Preview:")))); top_menu->add_spacer(false); - theme_create_menu = memnew(MenuButton); - theme_create_menu->set_text(TTR("Create Theme...")); - theme_create_menu->set_tooltip(TTR("Create a new Theme.")); - theme_create_menu->get_popup()->add_item(TTR("Empty Template"), POPUP_CREATE_EMPTY); - theme_create_menu->get_popup()->add_separator(); - theme_create_menu->get_popup()->add_item(TTR("Empty Editor Template"), POPUP_CREATE_EDITOR_EMPTY); - theme_create_menu->get_popup()->add_item(TTR("From Current Editor Theme"), POPUP_IMPORT_EDITOR_THEME); - top_menu->add_child(theme_create_menu); - theme_create_menu->get_popup()->connect("id_pressed", callable_mp(this, &ThemeEditor::_theme_create_menu_cbk)); - theme_edit_button = memnew(Button); - theme_edit_button->set_text(TTR("Edit Theme Items")); - theme_edit_button->set_tooltip(TTR("Customize Theme items.")); + theme_edit_button->set_text(TTR("Manage Items")); + theme_edit_button->set_tooltip(TTR("Add, remove, organize and import Theme items.")); theme_edit_button->set_flat(true); theme_edit_button->connect("pressed", callable_mp(this, &ThemeEditor::_theme_edit_button_cbk)); top_menu->add_child(theme_edit_button); @@ -1260,11 +2145,6 @@ ThemeEditor::ThemeEditor() { theme_edit_dialog = memnew(ThemeItemEditorDialog); theme_edit_dialog->hide(); add_child(theme_edit_dialog); - - file_dialog = memnew(EditorFileDialog); - file_dialog->add_filter("*.theme ; " + TTR("Theme File")); - add_child(file_dialog); - file_dialog->connect("file_selected", callable_mp(this, &ThemeEditor::_save_template_cbk)); } void ThemeEditorPlugin::edit(Object *p_node) { diff --git a/editor/plugins/theme_editor_plugin.h b/editor/plugins/theme_editor_plugin.h index 0a840aecd7..5f4de68f45 100644 --- a/editor/plugins/theme_editor_plugin.h +++ b/editor/plugins/theme_editor_plugin.h @@ -41,14 +41,148 @@ #include "editor/editor_node.h" +class ThemeItemImportTree : public VBoxContainer { + GDCLASS(ThemeItemImportTree, VBoxContainer); + + Ref edited_theme; + Ref base_theme; + + struct ThemeItem { + String type_name; + Theme::DataType data_type; + String item_name; + + bool operator<(const ThemeItem &p_item) const { + if (type_name == p_item.type_name && data_type == p_item.data_type) { + return item_name < p_item.item_name; + } + if (type_name == p_item.type_name) { + return data_type < p_item.data_type; + } + return type_name < p_item.type_name; + } + }; + + enum ItemCheckedState { + SELECT_IMPORT_DEFINITION, + SELECT_IMPORT_FULL, + }; + + Map selected_items; + + LineEdit *import_items_filter; + + Tree *import_items_tree; + List tree_color_items; + List tree_constant_items; + List tree_font_items; + List tree_font_size_items; + List tree_icon_items; + List tree_stylebox_items; + + bool updating_tree = false; + + enum ItemActionFlag { + IMPORT_ITEM = 1, + IMPORT_ITEM_DATA = 2, + }; + + TextureRect *select_colors_icon; + Label *select_colors_label; + Button *select_all_colors_button; + Button *select_full_colors_button; + Button *deselect_all_colors_button; + Label *total_selected_colors_label; + + TextureRect *select_constants_icon; + Label *select_constants_label; + Button *select_all_constants_button; + Button *select_full_constants_button; + Button *deselect_all_constants_button; + Label *total_selected_constants_label; + + TextureRect *select_fonts_icon; + Label *select_fonts_label; + Button *select_all_fonts_button; + Button *select_full_fonts_button; + Button *deselect_all_fonts_button; + Label *total_selected_fonts_label; + + TextureRect *select_font_sizes_icon; + Label *select_font_sizes_label; + Button *select_all_font_sizes_button; + Button *select_full_font_sizes_button; + Button *deselect_all_font_sizes_button; + Label *total_selected_font_sizes_label; + + TextureRect *select_icons_icon; + Label *select_icons_label; + Button *select_all_icons_button; + Button *select_full_icons_button; + Button *deselect_all_icons_button; + Label *total_selected_icons_label; + + TextureRect *select_styleboxes_icon; + Label *select_styleboxes_label; + Button *select_all_styleboxes_button; + Button *select_full_styleboxes_button; + Button *deselect_all_styleboxes_button; + Label *total_selected_styleboxes_label; + + HBoxContainer *select_icons_warning_hb; + TextureRect *select_icons_warning_icon; + Label *select_icons_warning; + + Button *import_collapse_types_button; + Button *import_expand_types_button; + Button *import_select_all_button; + Button *import_select_full_button; + Button *import_deselect_all_button; + + void _update_items_tree(); + void _toggle_type_items(bool p_collapse); + void _filter_text_changed(const String &p_value); + + void _store_selected_item(TreeItem *p_tree_item); + void _restore_selected_item(TreeItem *p_tree_item); + void _update_total_selected(Theme::DataType p_data_type); + + void _tree_item_edited(); + void _select_all_subitems(TreeItem *p_root_item, bool p_select_with_data); + void _deselect_all_subitems(TreeItem *p_root_item, bool p_deselect_completely); + void _update_parent_items(TreeItem *p_root_item); + + void _select_all_items_pressed(); + void _select_full_items_pressed(); + void _deselect_all_items_pressed(); + + void _select_all_data_type_pressed(int p_data_type); + void _select_full_data_type_pressed(int p_data_type); + void _deselect_all_data_type_pressed(int p_data_type); + + void _import_selected(); + +protected: + void _notification(int p_what); + static void _bind_methods(); + +public: + void set_edited_theme(const Ref &p_theme); + void set_base_theme(const Ref &p_theme); + void reset_item_tree(); + + bool has_selected_items() const; + + ThemeItemImportTree(); +}; + class ThemeItemEditorDialog : public AcceptDialog { GDCLASS(ThemeItemEditorDialog, AcceptDialog); Ref edited_theme; ItemList *edit_type_list; - OptionButton *edit_add_class_options; - LineEdit *edit_add_custom_value; + LineEdit *edit_add_type_value; String edited_item_type; Button *edit_items_add_color; @@ -83,6 +217,19 @@ class ThemeItemEditorDialog : public AcceptDialog { String edit_item_old_name; Theme::DataType edit_item_data_type = Theme::DATA_TYPE_MAX; + ThemeItemImportTree *import_default_theme_items; + ThemeItemImportTree *import_editor_theme_items; + ThemeItemImportTree *import_other_theme_items; + + LineEdit *import_another_theme_value; + Button *import_another_theme_button; + EditorFileDialog *import_another_theme_dialog; + + ConfirmationDialog *confirm_closing_dialog; + + void ok_pressed() override; + void _close_dialog(); + void _dialog_about_to_show(); void _update_edit_types(); void _edited_type_selected(int p_item_idx); @@ -90,8 +237,7 @@ class ThemeItemEditorDialog : public AcceptDialog { 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_class_type_items(); - void _add_custom_type(); + void _add_theme_type(); void _add_theme_item(Theme::DataType p_data_type, String p_item_name, String p_item_type); void _remove_data_type_items(Theme::DataType p_data_type, String p_item_type); void _remove_class_items(); @@ -103,6 +249,9 @@ class ThemeItemEditorDialog : public AcceptDialog { void _confirm_edit_theme_item(); void _edit_theme_item_gui_input(const Ref &p_event); + void _open_select_another_theme(); + void _select_another_theme_cbk(const String &p_path); + protected: void _notification(int p_what); @@ -115,29 +264,18 @@ public: class ThemeEditor : public VBoxContainer { GDCLASS(ThemeEditor, VBoxContainer); - Panel *main_panel; - MarginContainer *main_container; Ref theme; - EditorFileDialog *file_dialog; - double time_left = 0; Button *theme_edit_button; - MenuButton *theme_create_menu; ThemeItemEditorDialog *theme_edit_dialog; - enum CreatePopupMode { - POPUP_CREATE_EMPTY, - POPUP_CREATE_EDITOR_EMPTY, - POPUP_IMPORT_EDITOR_THEME, - }; - + Panel *main_panel; + MarginContainer *main_container; Tree *test_tree; - void _save_template_cbk(String fname); void _theme_edit_button_cbk(); - void _theme_create_menu_cbk(int p_option); void _propagate_redraw(Control *p_at); void _refresh_interval();