Path: blob/master/editor/scene/gui/theme_editor_plugin.cpp
9902 views
/**************************************************************************/1/* theme_editor_plugin.cpp */2/**************************************************************************/3/* This file is part of: */4/* GODOT ENGINE */5/* https://godotengine.org */6/**************************************************************************/7/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */8/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */9/* */10/* Permission is hereby granted, free of charge, to any person obtaining */11/* a copy of this software and associated documentation files (the */12/* "Software"), to deal in the Software without restriction, including */13/* without limitation the rights to use, copy, modify, merge, publish, */14/* distribute, sublicense, and/or sell copies of the Software, and to */15/* permit persons to whom the Software is furnished to do so, subject to */16/* the following conditions: */17/* */18/* The above copyright notice and this permission notice shall be */19/* included in all copies or substantial portions of the Software. */20/* */21/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */22/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */23/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */24/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */25/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */26/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */27/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */28/**************************************************************************/2930#include "theme_editor_plugin.h"3132#include "editor/doc/editor_help.h"33#include "editor/docks/filesystem_dock.h"34#include "editor/docks/inspector_dock.h"35#include "editor/editor_node.h"36#include "editor/editor_string_names.h"37#include "editor/editor_undo_redo_manager.h"38#include "editor/file_system/editor_file_system.h"39#include "editor/gui/editor_bottom_panel.h"40#include "editor/gui/editor_file_dialog.h"41#include "editor/gui/progress_dialog.h"42#include "editor/inspector/editor_resource_picker.h"43#include "editor/settings/editor_command_palette.h"44#include "editor/themes/editor_scale.h"45#include "scene/gui/check_button.h"46#include "scene/gui/color_picker.h"47#include "scene/gui/item_list.h"48#include "scene/gui/option_button.h"49#include "scene/gui/panel_container.h"50#include "scene/gui/scroll_container.h"51#include "scene/gui/separator.h"52#include "scene/gui/spin_box.h"53#include "scene/gui/split_container.h"54#include "scene/gui/tab_bar.h"55#include "scene/gui/tab_container.h"56#include "scene/gui/texture_rect.h"57#include "scene/theme/theme_db.h"5859static void _rename_theme_type(EditorUndoRedoManager *p_ur, Theme *p_theme, const String &p_old_theme_type, const String &p_new_theme_type) {60p_ur->add_do_method(p_theme, "rename_type", p_old_theme_type, p_new_theme_type);61p_ur->add_undo_method(p_theme, "rename_type", p_new_theme_type, p_old_theme_type);6263// Renaming a theme type to an empty name or a variation to a type associated with a built-in class64// removes type variation connections in a way that cannot be undone by reversing the rename alone.65const StringName old_base_type = p_theme->get_type_variation_base(p_old_theme_type);66if ((!p_old_theme_type.is_empty() && p_new_theme_type.is_empty()) || (old_base_type != StringName() && ClassDB::class_exists(p_new_theme_type))) {67if (old_base_type != StringName()) {68p_ur->add_undo_method(p_theme, "set_type_variation", p_old_theme_type, old_base_type);69}7071List<StringName> names;72p_theme->get_type_variation_list(p_old_theme_type, &names);73for (const StringName &E : names) {74p_ur->add_undo_method(p_theme, "set_type_variation", E, p_old_theme_type);75}76}77}7879///////////////////////8081void ThemeItemImportTree::_update_items_tree() {82import_items_tree->clear();83TreeItem *root = import_items_tree->create_item();8485if (base_theme.is_null()) {86return;87}8889String filter_text = import_items_filter->get_text();9091List<StringName> types;92List<StringName> names;93List<StringName> filtered_names;94base_theme->get_type_list(&types);95types.sort_custom<StringName::AlphCompare>();9697int color_amount = 0;98int constant_amount = 0;99int font_amount = 0;100int font_size_amount = 0;101int icon_amount = 0;102int stylebox_amount = 0;103104tree_color_items.clear();105tree_constant_items.clear();106tree_font_items.clear();107tree_font_size_items.clear();108tree_icon_items.clear();109tree_stylebox_items.clear();110111for (const StringName &E : types) {112String type_name = (String)E;113114Ref<Texture2D> type_icon;115if (E == "") {116type_icon = get_editor_theme_icon(SNAME("NodeDisabled"));117} else {118type_icon = EditorNode::get_singleton()->get_class_icon(E, "NodeDisabled");119}120121TreeItem *type_node = import_items_tree->create_item(root);122type_node->set_meta("_can_be_imported", false);123type_node->set_collapsed(true);124type_node->set_icon(0, type_icon);125type_node->set_text(0, type_name);126type_node->set_cell_mode(IMPORT_ITEM, TreeItem::CELL_MODE_CHECK);127type_node->set_checked(IMPORT_ITEM, false);128type_node->set_editable(IMPORT_ITEM, true);129type_node->set_cell_mode(IMPORT_ITEM_DATA, TreeItem::CELL_MODE_CHECK);130type_node->set_checked(IMPORT_ITEM_DATA, false);131type_node->set_editable(IMPORT_ITEM_DATA, true);132133bool is_matching_filter = (filter_text.is_empty() || type_name.containsn(filter_text));134bool has_filtered_items = false;135136for (int i = 0; i < Theme::DATA_TYPE_MAX; i++) {137Theme::DataType dt = (Theme::DataType)i;138139names.clear();140filtered_names.clear();141base_theme->get_theme_item_list(dt, E, &names);142143bool data_type_has_filtered_items = false;144145for (const StringName &F : names) {146String item_name = (String)F;147bool is_item_matching_filter = item_name.containsn(filter_text);148if (!filter_text.is_empty() && !is_matching_filter && !is_item_matching_filter) {149continue;150}151152// Only mark this if actual items match the filter and not just the type group.153if (!filter_text.is_empty() && is_item_matching_filter) {154has_filtered_items = true;155data_type_has_filtered_items = true;156}157filtered_names.push_back(F);158}159160if (filtered_names.is_empty()) {161continue;162}163164TreeItem *data_type_node = import_items_tree->create_item(type_node);165data_type_node->set_meta("_can_be_imported", false);166data_type_node->set_metadata(0, i);167data_type_node->set_collapsed(!data_type_has_filtered_items);168data_type_node->set_cell_mode(IMPORT_ITEM, TreeItem::CELL_MODE_CHECK);169data_type_node->set_checked(IMPORT_ITEM, false);170data_type_node->set_editable(IMPORT_ITEM, true);171data_type_node->set_cell_mode(IMPORT_ITEM_DATA, TreeItem::CELL_MODE_CHECK);172data_type_node->set_checked(IMPORT_ITEM_DATA, false);173data_type_node->set_editable(IMPORT_ITEM_DATA, true);174175List<TreeItem *> *item_list = nullptr;176177switch (dt) {178case Theme::DATA_TYPE_COLOR:179data_type_node->set_icon(0, get_editor_theme_icon(SNAME("Color")));180data_type_node->set_text(0, TTR("Colors"));181182item_list = &tree_color_items;183color_amount += filtered_names.size();184break;185186case Theme::DATA_TYPE_CONSTANT:187data_type_node->set_icon(0, get_editor_theme_icon(SNAME("MemberConstant")));188data_type_node->set_text(0, TTR("Constants"));189190item_list = &tree_constant_items;191constant_amount += filtered_names.size();192break;193194case Theme::DATA_TYPE_FONT:195data_type_node->set_icon(0, get_editor_theme_icon(SNAME("FontItem")));196data_type_node->set_text(0, TTR("Fonts"));197198item_list = &tree_font_items;199font_amount += filtered_names.size();200break;201202case Theme::DATA_TYPE_FONT_SIZE:203data_type_node->set_icon(0, get_editor_theme_icon(SNAME("FontSize")));204data_type_node->set_text(0, TTR("Font Sizes"));205206item_list = &tree_font_size_items;207font_size_amount += filtered_names.size();208break;209210case Theme::DATA_TYPE_ICON:211data_type_node->set_icon(0, get_editor_theme_icon(SNAME("ImageTexture")));212data_type_node->set_text(0, TTR("Icons"));213214item_list = &tree_icon_items;215icon_amount += filtered_names.size();216break;217218case Theme::DATA_TYPE_STYLEBOX:219data_type_node->set_icon(0, get_editor_theme_icon(SNAME("StyleBoxFlat")));220data_type_node->set_text(0, TTR("Styleboxes"));221222item_list = &tree_stylebox_items;223stylebox_amount += filtered_names.size();224break;225226case Theme::DATA_TYPE_MAX:227break; // Can't happen, but silences warning.228}229230filtered_names.sort_custom<StringName::AlphCompare>();231for (const StringName &F : filtered_names) {232TreeItem *item_node = import_items_tree->create_item(data_type_node);233item_node->set_meta("_can_be_imported", true);234item_node->set_text(0, F);235item_node->set_cell_mode(IMPORT_ITEM, TreeItem::CELL_MODE_CHECK);236item_node->set_checked(IMPORT_ITEM, false);237item_node->set_editable(IMPORT_ITEM, true);238item_node->set_cell_mode(IMPORT_ITEM_DATA, TreeItem::CELL_MODE_CHECK);239item_node->set_checked(IMPORT_ITEM_DATA, false);240item_node->set_editable(IMPORT_ITEM_DATA, true);241242_restore_selected_item(item_node);243item_node->propagate_check(IMPORT_ITEM, false);244item_node->propagate_check(IMPORT_ITEM_DATA, false);245246item_list->push_back(item_node);247}248}249250// Remove the item if it doesn't match the filter in any way.251if (!is_matching_filter && !has_filtered_items) {252root->remove_child(type_node);253memdelete(type_node);254continue;255}256257// Show one level inside of a type group if there are matches in items.258if (!filter_text.is_empty() && has_filtered_items) {259type_node->set_collapsed(false);260}261}262263if (color_amount > 0) {264Array arr = { color_amount };265select_colors_label->set_text(TTRN("1 color", "{num} colors", color_amount).format(arr, "{num}"));266select_all_colors_button->set_visible(true);267select_full_colors_button->set_visible(true);268deselect_all_colors_button->set_visible(true);269} else {270select_colors_label->set_text(TTR("No colors found."));271select_all_colors_button->set_visible(false);272select_full_colors_button->set_visible(false);273deselect_all_colors_button->set_visible(false);274}275276if (constant_amount > 0) {277Array arr = { constant_amount };278select_constants_label->set_text(TTRN("1 constant", "{num} constants", constant_amount).format(arr, "{num}"));279select_all_constants_button->set_visible(true);280select_full_constants_button->set_visible(true);281deselect_all_constants_button->set_visible(true);282} else {283select_constants_label->set_text(TTR("No constants found."));284select_all_constants_button->set_visible(false);285select_full_constants_button->set_visible(false);286deselect_all_constants_button->set_visible(false);287}288289if (font_amount > 0) {290Array arr = { font_amount };291select_fonts_label->set_text(TTRN("1 font", "{num} fonts", font_amount).format(arr, "{num}"));292select_all_fonts_button->set_visible(true);293select_full_fonts_button->set_visible(true);294deselect_all_fonts_button->set_visible(true);295} else {296select_fonts_label->set_text(TTR("No fonts found."));297select_all_fonts_button->set_visible(false);298select_full_fonts_button->set_visible(false);299deselect_all_fonts_button->set_visible(false);300}301302if (font_size_amount > 0) {303Array arr = { font_size_amount };304select_font_sizes_label->set_text(TTRN("1 font size", "{num} font sizes", font_size_amount).format(arr, "{num}"));305select_all_font_sizes_button->set_visible(true);306select_full_font_sizes_button->set_visible(true);307deselect_all_font_sizes_button->set_visible(true);308} else {309select_font_sizes_label->set_text(TTR("No font sizes found."));310select_all_font_sizes_button->set_visible(false);311select_full_font_sizes_button->set_visible(false);312deselect_all_font_sizes_button->set_visible(false);313}314315if (icon_amount > 0) {316Array arr = { icon_amount };317select_icons_label->set_text(TTRN("1 icon", "{num} icons", icon_amount).format(arr, "{num}"));318select_all_icons_button->set_visible(true);319select_full_icons_button->set_visible(true);320deselect_all_icons_button->set_visible(true);321select_icons_warning_hb->set_visible(true);322} else {323select_icons_label->set_text(TTR("No icons found."));324select_all_icons_button->set_visible(false);325select_full_icons_button->set_visible(false);326deselect_all_icons_button->set_visible(false);327select_icons_warning_hb->set_visible(false);328}329330if (stylebox_amount > 0) {331Array arr = { stylebox_amount };332select_styleboxes_label->set_text(TTRN("1 stylebox", "{num} styleboxes", stylebox_amount).format(arr, "{num}"));333select_all_styleboxes_button->set_visible(true);334select_full_styleboxes_button->set_visible(true);335deselect_all_styleboxes_button->set_visible(true);336} else {337select_styleboxes_label->set_text(TTR("No styleboxes found."));338select_all_styleboxes_button->set_visible(false);339select_full_styleboxes_button->set_visible(false);340deselect_all_styleboxes_button->set_visible(false);341}342}343344void ThemeItemImportTree::_toggle_type_items(bool p_collapse) {345TreeItem *root = import_items_tree->get_root();346if (!root) {347return;348}349350TreeItem *type_node = root->get_first_child();351while (type_node) {352type_node->set_collapsed(p_collapse);353type_node = type_node->get_next();354}355}356357void ThemeItemImportTree::_filter_text_changed(const String &p_value) {358_update_items_tree();359}360361void ThemeItemImportTree::_store_selected_item(TreeItem *p_tree_item) {362if (!p_tree_item->get_meta("_can_be_imported")) {363return;364}365366TreeItem *data_type_node = p_tree_item->get_parent();367if (!data_type_node || data_type_node == import_items_tree->get_root()) {368return;369}370371TreeItem *type_node = data_type_node->get_parent();372if (!type_node || type_node == import_items_tree->get_root()) {373return;374}375376ThemeItem ti;377ti.item_name = p_tree_item->get_text(0);378ti.data_type = (Theme::DataType)(int)data_type_node->get_metadata(0);379ti.type_name = type_node->get_text(0);380381bool import = p_tree_item->is_checked(IMPORT_ITEM);382bool with_data = p_tree_item->is_checked(IMPORT_ITEM_DATA);383384if (import && with_data) {385selected_items[ti] = SELECT_IMPORT_FULL;386} else if (import) {387selected_items[ti] = SELECT_IMPORT_DEFINITION;388} else {389selected_items.erase(ti);390}391392_update_total_selected(ti.data_type);393}394395void ThemeItemImportTree::_restore_selected_item(TreeItem *p_tree_item) {396if (!p_tree_item->get_meta("_can_be_imported")) {397return;398}399400TreeItem *data_type_node = p_tree_item->get_parent();401if (!data_type_node || data_type_node == import_items_tree->get_root()) {402return;403}404405TreeItem *type_node = data_type_node->get_parent();406if (!type_node || type_node == import_items_tree->get_root()) {407return;408}409410ThemeItem ti;411ti.item_name = p_tree_item->get_text(0);412ti.data_type = (Theme::DataType)(int)data_type_node->get_metadata(0);413ti.type_name = type_node->get_text(0);414415if (!selected_items.has(ti)) {416p_tree_item->set_checked(IMPORT_ITEM, false);417p_tree_item->set_checked(IMPORT_ITEM_DATA, false);418return;419}420421if (selected_items[ti] == SELECT_IMPORT_FULL) {422p_tree_item->set_checked(IMPORT_ITEM, true);423p_tree_item->set_checked(IMPORT_ITEM_DATA, true);424} else if (selected_items[ti] == SELECT_IMPORT_DEFINITION) {425p_tree_item->set_checked(IMPORT_ITEM, true);426p_tree_item->set_checked(IMPORT_ITEM_DATA, false);427}428}429430void ThemeItemImportTree::_update_total_selected(Theme::DataType p_data_type) {431ERR_FAIL_INDEX_MSG(p_data_type, Theme::DATA_TYPE_MAX, "Theme item data type is out of bounds.");432433Label *total_selected_items_label = nullptr;434switch (p_data_type) {435case Theme::DATA_TYPE_COLOR:436total_selected_items_label = total_selected_colors_label;437break;438439case Theme::DATA_TYPE_CONSTANT:440total_selected_items_label = total_selected_constants_label;441break;442443case Theme::DATA_TYPE_FONT:444total_selected_items_label = total_selected_fonts_label;445break;446447case Theme::DATA_TYPE_FONT_SIZE:448total_selected_items_label = total_selected_font_sizes_label;449break;450451case Theme::DATA_TYPE_ICON:452total_selected_items_label = total_selected_icons_label;453break;454455case Theme::DATA_TYPE_STYLEBOX:456total_selected_items_label = total_selected_styleboxes_label;457break;458459case Theme::DATA_TYPE_MAX:460return; // Can't happen, but silences warning.461}462463if (!total_selected_items_label) {464return;465}466467int count = 0;468for (const KeyValue<ThemeItem, ItemCheckedState> &E : selected_items) {469ThemeItem ti = E.key;470if (ti.data_type == p_data_type) {471count++;472}473}474475if (count == 0) {476total_selected_items_label->hide();477} else {478Array arr = { count };479total_selected_items_label->set_text(TTRN("{num} currently selected", "{num} currently selected", count).format(arr, "{num}"));480total_selected_items_label->show();481}482}483484void ThemeItemImportTree::_tree_item_edited() {485if (updating_tree) {486return;487}488489TreeItem *edited_item = import_items_tree->get_edited();490if (!edited_item) {491return;492}493494updating_tree = true;495496int edited_column = import_items_tree->get_edited_column();497bool is_checked = edited_item->is_checked(edited_column);498if (is_checked) {499if (edited_column == IMPORT_ITEM_DATA) {500edited_item->set_checked(IMPORT_ITEM, true);501edited_item->propagate_check(IMPORT_ITEM);502}503} else {504if (edited_column == IMPORT_ITEM) {505edited_item->set_checked(IMPORT_ITEM_DATA, false);506edited_item->propagate_check(IMPORT_ITEM_DATA);507}508}509edited_item->propagate_check(edited_column);510updating_tree = false;511}512513void ThemeItemImportTree::_check_propagated_to_tree_item(Object *p_obj, int p_column) {514TreeItem *item = Object::cast_to<TreeItem>(p_obj);515// Skip "category" tree items by checking for children.516if (item && !item->get_first_child()) {517_store_selected_item(item);518}519}520521void ThemeItemImportTree::_select_all_subitems(TreeItem *p_root_item, bool p_select_with_data) {522TreeItem *child_item = p_root_item->get_first_child();523while (child_item) {524child_item->set_checked(IMPORT_ITEM, true);525if (p_select_with_data) {526child_item->set_checked(IMPORT_ITEM_DATA, true);527}528_store_selected_item(child_item);529530_select_all_subitems(child_item, p_select_with_data);531child_item = child_item->get_next();532}533}534535void ThemeItemImportTree::_deselect_all_subitems(TreeItem *p_root_item, bool p_deselect_completely) {536TreeItem *child_item = p_root_item->get_first_child();537while (child_item) {538child_item->set_checked(IMPORT_ITEM_DATA, false);539if (p_deselect_completely) {540child_item->set_checked(IMPORT_ITEM, false);541}542_store_selected_item(child_item);543544_deselect_all_subitems(child_item, p_deselect_completely);545child_item = child_item->get_next();546}547}548549void ThemeItemImportTree::_select_all_items_pressed() {550if (updating_tree) {551return;552}553554updating_tree = true;555556TreeItem *root = import_items_tree->get_root();557_select_all_subitems(root, false);558559updating_tree = false;560}561562void ThemeItemImportTree::_select_full_items_pressed() {563if (updating_tree) {564return;565}566567updating_tree = true;568569TreeItem *root = import_items_tree->get_root();570_select_all_subitems(root, true);571572updating_tree = false;573}574575void ThemeItemImportTree::_deselect_all_items_pressed() {576if (updating_tree) {577return;578}579580updating_tree = true;581582TreeItem *root = import_items_tree->get_root();583_deselect_all_subitems(root, true);584585updating_tree = false;586}587588void ThemeItemImportTree::_select_all_data_type_pressed(int p_data_type) {589ERR_FAIL_INDEX_MSG(p_data_type, Theme::DATA_TYPE_MAX, "Theme item data type is out of bounds.");590591if (updating_tree) {592return;593}594595Theme::DataType data_type = (Theme::DataType)p_data_type;596List<TreeItem *> *item_list = nullptr;597598switch (data_type) {599case Theme::DATA_TYPE_COLOR:600item_list = &tree_color_items;601break;602603case Theme::DATA_TYPE_CONSTANT:604item_list = &tree_constant_items;605break;606607case Theme::DATA_TYPE_FONT:608item_list = &tree_font_items;609break;610611case Theme::DATA_TYPE_FONT_SIZE:612item_list = &tree_font_size_items;613break;614615case Theme::DATA_TYPE_ICON:616item_list = &tree_icon_items;617break;618619case Theme::DATA_TYPE_STYLEBOX:620item_list = &tree_stylebox_items;621break;622623case Theme::DATA_TYPE_MAX:624return; // Can't happen, but silences warning.625}626627updating_tree = true;628629for (List<TreeItem *>::Element *E = item_list->front(); E; E = E->next()) {630TreeItem *child_item = E->get();631if (!child_item) {632continue;633}634635child_item->set_checked(IMPORT_ITEM, true);636child_item->propagate_check(IMPORT_ITEM, false);637_store_selected_item(child_item);638}639640updating_tree = false;641}642643void ThemeItemImportTree::_select_full_data_type_pressed(int p_data_type) {644ERR_FAIL_INDEX_MSG(p_data_type, Theme::DATA_TYPE_MAX, "Theme item data type is out of bounds.");645646if (updating_tree) {647return;648}649650Theme::DataType data_type = (Theme::DataType)p_data_type;651List<TreeItem *> *item_list = nullptr;652653switch (data_type) {654case Theme::DATA_TYPE_COLOR:655item_list = &tree_color_items;656break;657658case Theme::DATA_TYPE_CONSTANT:659item_list = &tree_constant_items;660break;661662case Theme::DATA_TYPE_FONT:663item_list = &tree_font_items;664break;665666case Theme::DATA_TYPE_FONT_SIZE:667item_list = &tree_font_size_items;668break;669670case Theme::DATA_TYPE_ICON:671item_list = &tree_icon_items;672break;673674case Theme::DATA_TYPE_STYLEBOX:675item_list = &tree_stylebox_items;676break;677678case Theme::DATA_TYPE_MAX:679return; // Can't happen, but silences warning.680}681682updating_tree = true;683684for (List<TreeItem *>::Element *E = item_list->front(); E; E = E->next()) {685TreeItem *child_item = E->get();686if (!child_item) {687continue;688}689690child_item->set_checked(IMPORT_ITEM, true);691child_item->set_checked(IMPORT_ITEM_DATA, true);692child_item->propagate_check(IMPORT_ITEM, false);693child_item->propagate_check(IMPORT_ITEM_DATA, false);694_store_selected_item(child_item);695}696697updating_tree = false;698}699700void ThemeItemImportTree::_deselect_all_data_type_pressed(int p_data_type) {701ERR_FAIL_INDEX_MSG(p_data_type, Theme::DATA_TYPE_MAX, "Theme item data type is out of bounds.");702703if (updating_tree) {704return;705}706707Theme::DataType data_type = (Theme::DataType)p_data_type;708List<TreeItem *> *item_list = nullptr;709710switch (data_type) {711case Theme::DATA_TYPE_COLOR:712item_list = &tree_color_items;713break;714715case Theme::DATA_TYPE_CONSTANT:716item_list = &tree_constant_items;717break;718719case Theme::DATA_TYPE_FONT:720item_list = &tree_font_items;721break;722723case Theme::DATA_TYPE_FONT_SIZE:724item_list = &tree_font_size_items;725break;726727case Theme::DATA_TYPE_ICON:728item_list = &tree_icon_items;729break;730731case Theme::DATA_TYPE_STYLEBOX:732item_list = &tree_stylebox_items;733break;734735case Theme::DATA_TYPE_MAX:736return; // Can't happen, but silences warning.737}738739updating_tree = true;740741for (List<TreeItem *>::Element *E = item_list->front(); E; E = E->next()) {742TreeItem *child_item = E->get();743if (!child_item) {744continue;745}746747child_item->set_checked(IMPORT_ITEM, false);748child_item->set_checked(IMPORT_ITEM_DATA, false);749child_item->propagate_check(IMPORT_ITEM, false);750child_item->propagate_check(IMPORT_ITEM_DATA, false);751_store_selected_item(child_item);752}753754updating_tree = false;755}756757void ThemeItemImportTree::_import_selected() {758if (selected_items.is_empty()) {759EditorNode::get_singleton()->show_accept(TTR("Nothing was selected for the import."), TTR("OK"));760return;761}762763Ref<Theme> old_snapshot = edited_theme->duplicate();764Ref<Theme> new_snapshot = edited_theme->duplicate();765766ProgressDialog::get_singleton()->add_task("import_theme_items", TTR("Importing Theme Items"), selected_items.size() + 2);767768int idx = 0;769for (KeyValue<ThemeItem, ItemCheckedState> &E : selected_items) {770// Arbitrary number of items to skip from reporting.771// Reduces the number of UI updates that this causes when copying large themes.772if (idx % 10 == 0) {773Array arr = { idx + 1, selected_items.size() };774ProgressDialog::get_singleton()->task_step("import_theme_items", TTR("Importing items {n}/{n}").format(arr, "{n}"), idx);775}776777ItemCheckedState cs = E.value;778ThemeItem ti = E.key;779780if (cs == SELECT_IMPORT_DEFINITION || cs == SELECT_IMPORT_FULL) {781Variant item_value = Variant();782783if (cs == SELECT_IMPORT_FULL) {784item_value = base_theme->get_theme_item(ti.data_type, ti.item_name, ti.type_name);785} else {786switch (ti.data_type) {787case Theme::DATA_TYPE_COLOR:788item_value = Color();789break;790791case Theme::DATA_TYPE_CONSTANT:792item_value = 0;793break;794795case Theme::DATA_TYPE_FONT:796item_value = Ref<Font>();797break;798799case Theme::DATA_TYPE_FONT_SIZE:800item_value = -1;801break;802803case Theme::DATA_TYPE_ICON:804item_value = Ref<Texture2D>();805break;806807case Theme::DATA_TYPE_STYLEBOX:808item_value = Ref<StyleBox>();809break;810811case Theme::DATA_TYPE_MAX:812break; // Can't happen, but silences warning.813}814}815816new_snapshot->set_theme_item(ti.data_type, ti.item_name, ti.type_name, item_value);817}818819idx++;820}821822// Allow changes to be reported now that the operation is finished.823ProgressDialog::get_singleton()->task_step("import_theme_items", TTR("Updating the editor"), idx++);824825// Make sure the task is not ended before the editor freezes to update the Inspector.826ProgressDialog::get_singleton()->task_step("import_theme_items", TTR("Finalizing"), idx++);827828ProgressDialog::get_singleton()->end_task("import_theme_items");829830EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();831ur->create_action(TTR("Import Theme Items"));832833ur->add_do_method(*edited_theme, "clear");834ur->add_do_method(*edited_theme, "merge_with", new_snapshot);835ur->add_undo_method(*edited_theme, "clear");836ur->add_undo_method(*edited_theme, "merge_with", old_snapshot);837838ur->add_do_method(this, "emit_signal", SNAME("items_imported"));839ur->add_undo_method(this, "emit_signal", SNAME("items_imported"));840841ur->commit_action();842}843844void ThemeItemImportTree::set_edited_theme(const Ref<Theme> &p_theme) {845edited_theme = p_theme;846}847848void ThemeItemImportTree::set_base_theme(const Ref<Theme> &p_theme) {849base_theme = p_theme;850}851852void ThemeItemImportTree::reset_item_tree() {853import_items_filter->clear();854selected_items.clear();855856total_selected_colors_label->hide();857total_selected_constants_label->hide();858total_selected_fonts_label->hide();859total_selected_font_sizes_label->hide();860total_selected_icons_label->hide();861total_selected_styleboxes_label->hide();862863_update_items_tree();864}865866bool ThemeItemImportTree::has_selected_items() const {867return (selected_items.size() > 0);868}869870void ThemeItemImportTree::_notification(int p_what) {871switch (p_what) {872case NOTIFICATION_THEME_CHANGED: {873select_icons_warning_icon->set_texture(get_editor_theme_icon(SNAME("StatusWarning")));874select_icons_warning->add_theme_color_override(SceneStringName(font_color), get_theme_color(SNAME("font_disabled_color"), EditorStringName(Editor)));875876import_items_filter->set_right_icon(get_editor_theme_icon(SNAME("Search")));877878// Bottom panel buttons.879import_collapse_types_button->set_button_icon(get_editor_theme_icon(SNAME("CollapseTree")));880import_expand_types_button->set_button_icon(get_editor_theme_icon(SNAME("ExpandTree")));881882import_select_all_button->set_button_icon(get_editor_theme_icon(SNAME("ThemeSelectAll")));883import_select_full_button->set_button_icon(get_editor_theme_icon(SNAME("ThemeSelectFull")));884import_deselect_all_button->set_button_icon(get_editor_theme_icon(SNAME("ThemeDeselectAll")));885886// Side panel buttons.887select_colors_icon->set_texture(get_editor_theme_icon(SNAME("Color")));888deselect_all_colors_button->set_button_icon(get_editor_theme_icon(SNAME("ThemeDeselectAll")));889select_all_colors_button->set_button_icon(get_editor_theme_icon(SNAME("ThemeSelectAll")));890select_full_colors_button->set_button_icon(get_editor_theme_icon(SNAME("ThemeSelectFull")));891892select_constants_icon->set_texture(get_editor_theme_icon(SNAME("MemberConstant")));893deselect_all_constants_button->set_button_icon(get_editor_theme_icon(SNAME("ThemeDeselectAll")));894select_all_constants_button->set_button_icon(get_editor_theme_icon(SNAME("ThemeSelectAll")));895select_full_constants_button->set_button_icon(get_editor_theme_icon(SNAME("ThemeSelectFull")));896897select_fonts_icon->set_texture(get_editor_theme_icon(SNAME("FontItem")));898deselect_all_fonts_button->set_button_icon(get_editor_theme_icon(SNAME("ThemeDeselectAll")));899select_all_fonts_button->set_button_icon(get_editor_theme_icon(SNAME("ThemeSelectAll")));900select_full_fonts_button->set_button_icon(get_editor_theme_icon(SNAME("ThemeSelectFull")));901902select_font_sizes_icon->set_texture(get_editor_theme_icon(SNAME("FontSize")));903deselect_all_font_sizes_button->set_button_icon(get_editor_theme_icon(SNAME("ThemeDeselectAll")));904select_all_font_sizes_button->set_button_icon(get_editor_theme_icon(SNAME("ThemeSelectAll")));905select_full_font_sizes_button->set_button_icon(get_editor_theme_icon(SNAME("ThemeSelectFull")));906907select_icons_icon->set_texture(get_editor_theme_icon(SNAME("ImageTexture")));908deselect_all_icons_button->set_button_icon(get_editor_theme_icon(SNAME("ThemeDeselectAll")));909select_all_icons_button->set_button_icon(get_editor_theme_icon(SNAME("ThemeSelectAll")));910select_full_icons_button->set_button_icon(get_editor_theme_icon(SNAME("ThemeSelectFull")));911912select_styleboxes_icon->set_texture(get_editor_theme_icon(SNAME("StyleBoxFlat")));913deselect_all_styleboxes_button->set_button_icon(get_editor_theme_icon(SNAME("ThemeDeselectAll")));914select_all_styleboxes_button->set_button_icon(get_editor_theme_icon(SNAME("ThemeSelectAll")));915select_full_styleboxes_button->set_button_icon(get_editor_theme_icon(SNAME("ThemeSelectFull")));916} break;917}918}919920void ThemeItemImportTree::_bind_methods() {921ADD_SIGNAL(MethodInfo("items_imported"));922}923924ThemeItemImportTree::ThemeItemImportTree() {925import_items_filter = memnew(LineEdit);926import_items_filter->set_placeholder(TTR("Filter Items"));927import_items_filter->set_clear_button_enabled(true);928add_child(import_items_filter);929import_items_filter->connect(SceneStringName(text_changed), callable_mp(this, &ThemeItemImportTree::_filter_text_changed));930931HBoxContainer *import_main_hb = memnew(HBoxContainer);932import_main_hb->set_v_size_flags(Control::SIZE_EXPAND_FILL);933add_child(import_main_hb);934935import_items_tree = memnew(Tree);936import_items_tree->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED);937import_items_tree->set_hide_root(true);938import_items_tree->set_h_size_flags(Control::SIZE_EXPAND_FILL);939import_main_hb->add_child(import_items_tree);940import_items_tree->connect("item_edited", callable_mp(this, &ThemeItemImportTree::_tree_item_edited));941import_items_tree->connect("check_propagated_to_item", callable_mp(this, &ThemeItemImportTree::_check_propagated_to_tree_item));942943import_items_tree->set_columns(3);944import_items_tree->set_column_titles_visible(true);945import_items_tree->set_column_title(IMPORT_ITEM, TTR("Import"));946import_items_tree->set_column_title(IMPORT_ITEM_DATA, TTR("With Data"));947import_items_tree->set_column_expand(0, true);948import_items_tree->set_column_clip_content(0, true);949import_items_tree->set_column_expand(IMPORT_ITEM, false);950import_items_tree->set_column_expand(IMPORT_ITEM_DATA, false);951import_items_tree->set_column_custom_minimum_width(0, 160 * EDSCALE);952import_items_tree->set_column_custom_minimum_width(IMPORT_ITEM, 80 * EDSCALE);953import_items_tree->set_column_custom_minimum_width(IMPORT_ITEM_DATA, 80 * EDSCALE);954import_items_tree->set_column_clip_content(1, true);955import_items_tree->set_column_clip_content(2, true);956import_items_tree->set_theme_type_variation("TreeSecondary");957958ScrollContainer *import_bulk_sc = memnew(ScrollContainer);959import_bulk_sc->set_custom_minimum_size(Size2(260.0, 0.0) * EDSCALE);960import_bulk_sc->set_horizontal_scroll_mode(ScrollContainer::SCROLL_MODE_DISABLED);961import_main_hb->add_child(import_bulk_sc);962VBoxContainer *import_bulk_vb = memnew(VBoxContainer);963import_bulk_vb->set_h_size_flags(Control::SIZE_EXPAND_FILL);964import_bulk_sc->add_child(import_bulk_vb);965966Label *import_bulk_label = memnew(Label);967import_bulk_label->set_text(TTR("Select by data type:"));968import_bulk_vb->add_child(import_bulk_label);969970select_colors_icon = memnew(TextureRect);971select_colors_label = memnew(Label);972deselect_all_colors_button = memnew(Button);973select_all_colors_button = memnew(Button);974select_full_colors_button = memnew(Button);975total_selected_colors_label = memnew(Label);976977select_constants_icon = memnew(TextureRect);978select_constants_label = memnew(Label);979deselect_all_constants_button = memnew(Button);980select_all_constants_button = memnew(Button);981select_full_constants_button = memnew(Button);982total_selected_constants_label = memnew(Label);983984select_fonts_icon = memnew(TextureRect);985select_fonts_label = memnew(Label);986deselect_all_fonts_button = memnew(Button);987select_all_fonts_button = memnew(Button);988select_full_fonts_button = memnew(Button);989total_selected_fonts_label = memnew(Label);990991select_font_sizes_icon = memnew(TextureRect);992select_font_sizes_label = memnew(Label);993deselect_all_font_sizes_button = memnew(Button);994select_all_font_sizes_button = memnew(Button);995select_full_font_sizes_button = memnew(Button);996total_selected_font_sizes_label = memnew(Label);997998select_icons_icon = memnew(TextureRect);999select_icons_label = memnew(Label);1000deselect_all_icons_button = memnew(Button);1001select_all_icons_button = memnew(Button);1002select_full_icons_button = memnew(Button);1003total_selected_icons_label = memnew(Label);10041005select_styleboxes_icon = memnew(TextureRect);1006select_styleboxes_label = memnew(Label);1007deselect_all_styleboxes_button = memnew(Button);1008select_all_styleboxes_button = memnew(Button);1009select_full_styleboxes_button = memnew(Button);1010total_selected_styleboxes_label = memnew(Label);10111012for (int i = 0; i < Theme::DATA_TYPE_MAX; i++) {1013Theme::DataType dt = (Theme::DataType)i;10141015TextureRect *select_items_icon = nullptr;1016Label *select_items_label = nullptr;1017Button *deselect_all_items_button = nullptr;1018Button *select_all_items_button = nullptr;1019Button *select_full_items_button = nullptr;1020Label *total_selected_items_label = nullptr;10211022String items_title;1023String select_all_items_tooltip;1024String select_full_items_tooltip;1025String deselect_all_items_tooltip;10261027switch (dt) {1028case Theme::DATA_TYPE_COLOR:1029select_items_icon = select_colors_icon;1030select_items_label = select_colors_label;1031deselect_all_items_button = deselect_all_colors_button;1032select_all_items_button = select_all_colors_button;1033select_full_items_button = select_full_colors_button;1034total_selected_items_label = total_selected_colors_label;10351036items_title = TTR("Colors");1037select_all_items_tooltip = TTR("Select all visible color items.");1038select_full_items_tooltip = TTR("Select all visible color items and their data.");1039deselect_all_items_tooltip = TTR("Deselect all visible color items.");1040break;10411042case Theme::DATA_TYPE_CONSTANT:1043select_items_icon = select_constants_icon;1044select_items_label = select_constants_label;1045deselect_all_items_button = deselect_all_constants_button;1046select_all_items_button = select_all_constants_button;1047select_full_items_button = select_full_constants_button;1048total_selected_items_label = total_selected_constants_label;10491050items_title = TTR("Constants");1051select_all_items_tooltip = TTR("Select all visible constant items.");1052select_full_items_tooltip = TTR("Select all visible constant items and their data.");1053deselect_all_items_tooltip = TTR("Deselect all visible constant items.");1054break;10551056case Theme::DATA_TYPE_FONT:1057select_items_icon = select_fonts_icon;1058select_items_label = select_fonts_label;1059deselect_all_items_button = deselect_all_fonts_button;1060select_all_items_button = select_all_fonts_button;1061select_full_items_button = select_full_fonts_button;1062total_selected_items_label = total_selected_fonts_label;10631064items_title = TTR("Fonts");1065select_all_items_tooltip = TTR("Select all visible font items.");1066select_full_items_tooltip = TTR("Select all visible font items and their data.");1067deselect_all_items_tooltip = TTR("Deselect all visible font items.");1068break;10691070case Theme::DATA_TYPE_FONT_SIZE:1071select_items_icon = select_font_sizes_icon;1072select_items_label = select_font_sizes_label;1073deselect_all_items_button = deselect_all_font_sizes_button;1074select_all_items_button = select_all_font_sizes_button;1075select_full_items_button = select_full_font_sizes_button;1076total_selected_items_label = total_selected_font_sizes_label;10771078items_title = TTR("Font sizes");1079select_all_items_tooltip = TTR("Select all visible font size items.");1080select_full_items_tooltip = TTR("Select all visible font size items and their data.");1081deselect_all_items_tooltip = TTR("Deselect all visible font size items.");1082break;10831084case Theme::DATA_TYPE_ICON:1085select_items_icon = select_icons_icon;1086select_items_label = select_icons_label;1087deselect_all_items_button = deselect_all_icons_button;1088select_all_items_button = select_all_icons_button;1089select_full_items_button = select_full_icons_button;1090total_selected_items_label = total_selected_icons_label;10911092items_title = TTR("Icons");1093select_all_items_tooltip = TTR("Select all visible icon items.");1094select_full_items_tooltip = TTR("Select all visible icon items and their data.");1095deselect_all_items_tooltip = TTR("Deselect all visible icon items.");1096break;10971098case Theme::DATA_TYPE_STYLEBOX:1099select_items_icon = select_styleboxes_icon;1100select_items_label = select_styleboxes_label;1101deselect_all_items_button = deselect_all_styleboxes_button;1102select_all_items_button = select_all_styleboxes_button;1103select_full_items_button = select_full_styleboxes_button;1104total_selected_items_label = total_selected_styleboxes_label;11051106items_title = TTR("Styleboxes");1107select_all_items_tooltip = TTR("Select all visible stylebox items.");1108select_full_items_tooltip = TTR("Select all visible stylebox items and their data.");1109deselect_all_items_tooltip = TTR("Deselect all visible stylebox items.");1110break;11111112case Theme::DATA_TYPE_MAX:1113continue; // Can't happen, but silences warning.1114}11151116if (i > 0) {1117import_bulk_vb->add_child(memnew(HSeparator));1118}11191120HBoxContainer *all_set = memnew(HBoxContainer);1121import_bulk_vb->add_child(all_set);11221123HBoxContainer *label_set = memnew(HBoxContainer);1124label_set->set_h_size_flags(Control::SIZE_EXPAND_FILL);1125all_set->add_child(label_set);1126select_items_icon->set_v_size_flags(Control::SIZE_SHRINK_CENTER);1127label_set->add_child(select_items_icon);1128select_items_label->set_h_size_flags(Control::SIZE_EXPAND_FILL);1129select_items_label->set_clip_text(true);1130select_items_label->set_text(items_title);1131label_set->add_child(select_items_label);11321133HBoxContainer *button_set = memnew(HBoxContainer);1134button_set->set_alignment(BoxContainer::ALIGNMENT_END);1135all_set->add_child(button_set);1136select_all_items_button->set_flat(true);1137select_all_items_button->set_tooltip_text(select_all_items_tooltip);1138button_set->add_child(select_all_items_button);1139select_all_items_button->connect(SceneStringName(pressed), callable_mp(this, &ThemeItemImportTree::_select_all_data_type_pressed).bind(i));1140select_full_items_button->set_flat(true);1141select_full_items_button->set_tooltip_text(select_full_items_tooltip);1142button_set->add_child(select_full_items_button);1143select_full_items_button->connect(SceneStringName(pressed), callable_mp(this, &ThemeItemImportTree::_select_full_data_type_pressed).bind(i));1144deselect_all_items_button->set_flat(true);1145deselect_all_items_button->set_tooltip_text(deselect_all_items_tooltip);1146button_set->add_child(deselect_all_items_button);1147deselect_all_items_button->connect(SceneStringName(pressed), callable_mp(this, &ThemeItemImportTree::_deselect_all_data_type_pressed).bind(i));11481149total_selected_items_label->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_RIGHT);1150total_selected_items_label->hide();1151import_bulk_vb->add_child(total_selected_items_label);11521153if (dt == Theme::DATA_TYPE_ICON) {1154select_icons_warning_hb = memnew(HBoxContainer);1155import_bulk_vb->add_child(select_icons_warning_hb);11561157select_icons_warning_icon = memnew(TextureRect);1158select_icons_warning_icon->set_v_size_flags(Control::SIZE_SHRINK_CENTER);1159select_icons_warning_hb->add_child(select_icons_warning_icon);11601161select_icons_warning = memnew(Label);1162select_icons_warning->set_text(TTR("Caution: Adding icon data may considerably increase the size of your Theme resource."));1163select_icons_warning->set_autowrap_mode(TextServer::AUTOWRAP_WORD_SMART);1164select_icons_warning->set_h_size_flags(Control::SIZE_EXPAND_FILL);1165select_icons_warning_hb->add_child(select_icons_warning);1166}1167}11681169add_child(memnew(HSeparator));11701171HBoxContainer *import_buttons = memnew(HBoxContainer);1172add_child(import_buttons);11731174import_collapse_types_button = memnew(Button);1175import_collapse_types_button->set_flat(true);1176import_collapse_types_button->set_tooltip_text(TTR("Collapse types."));1177import_buttons->add_child(import_collapse_types_button);1178import_collapse_types_button->connect(SceneStringName(pressed), callable_mp(this, &ThemeItemImportTree::_toggle_type_items).bind(true));1179import_expand_types_button = memnew(Button);1180import_expand_types_button->set_flat(true);1181import_expand_types_button->set_tooltip_text(TTR("Expand types."));1182import_buttons->add_child(import_expand_types_button);1183import_expand_types_button->connect(SceneStringName(pressed), callable_mp(this, &ThemeItemImportTree::_toggle_type_items).bind(false));11841185import_buttons->add_child(memnew(VSeparator));11861187import_select_all_button = memnew(Button);1188import_select_all_button->set_flat(true);1189import_select_all_button->set_text(TTR("Select All"));1190import_select_all_button->set_tooltip_text(TTR("Select all Theme items."));1191import_buttons->add_child(import_select_all_button);1192import_select_all_button->connect(SceneStringName(pressed), callable_mp(this, &ThemeItemImportTree::_select_all_items_pressed));1193import_select_full_button = memnew(Button);1194import_select_full_button->set_flat(true);1195import_select_full_button->set_text(TTR("Select With Data"));1196import_select_full_button->set_tooltip_text(TTR("Select all Theme items with item data."));1197import_buttons->add_child(import_select_full_button);1198import_select_full_button->connect(SceneStringName(pressed), callable_mp(this, &ThemeItemImportTree::_select_full_items_pressed));1199import_deselect_all_button = memnew(Button);1200import_deselect_all_button->set_flat(true);1201import_deselect_all_button->set_text(TTR("Deselect All"));1202import_deselect_all_button->set_tooltip_text(TTR("Deselect all Theme items."));1203import_buttons->add_child(import_deselect_all_button);1204import_deselect_all_button->connect(SceneStringName(pressed), callable_mp(this, &ThemeItemImportTree::_deselect_all_items_pressed));12051206import_buttons->add_spacer();12071208Button *import_add_selected_button = memnew(Button);1209import_add_selected_button->set_text(TTR("Import Selected"));1210import_buttons->add_child(import_add_selected_button);1211import_add_selected_button->connect(SceneStringName(pressed), callable_mp(this, &ThemeItemImportTree::_import_selected));1212}12131214///////////////////////12151216void ThemeItemEditorDialog::ok_pressed() {1217if (import_default_theme_items->has_selected_items() || import_editor_theme_items->has_selected_items() || import_other_theme_items->has_selected_items()) {1218confirm_closing_dialog->set_text(TTR("Import Items tab has some items selected. Selection will be lost upon closing this window.\nClose anyway?"));1219confirm_closing_dialog->popup_centered(Size2(380, 120) * EDSCALE);1220return;1221}12221223hide();1224}12251226void ThemeItemEditorDialog::_close_dialog() {1227hide();1228}12291230void ThemeItemEditorDialog::_dialog_about_to_show() {1231ERR_FAIL_COND_MSG(edited_theme.is_null(), "Invalid state of the Theme Editor; the Theme resource is missing.");12321233_update_edit_types();12341235import_default_theme_items->set_edited_theme(edited_theme);1236import_default_theme_items->set_base_theme(ThemeDB::get_singleton()->get_default_theme());1237import_default_theme_items->reset_item_tree();12381239import_editor_theme_items->set_edited_theme(edited_theme);1240import_editor_theme_items->set_base_theme(EditorNode::get_singleton()->get_editor_theme());1241import_editor_theme_items->reset_item_tree();12421243import_other_theme_items->set_edited_theme(edited_theme);1244import_other_theme_items->reset_item_tree();1245}12461247void ThemeItemEditorDialog::_update_edit_types() {1248Ref<Theme> base_theme = ThemeDB::get_singleton()->get_default_theme();12491250List<StringName> theme_types;1251edited_theme->get_type_list(&theme_types);1252theme_types.sort_custom<StringName::AlphCompare>();12531254bool item_reselected = false;1255edit_type_list->clear();1256TreeItem *list_root = edit_type_list->create_item();12571258for (const StringName &E : theme_types) {1259Ref<Texture2D> item_icon;1260if (E == "") {1261item_icon = get_editor_theme_icon(SNAME("NodeDisabled"));1262} else {1263item_icon = EditorNode::get_singleton()->get_class_icon(E, "NodeDisabled");1264}1265TreeItem *list_item = edit_type_list->create_item(list_root);1266list_item->set_text(0, E);1267list_item->set_metadata(0, E);1268list_item->set_editable(0, true);1269list_item->set_icon(0, item_icon);1270list_item->add_button(0, get_editor_theme_icon(SNAME("Remove")), TYPES_TREE_REMOVE_ITEM, false, TTRC("Remove Type"));12711272if (E == edited_item_type) {1273list_item->select(0);1274item_reselected = true;1275}1276}1277if (!item_reselected) {1278edited_item_type = "";12791280if (list_root->get_child_count() > 0) {1281list_root->get_child(0)->select(0);1282}1283}12841285List<StringName> default_types;1286base_theme->get_type_list(&default_types);1287default_types.sort_custom<StringName::AlphCompare>();12881289String selected_type = "";1290TreeItem *selected_item = edit_type_list->get_selected();1291if (selected_item) {1292selected_type = selected_item->get_text(0);12931294edit_items_add_color->set_disabled(false);1295edit_items_add_constant->set_disabled(false);1296edit_items_add_font->set_disabled(false);1297edit_items_add_font_size->set_disabled(false);1298edit_items_add_icon->set_disabled(false);1299edit_items_add_stylebox->set_disabled(false);13001301edit_items_remove_class->set_disabled(false);1302edit_items_remove_custom->set_disabled(false);1303edit_items_remove_all->set_disabled(false);13041305edit_items_message->set_text("");1306edit_items_message->hide();1307} else {1308edit_items_add_color->set_disabled(true);1309edit_items_add_constant->set_disabled(true);1310edit_items_add_font->set_disabled(true);1311edit_items_add_font_size->set_disabled(true);1312edit_items_add_icon->set_disabled(true);1313edit_items_add_stylebox->set_disabled(true);13141315edit_items_remove_class->set_disabled(true);1316edit_items_remove_custom->set_disabled(true);1317edit_items_remove_all->set_disabled(true);13181319edit_items_message->set_text(TTR("Select a theme type from the list to edit its items.\nYou can add a custom type or import a type with its items from another theme."));1320edit_items_message->show();1321}13221323_update_edit_item_tree(selected_type);1324}13251326void ThemeItemEditorDialog::_edited_type_selected() {1327TreeItem *selected_item = edit_type_list->get_selected();1328String selected_type = selected_item->get_text(0);1329_update_edit_item_tree(selected_type);1330}13311332void ThemeItemEditorDialog::_edited_type_edited() {1333TreeItem *edited_item = edit_type_list->get_selected();1334const String old_type_name = edited_item->get_metadata(0);13351336const String &new_type_name = Theme::validate_type_name(edited_item->get_text(0));1337if (old_type_name == new_type_name) {1338edited_item->set_text(0, old_type_name);1339return;1340}13411342List<StringName> theme_types;1343edited_theme->get_type_list(&theme_types);1344if (theme_types.find(new_type_name) != nullptr) {1345edited_item->set_text(0, old_type_name);1346return;1347}13481349// The list will be recreated, but let's update the item just in case.1350edited_item->set_metadata(0, new_type_name);1351edited_item->set_text(0, new_type_name);13521353EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();1354ur->create_action(TTR("Rename Theme Type"));13551356_rename_theme_type(ur, *edited_theme, old_type_name, new_type_name);13571358// Set `edited_item_type`.1359ur->add_do_method(this, "_update_edit_item_tree", new_type_name);1360ur->add_undo_method(this, "_update_edit_item_tree", old_type_name);13611362ur->add_do_method(this, "_update_edit_types");1363ur->add_undo_method(this, "_update_edit_types");13641365ur->commit_action();1366}13671368void ThemeItemEditorDialog::_edited_type_button_pressed(Object *p_item, int p_column, int p_id, MouseButton p_button) {1369if (p_button != MouseButton::LEFT) {1370return;1371}13721373TreeItem *item = Object::cast_to<TreeItem>(p_item);1374if (!item) {1375return;1376}13771378switch (p_id) {1379case TYPES_TREE_REMOVE_ITEM: {1380String type_name = item->get_text(0);1381_remove_theme_type(type_name);1382} break;1383}1384}13851386void ThemeItemEditorDialog::_update_edit_item_tree(String p_item_type) {1387edited_item_type = p_item_type;13881389edit_items_tree->clear();1390TreeItem *root = edit_items_tree->create_item();13911392List<StringName> names;1393bool has_any_items = false;13941395{ // Colors.1396names.clear();1397edited_theme->get_color_list(p_item_type, &names);13981399if (names.size() > 0) {1400TreeItem *color_root = edit_items_tree->create_item(root);1401color_root->set_metadata(0, Theme::DATA_TYPE_COLOR);1402color_root->set_icon(0, get_editor_theme_icon(SNAME("Color")));1403color_root->set_text(0, TTR("Colors"));1404color_root->add_button(0, get_editor_theme_icon(SNAME("Clear")), ITEMS_TREE_REMOVE_DATA_TYPE, false, TTR("Remove All Color Items"));14051406names.sort_custom<StringName::AlphCompare>();1407for (const StringName &E : names) {1408TreeItem *item = edit_items_tree->create_item(color_root);1409item->set_text(0, E);1410item->add_button(0, get_editor_theme_icon(SNAME("Edit")), ITEMS_TREE_RENAME_ITEM, false, TTR("Rename Item"));1411item->add_button(0, get_editor_theme_icon(SNAME("Remove")), ITEMS_TREE_REMOVE_ITEM, false, TTR("Remove Item"));1412}14131414has_any_items = true;1415}1416}14171418{ // Constants.1419names.clear();1420edited_theme->get_constant_list(p_item_type, &names);14211422if (names.size() > 0) {1423TreeItem *constant_root = edit_items_tree->create_item(root);1424constant_root->set_metadata(0, Theme::DATA_TYPE_CONSTANT);1425constant_root->set_icon(0, get_editor_theme_icon(SNAME("MemberConstant")));1426constant_root->set_text(0, TTR("Constants"));1427constant_root->add_button(0, get_editor_theme_icon(SNAME("Clear")), ITEMS_TREE_REMOVE_DATA_TYPE, false, TTR("Remove All Constant Items"));14281429names.sort_custom<StringName::AlphCompare>();1430for (const StringName &E : names) {1431TreeItem *item = edit_items_tree->create_item(constant_root);1432item->set_text(0, E);1433item->add_button(0, get_editor_theme_icon(SNAME("Edit")), ITEMS_TREE_RENAME_ITEM, false, TTR("Rename Item"));1434item->add_button(0, get_editor_theme_icon(SNAME("Remove")), ITEMS_TREE_REMOVE_ITEM, false, TTR("Remove Item"));1435}14361437has_any_items = true;1438}1439}14401441{ // Fonts.1442names.clear();1443edited_theme->get_font_list(p_item_type, &names);14441445if (names.size() > 0) {1446TreeItem *font_root = edit_items_tree->create_item(root);1447font_root->set_metadata(0, Theme::DATA_TYPE_FONT);1448font_root->set_icon(0, get_editor_theme_icon(SNAME("FontItem")));1449font_root->set_text(0, TTR("Fonts"));1450font_root->add_button(0, get_editor_theme_icon(SNAME("Clear")), ITEMS_TREE_REMOVE_DATA_TYPE, false, TTR("Remove All Font Items"));14511452names.sort_custom<StringName::AlphCompare>();1453for (const StringName &E : names) {1454TreeItem *item = edit_items_tree->create_item(font_root);1455item->set_text(0, E);1456item->add_button(0, get_editor_theme_icon(SNAME("Edit")), ITEMS_TREE_RENAME_ITEM, false, TTR("Rename Item"));1457item->add_button(0, get_editor_theme_icon(SNAME("Remove")), ITEMS_TREE_REMOVE_ITEM, false, TTR("Remove Item"));1458}14591460has_any_items = true;1461}1462}14631464{ // Font sizes.1465names.clear();1466edited_theme->get_font_size_list(p_item_type, &names);14671468if (names.size() > 0) {1469TreeItem *font_size_root = edit_items_tree->create_item(root);1470font_size_root->set_metadata(0, Theme::DATA_TYPE_FONT_SIZE);1471font_size_root->set_icon(0, get_editor_theme_icon(SNAME("FontSize")));1472font_size_root->set_text(0, TTR("Font Sizes"));1473font_size_root->add_button(0, get_editor_theme_icon(SNAME("Clear")), ITEMS_TREE_REMOVE_DATA_TYPE, false, TTR("Remove All Font Size Items"));14741475names.sort_custom<StringName::AlphCompare>();1476for (const StringName &E : names) {1477TreeItem *item = edit_items_tree->create_item(font_size_root);1478item->set_text(0, E);1479item->add_button(0, get_editor_theme_icon(SNAME("Edit")), ITEMS_TREE_RENAME_ITEM, false, TTR("Rename Item"));1480item->add_button(0, get_editor_theme_icon(SNAME("Remove")), ITEMS_TREE_REMOVE_ITEM, false, TTR("Remove Item"));1481}14821483has_any_items = true;1484}1485}14861487{ // Icons.1488names.clear();1489edited_theme->get_icon_list(p_item_type, &names);14901491if (names.size() > 0) {1492TreeItem *icon_root = edit_items_tree->create_item(root);1493icon_root->set_metadata(0, Theme::DATA_TYPE_ICON);1494icon_root->set_icon(0, get_editor_theme_icon(SNAME("ImageTexture")));1495icon_root->set_text(0, TTR("Icons"));1496icon_root->add_button(0, get_editor_theme_icon(SNAME("Clear")), ITEMS_TREE_REMOVE_DATA_TYPE, false, TTR("Remove All Icon Items"));14971498names.sort_custom<StringName::AlphCompare>();1499for (const StringName &E : names) {1500TreeItem *item = edit_items_tree->create_item(icon_root);1501item->set_text(0, E);1502item->add_button(0, get_editor_theme_icon(SNAME("Edit")), ITEMS_TREE_RENAME_ITEM, false, TTR("Rename Item"));1503item->add_button(0, get_editor_theme_icon(SNAME("Remove")), ITEMS_TREE_REMOVE_ITEM, false, TTR("Remove Item"));1504}15051506has_any_items = true;1507}1508}15091510{ // Styleboxes.1511names.clear();1512edited_theme->get_stylebox_list(p_item_type, &names);15131514if (names.size() > 0) {1515TreeItem *stylebox_root = edit_items_tree->create_item(root);1516stylebox_root->set_metadata(0, Theme::DATA_TYPE_STYLEBOX);1517stylebox_root->set_icon(0, get_editor_theme_icon(SNAME("StyleBoxFlat")));1518stylebox_root->set_text(0, TTR("Styleboxes"));1519stylebox_root->add_button(0, get_editor_theme_icon(SNAME("Clear")), ITEMS_TREE_REMOVE_DATA_TYPE, false, TTR("Remove All StyleBox Items"));15201521names.sort_custom<StringName::AlphCompare>();1522for (const StringName &E : names) {1523TreeItem *item = edit_items_tree->create_item(stylebox_root);1524item->set_text(0, E);1525item->add_button(0, get_editor_theme_icon(SNAME("Edit")), ITEMS_TREE_RENAME_ITEM, false, TTR("Rename Item"));1526item->add_button(0, get_editor_theme_icon(SNAME("Remove")), ITEMS_TREE_REMOVE_ITEM, false, TTR("Remove Item"));1527}15281529has_any_items = true;1530}1531}15321533// If some type is selected, but it doesn't seem to have any items, show a guiding message.1534TreeItem *selected_item = edit_type_list->get_selected();1535if (selected_item) {1536if (!has_any_items) {1537edit_items_message->set_text(TTR("This theme type is empty.\nAdd more items to it manually or by importing from another theme."));1538edit_items_message->show();1539} else {1540edit_items_message->set_text("");1541edit_items_message->hide();1542}1543}1544}15451546void ThemeItemEditorDialog::_item_tree_button_pressed(Object *p_item, int p_column, int p_id, MouseButton p_button) {1547if (p_button != MouseButton::LEFT) {1548return;1549}15501551TreeItem *item = Object::cast_to<TreeItem>(p_item);1552if (!item) {1553return;1554}15551556switch (p_id) {1557case ITEMS_TREE_RENAME_ITEM: {1558String item_name = item->get_text(0);1559int data_type = item->get_parent()->get_metadata(0);1560_open_rename_theme_item_dialog((Theme::DataType)data_type, item_name);1561_update_edit_item_tree(edited_item_type);1562} break;1563case ITEMS_TREE_REMOVE_ITEM: {1564String item_name = item->get_text(0);1565int data_type = item->get_parent()->get_metadata(0);15661567EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();1568ur->create_action(TTR("Remove Theme Item"));1569ur->add_do_method(*edited_theme, "clear_theme_item", (Theme::DataType)data_type, item_name, edited_item_type);1570ur->add_undo_method(*edited_theme, "set_theme_item", (Theme::DataType)data_type, item_name, edited_item_type, edited_theme->get_theme_item((Theme::DataType)data_type, item_name, edited_item_type));1571ur->add_do_method(this, "_update_edit_item_tree", edited_item_type);1572ur->add_undo_method(this, "_update_edit_item_tree", edited_item_type);1573ur->commit_action();1574} break;1575case ITEMS_TREE_REMOVE_DATA_TYPE: {1576int data_type = item->get_metadata(0);1577_remove_data_type_items((Theme::DataType)data_type, edited_item_type);1578} break;1579}1580}15811582void ThemeItemEditorDialog::_add_theme_type() {1583const String &new_type_name = Theme::validate_type_name(edit_add_type_value->get_text());1584edit_add_type_value->clear();15851586EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();1587ur->create_action(TTR("Add Theme Type"));15881589ur->add_do_method(*edited_theme, "add_type", new_type_name);1590ur->add_undo_method(*edited_theme, "remove_type", new_type_name);15911592ur->add_do_method(this, "_update_edit_types");1593ur->add_undo_method(this, "_update_edit_types");15941595ur->commit_action();1596}15971598void ThemeItemEditorDialog::_add_theme_item(Theme::DataType p_data_type, const String &p_item_name, const String &p_item_type) {1599EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();1600ur->create_action(TTR("Create Theme Item"));16011602switch (p_data_type) {1603case Theme::DATA_TYPE_ICON:1604ur->add_do_method(*edited_theme, "set_icon", p_item_name, p_item_type, Ref<Texture2D>());1605ur->add_undo_method(*edited_theme, "clear_icon", p_item_name, p_item_type);1606break;1607case Theme::DATA_TYPE_STYLEBOX:1608ur->add_do_method(*edited_theme, "set_stylebox", p_item_name, p_item_type, Ref<StyleBox>());1609ur->add_undo_method(*edited_theme, "clear_stylebox", p_item_name, p_item_type);16101611if (theme_type_editor->is_stylebox_pinned(edited_theme->get_stylebox(p_item_name, p_item_type))) {1612ur->add_undo_method(theme_type_editor, "_unpin_leading_stylebox");1613}1614break;1615case Theme::DATA_TYPE_FONT:1616ur->add_do_method(*edited_theme, "set_font", p_item_name, p_item_type, Ref<Font>());1617ur->add_undo_method(*edited_theme, "clear_font", p_item_name, p_item_type);1618break;1619case Theme::DATA_TYPE_FONT_SIZE:1620ur->add_do_method(*edited_theme, "set_font_size", p_item_name, p_item_type, -1);1621ur->add_undo_method(*edited_theme, "clear_font_size", p_item_name, p_item_type);1622break;1623case Theme::DATA_TYPE_COLOR:1624ur->add_do_method(*edited_theme, "set_color", p_item_name, p_item_type, Color());1625ur->add_undo_method(*edited_theme, "clear_color", p_item_name, p_item_type);1626break;1627case Theme::DATA_TYPE_CONSTANT:1628ur->add_do_method(*edited_theme, "set_constant", p_item_name, p_item_type, 0);1629ur->add_undo_method(*edited_theme, "clear_constant", p_item_name, p_item_type);1630break;1631case Theme::DATA_TYPE_MAX:1632break; // Can't happen, but silences warning.1633}16341635ur->add_do_method(this, "_update_edit_item_tree", edited_item_type);1636ur->add_undo_method(this, "_update_edit_item_tree", edited_item_type);1637ur->commit_action();1638}16391640void ThemeItemEditorDialog::_remove_theme_type(const String &p_theme_type) {1641Ref<Theme> old_snapshot = edited_theme->duplicate();16421643EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();1644ur->create_action(TTR("Remove Theme Type"));16451646ur->add_do_method(*edited_theme, "remove_type", p_theme_type);1647// If the type was empty, it cannot be restored with merge, but thankfully we can fake it.1648ur->add_undo_method(*edited_theme, "add_type", p_theme_type);1649ur->add_undo_method(*edited_theme, "merge_with", old_snapshot);16501651ur->add_do_method(this, "_update_edit_types");1652ur->add_undo_method(this, "_update_edit_types");16531654ur->commit_action();1655}16561657void ThemeItemEditorDialog::_remove_data_type_items(Theme::DataType p_data_type, String p_item_type) {1658List<StringName> names;16591660Ref<Theme> old_snapshot = edited_theme->duplicate();1661Ref<Theme> new_snapshot = edited_theme->duplicate();16621663EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();1664ur->create_action(TTR("Remove Data Type Items From Theme"));16651666new_snapshot->get_theme_item_list(p_data_type, p_item_type, &names);1667for (const StringName &E : names) {1668new_snapshot->clear_theme_item(p_data_type, E, edited_item_type);16691670if (p_data_type == Theme::DATA_TYPE_STYLEBOX && theme_type_editor->is_stylebox_pinned(edited_theme->get_stylebox(E, p_item_type))) {1671ur->add_do_method(theme_type_editor, "_unpin_leading_stylebox");1672ur->add_undo_method(theme_type_editor, "_pin_leading_stylebox", E, edited_theme->get_stylebox(E, p_item_type));1673}1674}16751676ur->add_do_method(*edited_theme, "clear");1677ur->add_do_method(*edited_theme, "merge_with", new_snapshot);1678ur->add_undo_method(*edited_theme, "merge_with", old_snapshot);16791680ur->add_do_method(this, "_update_edit_item_tree", edited_item_type);1681ur->add_undo_method(this, "_update_edit_item_tree", edited_item_type);16821683ur->commit_action();1684}16851686void ThemeItemEditorDialog::_remove_class_items() {1687List<StringName> names;16881689Ref<Theme> old_snapshot = edited_theme->duplicate();1690Ref<Theme> new_snapshot = edited_theme->duplicate();16911692EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();1693ur->create_action(TTR("Remove Class Items From Theme"));16941695for (int dt = 0; dt < Theme::DATA_TYPE_MAX; dt++) {1696Theme::DataType data_type = (Theme::DataType)dt;16971698names.clear();1699ThemeDB::get_singleton()->get_default_theme()->get_theme_item_list(data_type, edited_item_type, &names);1700for (const StringName &E : names) {1701if (new_snapshot->has_theme_item_nocheck(data_type, E, edited_item_type)) {1702new_snapshot->clear_theme_item(data_type, E, edited_item_type);17031704if (dt == Theme::DATA_TYPE_STYLEBOX && theme_type_editor->is_stylebox_pinned(edited_theme->get_stylebox(E, edited_item_type))) {1705ur->add_do_method(theme_type_editor, "_unpin_leading_stylebox");1706ur->add_undo_method(theme_type_editor, "_pin_leading_stylebox", E, edited_theme->get_stylebox(E, edited_item_type));1707}1708}1709}1710}17111712ur->add_do_method(*edited_theme, "clear");1713ur->add_do_method(*edited_theme, "merge_with", new_snapshot);1714ur->add_undo_method(*edited_theme, "merge_with", old_snapshot);17151716ur->add_do_method(this, "_update_edit_item_tree", edited_item_type);1717ur->add_undo_method(this, "_update_edit_item_tree", edited_item_type);17181719ur->commit_action();1720}17211722void ThemeItemEditorDialog::_remove_custom_items() {1723List<StringName> names;17241725Ref<Theme> old_snapshot = edited_theme->duplicate();1726Ref<Theme> new_snapshot = edited_theme->duplicate();17271728EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();1729ur->create_action(TTR("Remove Custom Items From Theme"));17301731for (int dt = 0; dt < Theme::DATA_TYPE_MAX; dt++) {1732Theme::DataType data_type = (Theme::DataType)dt;17331734names.clear();1735new_snapshot->get_theme_item_list(data_type, edited_item_type, &names);1736for (const StringName &E : names) {1737if (!ThemeDB::get_singleton()->get_default_theme()->has_theme_item_nocheck(data_type, E, edited_item_type)) {1738new_snapshot->clear_theme_item(data_type, E, edited_item_type);17391740if (dt == Theme::DATA_TYPE_STYLEBOX && theme_type_editor->is_stylebox_pinned(edited_theme->get_stylebox(E, edited_item_type))) {1741ur->add_do_method(theme_type_editor, "_unpin_leading_stylebox");1742ur->add_undo_method(theme_type_editor, "_pin_leading_stylebox", E, edited_theme->get_stylebox(E, edited_item_type));1743}1744}1745}1746}17471748ur->add_do_method(*edited_theme, "clear");1749ur->add_do_method(*edited_theme, "merge_with", new_snapshot);1750ur->add_undo_method(*edited_theme, "merge_with", old_snapshot);17511752ur->add_do_method(this, "_update_edit_item_tree", edited_item_type);1753ur->add_undo_method(this, "_update_edit_item_tree", edited_item_type);17541755ur->commit_action();1756}17571758void ThemeItemEditorDialog::_remove_all_items() {1759List<StringName> names;17601761Ref<Theme> old_snapshot = edited_theme->duplicate();1762Ref<Theme> new_snapshot = edited_theme->duplicate();17631764EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();1765ur->create_action(TTR("Remove All Items From Theme"));17661767for (int dt = 0; dt < Theme::DATA_TYPE_MAX; dt++) {1768Theme::DataType data_type = (Theme::DataType)dt;17691770names.clear();1771new_snapshot->get_theme_item_list(data_type, edited_item_type, &names);1772for (const StringName &E : names) {1773new_snapshot->clear_theme_item(data_type, E, edited_item_type);17741775if (dt == Theme::DATA_TYPE_STYLEBOX && theme_type_editor->is_stylebox_pinned(edited_theme->get_stylebox(E, edited_item_type))) {1776ur->add_do_method(theme_type_editor, "_unpin_leading_stylebox");1777ur->add_undo_method(theme_type_editor, "_pin_leading_stylebox", E, edited_theme->get_stylebox(E, edited_item_type));1778}1779}1780}17811782ur->add_do_method(*edited_theme, "clear");1783ur->add_do_method(*edited_theme, "merge_with", new_snapshot);1784ur->add_undo_method(*edited_theme, "merge_with", old_snapshot);17851786ur->add_do_method(this, "_update_edit_item_tree", edited_item_type);1787ur->add_undo_method(this, "_update_edit_item_tree", edited_item_type);17881789ur->commit_action();1790}17911792void ThemeItemEditorDialog::_open_add_theme_item_dialog(int p_data_type) {1793ERR_FAIL_INDEX_MSG(p_data_type, Theme::DATA_TYPE_MAX, "Theme item data type is out of bounds.");17941795item_popup_mode = CREATE_THEME_ITEM;1796edit_item_data_type = (Theme::DataType)p_data_type;17971798switch (edit_item_data_type) {1799case Theme::DATA_TYPE_COLOR:1800edit_theme_item_dialog->set_title(TTR("Add Color Item"));1801break;1802case Theme::DATA_TYPE_CONSTANT:1803edit_theme_item_dialog->set_title(TTR("Add Constant Item"));1804break;1805case Theme::DATA_TYPE_FONT:1806edit_theme_item_dialog->set_title(TTR("Add Font Item"));1807break;1808case Theme::DATA_TYPE_FONT_SIZE:1809edit_theme_item_dialog->set_title(TTR("Add Font Size Item"));1810break;1811case Theme::DATA_TYPE_ICON:1812edit_theme_item_dialog->set_title(TTR("Add Icon Item"));1813break;1814case Theme::DATA_TYPE_STYLEBOX:1815edit_theme_item_dialog->set_title(TTR("Add Stylebox Item"));1816break;1817case Theme::DATA_TYPE_MAX:1818break; // Can't happen, but silences warning.1819}18201821edit_theme_item_old_vb->hide();1822theme_item_name->clear();1823edit_theme_item_dialog->popup_centered(Size2(380, 110) * EDSCALE);1824theme_item_name->grab_focus();1825}18261827void ThemeItemEditorDialog::_open_rename_theme_item_dialog(Theme::DataType p_data_type, String p_item_name) {1828ERR_FAIL_INDEX_MSG(p_data_type, Theme::DATA_TYPE_MAX, "Theme item data type is out of bounds.");18291830item_popup_mode = RENAME_THEME_ITEM;1831edit_item_data_type = p_data_type;1832edit_item_old_name = p_item_name;18331834switch (edit_item_data_type) {1835case Theme::DATA_TYPE_COLOR:1836edit_theme_item_dialog->set_title(TTR("Rename Color Item"));1837break;1838case Theme::DATA_TYPE_CONSTANT:1839edit_theme_item_dialog->set_title(TTR("Rename Constant Item"));1840break;1841case Theme::DATA_TYPE_FONT:1842edit_theme_item_dialog->set_title(TTR("Rename Font Item"));1843break;1844case Theme::DATA_TYPE_FONT_SIZE:1845edit_theme_item_dialog->set_title(TTR("Rename Font Size Item"));1846break;1847case Theme::DATA_TYPE_ICON:1848edit_theme_item_dialog->set_title(TTR("Rename Icon Item"));1849break;1850case Theme::DATA_TYPE_STYLEBOX:1851edit_theme_item_dialog->set_title(TTR("Rename Stylebox Item"));1852break;1853case Theme::DATA_TYPE_MAX:1854break; // Can't happen, but silences warning.1855}18561857edit_theme_item_old_vb->show();1858theme_item_old_name->set_text(p_item_name);1859theme_item_name->set_text(p_item_name);1860edit_theme_item_dialog->popup_centered(Size2(380, 140) * EDSCALE);1861theme_item_name->grab_focus();1862}18631864void ThemeItemEditorDialog::_confirm_edit_theme_item() {1865const String new_item_name = theme_item_name->get_text().strip_edges().validate_ascii_identifier();18661867if (item_popup_mode == CREATE_THEME_ITEM) {1868_add_theme_item(edit_item_data_type, new_item_name, edited_item_type);1869} else if (item_popup_mode == RENAME_THEME_ITEM) {1870EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();1871ur->create_action(TTR("Rename Theme Item"));18721873ur->add_do_method(*edited_theme, "rename_theme_item", edit_item_data_type, edit_item_old_name, new_item_name, edited_item_type);1874ur->add_undo_method(*edited_theme, "rename_theme_item", edit_item_data_type, new_item_name, edit_item_old_name, edited_item_type);18751876ur->add_do_method(this, "_update_edit_item_tree", edited_item_type);1877ur->add_undo_method(this, "_update_edit_item_tree", edited_item_type);18781879ur->commit_action();1880}18811882item_popup_mode = ITEM_POPUP_MODE_MAX;1883edit_item_data_type = Theme::DATA_TYPE_MAX;1884edit_item_old_name = "";1885}18861887void ThemeItemEditorDialog::_edit_theme_item_gui_input(const Ref<InputEvent> &p_event) {1888Ref<InputEventKey> k = p_event;18891890if (k.is_valid()) {1891if (!k->is_pressed()) {1892return;1893}18941895if (k->is_action_pressed(SNAME("ui_text_submit"), false, true)) {1896_confirm_edit_theme_item();1897edit_theme_item_dialog->hide();1898edit_theme_item_dialog->set_input_as_handled();1899} else if (k->is_action_pressed(SNAME("ui_cancel"), false, true)) {1900edit_theme_item_dialog->hide();1901edit_theme_item_dialog->set_input_as_handled();1902}1903}1904}19051906void ThemeItemEditorDialog::_open_select_another_theme() {1907import_another_theme_dialog->popup_file_dialog();1908}19091910void ThemeItemEditorDialog::_select_another_theme_cbk(const String &p_path) {1911Ref<Theme> loaded_theme = ResourceLoader::load(p_path);1912if (loaded_theme.is_null()) {1913EditorNode::get_singleton()->show_warning(TTR("Invalid file, not a Theme resource."));1914return;1915}1916if (loaded_theme == edited_theme) {1917EditorNode::get_singleton()->show_warning(TTR("Invalid file, same as the edited Theme resource."));1918return;1919}19201921import_another_theme_value->set_text(p_path);1922import_other_theme_items->set_base_theme(loaded_theme);1923import_other_theme_items->reset_item_tree();1924}19251926void ThemeItemEditorDialog::_notification(int p_what) {1927switch (p_what) {1928case NOTIFICATION_ENTER_TREE: {1929connect("about_to_popup", callable_mp(this, &ThemeItemEditorDialog::_dialog_about_to_show));1930[[fallthrough]];1931}1932case NOTIFICATION_THEME_CHANGED: {1933edit_items_add_color->set_button_icon(get_editor_theme_icon(SNAME("Color")));1934edit_items_add_constant->set_button_icon(get_editor_theme_icon(SNAME("MemberConstant")));1935edit_items_add_font->set_button_icon(get_editor_theme_icon(SNAME("FontItem")));1936edit_items_add_font_size->set_button_icon(get_editor_theme_icon(SNAME("FontSize")));1937edit_items_add_icon->set_button_icon(get_editor_theme_icon(SNAME("ImageTexture")));1938edit_items_add_stylebox->set_button_icon(get_editor_theme_icon(SNAME("StyleBoxFlat")));19391940edit_items_remove_class->set_button_icon(get_editor_theme_icon(SNAME("Control")));1941edit_items_remove_custom->set_button_icon(get_editor_theme_icon(SNAME("ThemeRemoveCustomItems")));1942edit_items_remove_all->set_button_icon(get_editor_theme_icon(SNAME("ThemeRemoveAllItems")));19431944edit_add_type_button->set_button_icon(get_editor_theme_icon(SNAME("Add")));19451946import_another_theme_button->set_button_icon(get_editor_theme_icon(SNAME("Folder")));1947} break;1948}1949}19501951void ThemeItemEditorDialog::_bind_methods() {1952ClassDB::bind_method(D_METHOD("_update_edit_types"), &ThemeItemEditorDialog::_update_edit_types);1953ClassDB::bind_method(D_METHOD("_update_edit_item_tree"), &ThemeItemEditorDialog::_update_edit_item_tree);1954}19551956void ThemeItemEditorDialog::set_edited_theme(const Ref<Theme> &p_theme) {1957edited_theme = p_theme;1958}19591960ThemeItemEditorDialog::ThemeItemEditorDialog(ThemeTypeEditor *p_theme_type_editor) {1961set_title(TTR("Manage Theme Items"));1962set_ok_button_text(TTR("Close"));1963set_hide_on_ok(false); // Closing may require a confirmation in some cases.19641965theme_type_editor = p_theme_type_editor;19661967tc = memnew(TabContainer);1968add_child(tc);1969tc->set_theme_type_variation("TabContainerOdd");19701971// Edit Items tab.1972HSplitContainer *edit_dialog_hs = memnew(HSplitContainer);1973tc->add_child(edit_dialog_hs);1974tc->set_tab_title(0, TTR("Edit Items"));19751976VBoxContainer *edit_dialog_side_vb = memnew(VBoxContainer);1977edit_dialog_side_vb->set_custom_minimum_size(Size2(200.0, 0.0) * EDSCALE);1978edit_dialog_hs->add_child(edit_dialog_side_vb);19791980Label *edit_type_label = memnew(Label);1981edit_type_label->set_text(TTR("Types:"));1982edit_dialog_side_vb->add_child(edit_type_label);19831984edit_type_list = memnew(Tree);1985edit_type_list->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED);1986edit_type_list->set_hide_root(true);1987edit_type_list->set_hide_folding(true);1988edit_type_list->set_columns(1);1989edit_type_list->set_v_size_flags(Control::SIZE_EXPAND_FILL);1990edit_dialog_side_vb->add_child(edit_type_list);1991edit_type_list->connect(SceneStringName(item_selected), callable_mp(this, &ThemeItemEditorDialog::_edited_type_selected));1992edit_type_list->connect("item_edited", callable_mp(this, &ThemeItemEditorDialog::_edited_type_edited));1993edit_type_list->connect("button_clicked", callable_mp(this, &ThemeItemEditorDialog::_edited_type_button_pressed));1994edit_type_list->set_theme_type_variation("TreeSecondary");19951996Label *edit_add_type_label = memnew(Label);1997edit_add_type_label->set_text(TTR("Add Type:"));1998edit_dialog_side_vb->add_child(edit_add_type_label);19992000HBoxContainer *edit_add_type_hb = memnew(HBoxContainer);2001edit_dialog_side_vb->add_child(edit_add_type_hb);2002edit_add_type_value = memnew(LineEdit);2003edit_add_type_value->set_h_size_flags(Control::SIZE_EXPAND_FILL);2004edit_add_type_value->connect(SceneStringName(text_submitted), callable_mp(this, &ThemeItemEditorDialog::_add_theme_type).unbind(1));2005edit_add_type_hb->add_child(edit_add_type_value);2006edit_add_type_button = memnew(Button);2007edit_add_type_hb->add_child(edit_add_type_button);2008edit_add_type_button->connect(SceneStringName(pressed), callable_mp(this, &ThemeItemEditorDialog::_add_theme_type));20092010VBoxContainer *edit_items_vb = memnew(VBoxContainer);2011edit_items_vb->set_h_size_flags(Control::SIZE_EXPAND_FILL);2012edit_dialog_hs->add_child(edit_items_vb);20132014HBoxContainer *edit_items_toolbar = memnew(HBoxContainer);2015edit_items_vb->add_child(edit_items_toolbar);20162017Label *edit_items_toolbar_add_label = memnew(Label);2018edit_items_toolbar_add_label->set_text(TTR("Add Item:"));2019edit_items_toolbar->add_child(edit_items_toolbar_add_label);20202021edit_items_add_color = memnew(Button);2022edit_items_add_color->set_tooltip_text(TTR("Add Color Item"));2023edit_items_add_color->set_flat(true);2024edit_items_add_color->set_disabled(true);2025edit_items_toolbar->add_child(edit_items_add_color);2026edit_items_add_color->connect(SceneStringName(pressed), callable_mp(this, &ThemeItemEditorDialog::_open_add_theme_item_dialog).bind(Theme::DATA_TYPE_COLOR));20272028edit_items_add_constant = memnew(Button);2029edit_items_add_constant->set_tooltip_text(TTR("Add Constant Item"));2030edit_items_add_constant->set_flat(true);2031edit_items_add_constant->set_disabled(true);2032edit_items_toolbar->add_child(edit_items_add_constant);2033edit_items_add_constant->connect(SceneStringName(pressed), callable_mp(this, &ThemeItemEditorDialog::_open_add_theme_item_dialog).bind(Theme::DATA_TYPE_CONSTANT));20342035edit_items_add_font = memnew(Button);2036edit_items_add_font->set_tooltip_text(TTR("Add Font Item"));2037edit_items_add_font->set_flat(true);2038edit_items_add_font->set_disabled(true);2039edit_items_toolbar->add_child(edit_items_add_font);2040edit_items_add_font->connect(SceneStringName(pressed), callable_mp(this, &ThemeItemEditorDialog::_open_add_theme_item_dialog).bind(Theme::DATA_TYPE_FONT));20412042edit_items_add_font_size = memnew(Button);2043edit_items_add_font_size->set_tooltip_text(TTR("Add Font Size Item"));2044edit_items_add_font_size->set_flat(true);2045edit_items_add_font_size->set_disabled(true);2046edit_items_toolbar->add_child(edit_items_add_font_size);2047edit_items_add_font_size->connect(SceneStringName(pressed), callable_mp(this, &ThemeItemEditorDialog::_open_add_theme_item_dialog).bind(Theme::DATA_TYPE_FONT_SIZE));20482049edit_items_add_icon = memnew(Button);2050edit_items_add_icon->set_tooltip_text(TTR("Add Icon Item"));2051edit_items_add_icon->set_flat(true);2052edit_items_add_icon->set_disabled(true);2053edit_items_toolbar->add_child(edit_items_add_icon);2054edit_items_add_icon->connect(SceneStringName(pressed), callable_mp(this, &ThemeItemEditorDialog::_open_add_theme_item_dialog).bind(Theme::DATA_TYPE_ICON));20552056edit_items_add_stylebox = memnew(Button);2057edit_items_add_stylebox->set_tooltip_text(TTR("Add StyleBox Item"));2058edit_items_add_stylebox->set_flat(true);2059edit_items_add_stylebox->set_disabled(true);2060edit_items_toolbar->add_child(edit_items_add_stylebox);2061edit_items_add_stylebox->connect(SceneStringName(pressed), callable_mp(this, &ThemeItemEditorDialog::_open_add_theme_item_dialog).bind(Theme::DATA_TYPE_STYLEBOX));20622063edit_items_toolbar->add_child(memnew(VSeparator));20642065Label *edit_items_toolbar_remove_label = memnew(Label);2066edit_items_toolbar_remove_label->set_text(TTR("Remove Items:"));2067edit_items_toolbar->add_child(edit_items_toolbar_remove_label);20682069edit_items_remove_class = memnew(Button);2070edit_items_remove_class->set_tooltip_text(TTR("Remove Class Items"));2071edit_items_remove_class->set_flat(true);2072edit_items_remove_class->set_disabled(true);2073edit_items_toolbar->add_child(edit_items_remove_class);2074edit_items_remove_class->connect(SceneStringName(pressed), callable_mp(this, &ThemeItemEditorDialog::_remove_class_items));20752076edit_items_remove_custom = memnew(Button);2077edit_items_remove_custom->set_tooltip_text(TTR("Remove Custom Items"));2078edit_items_remove_custom->set_flat(true);2079edit_items_remove_custom->set_disabled(true);2080edit_items_toolbar->add_child(edit_items_remove_custom);2081edit_items_remove_custom->connect(SceneStringName(pressed), callable_mp(this, &ThemeItemEditorDialog::_remove_custom_items));20822083edit_items_remove_all = memnew(Button);2084edit_items_remove_all->set_tooltip_text(TTR("Remove All Items"));2085edit_items_remove_all->set_flat(true);2086edit_items_remove_all->set_disabled(true);2087edit_items_toolbar->add_child(edit_items_remove_all);2088edit_items_remove_all->connect(SceneStringName(pressed), callable_mp(this, &ThemeItemEditorDialog::_remove_all_items));20892090edit_items_tree = memnew(Tree);2091edit_items_tree->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED);2092edit_items_tree->set_v_size_flags(Control::SIZE_EXPAND_FILL);2093edit_items_tree->set_hide_root(true);2094edit_items_tree->set_columns(1);2095edit_items_vb->add_child(edit_items_tree);2096edit_items_tree->connect("button_clicked", callable_mp(this, &ThemeItemEditorDialog::_item_tree_button_pressed));20972098edit_items_message = memnew(Label);2099edit_items_message->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT);2100edit_items_message->set_mouse_filter(Control::MOUSE_FILTER_STOP);2101edit_items_message->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_CENTER);2102edit_items_message->set_vertical_alignment(VERTICAL_ALIGNMENT_CENTER);2103edit_items_message->set_autowrap_mode(TextServer::AUTOWRAP_WORD);2104edit_items_tree->add_child(edit_items_message);21052106edit_theme_item_dialog = memnew(ConfirmationDialog);2107edit_theme_item_dialog->set_title(TTR("Add Theme Item"));2108add_child(edit_theme_item_dialog);2109VBoxContainer *edit_theme_item_vb = memnew(VBoxContainer);2110edit_theme_item_dialog->add_child(edit_theme_item_vb);21112112edit_theme_item_old_vb = memnew(VBoxContainer);2113edit_theme_item_vb->add_child(edit_theme_item_old_vb);2114Label *edit_theme_item_old = memnew(Label);2115edit_theme_item_old->set_text(TTR("Old Name:"));2116edit_theme_item_old_vb->add_child(edit_theme_item_old);2117theme_item_old_name = memnew(Label);2118edit_theme_item_old_vb->add_child(theme_item_old_name);21192120Label *edit_theme_item_label = memnew(Label);2121edit_theme_item_label->set_text(TTR("Name:"));2122edit_theme_item_vb->add_child(edit_theme_item_label);2123theme_item_name = memnew(LineEdit);2124edit_theme_item_vb->add_child(theme_item_name);2125theme_item_name->connect(SceneStringName(gui_input), callable_mp(this, &ThemeItemEditorDialog::_edit_theme_item_gui_input));2126edit_theme_item_dialog->connect(SceneStringName(confirmed), callable_mp(this, &ThemeItemEditorDialog::_confirm_edit_theme_item));21272128// Import Items tab.2129TabContainer *import_tc = memnew(TabContainer);2130import_tc->set_tab_alignment(TabBar::ALIGNMENT_CENTER);2131tc->add_child(import_tc);2132tc->set_tab_title(1, TTR("Import Items"));21332134import_default_theme_items = memnew(ThemeItemImportTree);2135import_tc->add_child(import_default_theme_items);2136import_tc->set_tab_title(0, TTR("Default Theme"));2137import_default_theme_items->connect("items_imported", callable_mp(this, &ThemeItemEditorDialog::_update_edit_types));21382139import_editor_theme_items = memnew(ThemeItemImportTree);2140import_tc->add_child(import_editor_theme_items);2141import_tc->set_tab_title(1, TTR("Editor Theme"));2142import_editor_theme_items->connect("items_imported", callable_mp(this, &ThemeItemEditorDialog::_update_edit_types));21432144VBoxContainer *import_another_theme_vb = memnew(VBoxContainer);21452146HBoxContainer *import_another_file_hb = memnew(HBoxContainer);2147import_another_theme_vb->add_child(import_another_file_hb);2148import_another_theme_value = memnew(LineEdit);2149import_another_theme_value->set_h_size_flags(Control::SIZE_EXPAND_FILL);2150import_another_theme_value->set_editable(false);2151import_another_file_hb->add_child(import_another_theme_value);2152import_another_theme_button = memnew(Button);2153import_another_file_hb->add_child(import_another_theme_button);2154import_another_theme_button->connect(SceneStringName(pressed), callable_mp(this, &ThemeItemEditorDialog::_open_select_another_theme));21552156import_another_theme_dialog = memnew(EditorFileDialog);2157import_another_theme_dialog->set_file_mode(EditorFileDialog::FILE_MODE_OPEN_FILE);2158import_another_theme_dialog->set_title(TTR("Select Another Theme Resource:"));2159List<String> ext;2160ResourceLoader::get_recognized_extensions_for_type("Theme", &ext);2161for (const String &E : ext) {2162import_another_theme_dialog->add_filter("*." + E, TTR("Theme Resource"));2163}2164import_another_file_hb->add_child(import_another_theme_dialog);2165import_another_theme_dialog->connect("file_selected", callable_mp(this, &ThemeItemEditorDialog::_select_another_theme_cbk));21662167import_other_theme_items = memnew(ThemeItemImportTree);2168import_other_theme_items->set_v_size_flags(Control::SIZE_EXPAND_FILL);2169import_another_theme_vb->add_child(import_other_theme_items);21702171import_tc->add_child(import_another_theme_vb);2172import_tc->set_tab_title(2, TTR("Another Theme"));2173import_other_theme_items->connect("items_imported", callable_mp(this, &ThemeItemEditorDialog::_update_edit_types));21742175confirm_closing_dialog = memnew(ConfirmationDialog);2176confirm_closing_dialog->set_autowrap(true);2177add_child(confirm_closing_dialog);2178confirm_closing_dialog->connect(SceneStringName(confirmed), callable_mp(this, &ThemeItemEditorDialog::_close_dialog));2179}21802181///////////////////////21822183void ThemeTypeDialog::_dialog_about_to_show() {2184add_type_filter->set_text("");2185add_type_filter->grab_focus();21862187_update_add_type_options();2188}21892190void ThemeTypeDialog::ok_pressed() {2191_add_type_selected(add_type_filter->get_text().strip_edges());2192}21932194void ThemeTypeDialog::_update_add_type_options(const String &p_filter) {2195add_type_options->clear();21962197List<StringName> names;2198ThemeDB::get_singleton()->get_default_theme()->get_type_list(&names);2199if (include_own_types) {2200edited_theme->get_type_list(&names);2201}2202names.sort_custom<StringName::AlphCompare>();22032204Vector<StringName> unique_names;2205for (const StringName &E : names) {2206// Filter out undesired values.2207if (!p_filter.is_subsequence_ofn(String(E))) {2208continue;2209}22102211// Skip duplicate values.2212if (unique_names.has(E)) {2213continue;2214}2215unique_names.append(E);22162217Ref<Texture2D> item_icon;2218if (E == "") {2219item_icon = get_editor_theme_icon(SNAME("NodeDisabled"));2220} else {2221item_icon = EditorNode::get_singleton()->get_class_icon(E, "NodeDisabled");2222}22232224add_type_options->add_item(E, item_icon);2225}2226}22272228void ThemeTypeDialog::_add_type_filter_cbk(const String &p_value) {2229_update_add_type_options(p_value);2230}22312232void ThemeTypeDialog::_type_filter_input(const Ref<InputEvent> &p_event) {2233// Redirect navigational key events to the item list.2234Ref<InputEventKey> key = p_event;2235if (key.is_valid()) {2236if (key->is_action("ui_up", true) || key->is_action("ui_down", true) || key->is_action("ui_page_up") || key->is_action("ui_page_down")) {2237add_type_options->gui_input(key);2238add_type_filter->accept_event();2239}2240}2241}22422243void ThemeTypeDialog::_add_type_options_cbk(int p_index) {2244add_type_filter->set_text(add_type_options->get_item_text(p_index));2245add_type_filter->set_caret_column(add_type_filter->get_text().length());2246}22472248void ThemeTypeDialog::_add_type_dialog_entered(const String &p_value) {2249_add_type_selected(Theme::validate_type_name(p_value));2250}22512252void ThemeTypeDialog::_add_type_dialog_activated(int p_index) {2253_add_type_selected(add_type_options->get_item_text(p_index));2254}22552256void ThemeTypeDialog::_add_type_selected(const String &p_type_name) {2257pre_submitted_value = p_type_name;2258if (p_type_name.is_empty()) {2259add_type_confirmation->popup_centered();2260return;2261}22622263_add_type_confirmed();2264}22652266void ThemeTypeDialog::_add_type_confirmed() {2267emit_signal(SNAME("type_selected"), pre_submitted_value);2268hide();2269}22702271void ThemeTypeDialog::_notification(int p_what) {2272switch (p_what) {2273case NOTIFICATION_ENTER_TREE: {2274connect("about_to_popup", callable_mp(this, &ThemeTypeDialog::_dialog_about_to_show));2275[[fallthrough]];2276}2277case NOTIFICATION_THEME_CHANGED: {2278_update_add_type_options();2279} break;22802281case NOTIFICATION_VISIBILITY_CHANGED: {2282if (is_visible()) {2283add_type_filter->grab_focus();2284}2285} break;2286}2287}22882289void ThemeTypeDialog::_bind_methods() {2290ADD_SIGNAL(MethodInfo("type_selected", PropertyInfo(Variant::STRING, "type_name")));2291}22922293void ThemeTypeDialog::set_edited_theme(const Ref<Theme> &p_theme) {2294edited_theme = p_theme;2295}22962297void ThemeTypeDialog::set_include_own_types(bool p_enable) {2298include_own_types = p_enable;2299}23002301ThemeTypeDialog::ThemeTypeDialog() {2302set_hide_on_ok(false);23032304VBoxContainer *add_type_vb = memnew(VBoxContainer);2305add_child(add_type_vb);23062307Label *add_type_filter_label = memnew(Label);2308add_type_filter_label->set_text(TTR("Filter the list of types or create a new custom type:"));2309add_type_vb->add_child(add_type_filter_label);23102311add_type_filter = memnew(LineEdit);2312add_type_vb->add_child(add_type_filter);2313add_type_filter->connect(SceneStringName(text_changed), callable_mp(this, &ThemeTypeDialog::_add_type_filter_cbk));2314add_type_filter->connect(SceneStringName(text_submitted), callable_mp(this, &ThemeTypeDialog::_add_type_dialog_entered));2315add_type_filter->connect(SceneStringName(gui_input), callable_mp(this, &ThemeTypeDialog::_type_filter_input));23162317Label *add_type_options_label = memnew(Label);2318add_type_options_label->set_text(TTR("Available Node-based types:"));2319add_type_vb->add_child(add_type_options_label);23202321add_type_options = memnew(ItemList);2322add_type_options->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED);2323add_type_options->set_v_size_flags(Control::SIZE_EXPAND_FILL);2324add_type_vb->add_child(add_type_options);2325add_type_options->connect(SceneStringName(item_selected), callable_mp(this, &ThemeTypeDialog::_add_type_options_cbk));2326add_type_options->connect("item_activated", callable_mp(this, &ThemeTypeDialog::_add_type_dialog_activated));23272328add_type_confirmation = memnew(ConfirmationDialog);2329add_type_confirmation->set_title(TTR("Type name is empty!"));2330add_type_confirmation->set_text(TTR("Are you sure you want to create an empty type?"));2331add_type_confirmation->connect(SceneStringName(confirmed), callable_mp(this, &ThemeTypeDialog::_add_type_confirmed));2332add_child(add_type_confirmation);2333}23342335///////////////////////23362337Control *ThemeItemLabel::make_custom_tooltip(const String &p_text) const {2338return EditorHelpBitTooltip::show_tooltip(const_cast<ThemeItemLabel *>(this), p_text);2339}23402341VBoxContainer *ThemeTypeEditor::_create_item_list(Theme::DataType p_data_type) {2342VBoxContainer *items_tab = memnew(VBoxContainer);2343items_tab->set_custom_minimum_size(Size2(0, 160) * EDSCALE);2344data_type_tabs->add_child(items_tab);2345data_type_tabs->set_tab_title(data_type_tabs->get_tab_count() - 1, "");23462347ScrollContainer *items_sc = memnew(ScrollContainer);2348items_sc->set_v_size_flags(SIZE_EXPAND_FILL);2349items_sc->set_horizontal_scroll_mode(ScrollContainer::SCROLL_MODE_DISABLED);2350items_tab->add_child(items_sc);2351VBoxContainer *items_list = memnew(VBoxContainer);2352items_list->set_h_size_flags(SIZE_EXPAND_FILL);2353items_sc->add_child(items_list);23542355HBoxContainer *item_add_hb = memnew(HBoxContainer);2356items_tab->add_child(item_add_hb);2357LineEdit *item_add_edit = memnew(LineEdit);2358item_add_edit->set_h_size_flags(SIZE_EXPAND_FILL);2359item_add_hb->add_child(item_add_edit);2360item_add_edit->connect(SceneStringName(text_submitted), callable_mp(this, &ThemeTypeEditor::_item_add_lineedit_cbk).bind(p_data_type, item_add_edit));2361Button *item_add_button = memnew(Button);2362item_add_button->set_text(TTR("Add"));2363item_add_button->set_disabled(true);2364item_add_hb->add_child(item_add_button);2365item_add_button->connect(SceneStringName(pressed), callable_mp(this, &ThemeTypeEditor::_item_add_cbk).bind(p_data_type, item_add_edit));2366item_add_edit->set_meta("button", item_add_button);2367item_add_edit->connect(SceneStringName(text_changed), callable_mp(this, &ThemeTypeEditor::_update_add_button).bind(item_add_edit));23682369return items_list;2370}23712372void ThemeTypeEditor::_update_type_list() {2373ERR_FAIL_COND(edited_theme.is_null());23742375if (updating) {2376return;2377}2378updating = true;23792380Control *focused = get_viewport()->gui_get_focus_owner();2381if (focused) {2382if (focusables.has(focused)) {2383// If focus is currently on one of the internal property editors, don't update.2384updating = false;2385return;2386}23872388Node *focus_parent = focused->get_parent();2389while (focus_parent) {2390Control *c = Object::cast_to<Control>(focus_parent);2391if (c && focusables.has(c)) {2392// If focus is currently on one of the internal property editors, don't update.2393updating = false;2394return;2395}23962397focus_parent = focus_parent->get_parent();2398}2399}24002401List<StringName> theme_types;2402edited_theme->get_type_list(&theme_types);2403theme_types.sort_custom<StringName::AlphCompare>();24042405theme_type_list->clear();24062407if (theme_types.is_empty()) {2408theme_type_list->set_disabled(true);2409theme_type_list->add_item(TTRC("None"));2410theme_type_list->set_item_auto_translate_mode(-1, AUTO_TRANSLATE_MODE_ALWAYS);24112412edited_type = "";2413_update_type_items();2414} else {2415theme_type_list->set_disabled(false);24162417bool item_reselected = false;2418int e_idx = 0;2419for (const StringName &E : theme_types) {2420Ref<Texture2D> item_icon;2421if (E == "") {2422item_icon = get_editor_theme_icon(SNAME("NodeDisabled"));2423} else {2424item_icon = EditorNode::get_singleton()->get_class_icon(E, "NodeDisabled");2425}2426theme_type_list->add_icon_item(item_icon, E);24272428if (E == edited_type) {2429theme_type_list->select(e_idx);2430item_reselected = true;2431}2432e_idx++;2433}24342435if (item_reselected) {2436_update_type_items();2437} else {2438theme_type_list->select(0);2439_list_type_selected(0);2440}2441}24422443rename_type_button->set_disabled(theme_types.is_empty());2444remove_type_button->set_disabled(theme_types.is_empty());24452446updating = false;2447}24482449void ThemeTypeEditor::_update_type_list_debounced() {2450update_debounce_timer->start();2451}24522453HashMap<StringName, bool> ThemeTypeEditor::_get_type_items(String p_type_name, Theme::DataType p_type, bool p_include_default) {2454HashMap<StringName, bool> items;2455List<StringName> names;24562457if (p_include_default) {2458names.clear();2459String default_type;24602461{2462const StringName variation_base = edited_theme->get_type_variation_base(p_type_name);2463if (variation_base != StringName()) {2464default_type = variation_base;2465}2466}24672468if (default_type.is_empty()) {2469// If variation base was not found in the edited theme, look in the default theme.2470const StringName variation_base = ThemeDB::get_singleton()->get_default_theme()->get_type_variation_base(p_type_name);2471if (variation_base != StringName()) {2472default_type = variation_base;2473}2474}24752476if (default_type.is_empty()) {2477default_type = p_type_name;2478}24792480List<ThemeDB::ThemeItemBind> theme_binds;2481ThemeDB::get_singleton()->get_class_items(default_type, &theme_binds, true, p_type);2482for (const ThemeDB::ThemeItemBind &E : theme_binds) {2483names.push_back(E.item_name);2484}24852486names.sort_custom<StringName::AlphCompare>();2487for (const StringName &E : names) {2488items[E] = false;2489}2490}24912492{2493names.clear();2494edited_theme->get_theme_item_list(p_type, p_type_name, &names);2495names.sort_custom<StringName::AlphCompare>();2496for (const StringName &E : names) {2497items[E] = true;2498}2499}25002501List<StringName> keys;2502for (const KeyValue<StringName, bool> &E : items) {2503keys.push_back(E.key);2504}2505keys.sort_custom<StringName::AlphCompare>();25062507HashMap<StringName, bool> ordered_items;2508for (const StringName &E : keys) {2509ordered_items[E] = items[E];2510}25112512return ordered_items;2513}25142515HBoxContainer *ThemeTypeEditor::_create_property_control(Theme::DataType p_data_type, String p_item_name, bool p_editable) {2516HBoxContainer *item_control = memnew(HBoxContainer);25172518HBoxContainer *item_name_container = memnew(HBoxContainer);2519item_name_container->set_h_size_flags(SIZE_EXPAND_FILL);2520item_name_container->set_stretch_ratio(2.0);2521item_control->add_child(item_name_container);25222523Label *item_name = memnew(ThemeItemLabel);2524item_name->set_h_size_flags(SIZE_EXPAND_FILL);2525item_name->set_clip_text(true);2526item_name->set_text(p_item_name);2527// `|` separators used in `EditorHelpBit`.2528item_name->set_tooltip_text("theme_item|" + edited_type + "|" + p_item_name);2529item_name->set_mouse_filter(Control::MOUSE_FILTER_STOP);2530item_name_container->add_child(item_name);25312532if (p_editable) {2533LineEdit *item_name_edit = memnew(LineEdit);2534item_name_edit->set_h_size_flags(SIZE_EXPAND_FILL);2535item_name_edit->set_text(p_item_name);2536item_name_container->add_child(item_name_edit);2537item_name_edit->connect(SceneStringName(text_submitted), callable_mp(this, &ThemeTypeEditor::_item_rename_entered).bind(p_data_type, p_item_name, item_name_container));2538item_name_edit->hide();25392540Button *item_rename_button = memnew(Button);2541item_rename_button->set_button_icon(get_editor_theme_icon(SNAME("Edit")));2542item_rename_button->set_tooltip_text(TTR("Rename Item"));2543item_rename_button->set_flat(true);2544item_name_container->add_child(item_rename_button);2545item_rename_button->connect(SceneStringName(pressed), callable_mp(this, &ThemeTypeEditor::_item_rename_cbk).bind(p_data_type, p_item_name, item_name_container));25462547Button *item_remove_button = memnew(Button);2548item_remove_button->set_button_icon(get_editor_theme_icon(SNAME("Remove")));2549item_remove_button->set_tooltip_text(TTR("Remove Item"));2550item_remove_button->set_flat(true);2551item_name_container->add_child(item_remove_button);2552item_remove_button->connect(SceneStringName(pressed), callable_mp(this, &ThemeTypeEditor::_item_remove_cbk).bind(p_data_type, p_item_name));25532554Button *item_rename_confirm_button = memnew(Button);2555item_rename_confirm_button->set_button_icon(get_editor_theme_icon(SNAME("ImportCheck")));2556item_rename_confirm_button->set_tooltip_text(TTR("Confirm Item Rename"));2557item_rename_confirm_button->set_flat(true);2558item_name_container->add_child(item_rename_confirm_button);2559item_rename_confirm_button->connect(SceneStringName(pressed), callable_mp(this, &ThemeTypeEditor::_item_rename_confirmed).bind(p_data_type, p_item_name, item_name_container));2560item_rename_confirm_button->hide();25612562Button *item_rename_cancel_button = memnew(Button);2563item_rename_cancel_button->set_button_icon(get_editor_theme_icon(SNAME("ImportFail")));2564item_rename_cancel_button->set_tooltip_text(TTR("Cancel Item Rename"));2565item_rename_cancel_button->set_flat(true);2566item_name_container->add_child(item_rename_cancel_button);2567item_rename_cancel_button->connect(SceneStringName(pressed), callable_mp(this, &ThemeTypeEditor::_item_rename_canceled).bind(p_data_type, p_item_name, item_name_container));2568item_rename_cancel_button->hide();2569} else {2570item_name->add_theme_color_override(SceneStringName(font_color), get_theme_color(SNAME("font_disabled_color"), EditorStringName(Editor)));25712572Button *item_override_button = memnew(Button);2573item_override_button->set_button_icon(get_editor_theme_icon(SNAME("Add")));2574item_override_button->set_tooltip_text(TTR("Override Item"));2575item_override_button->set_flat(true);2576item_name_container->add_child(item_override_button);2577item_override_button->connect(SceneStringName(pressed), callable_mp(this, &ThemeTypeEditor::_item_override_cbk).bind(p_data_type, p_item_name));2578}25792580return item_control;2581}25822583void ThemeTypeEditor::_add_focusable(Control *p_control) {2584focusables.append(p_control);2585}25862587void ThemeTypeEditor::_update_type_items() {2588bool show_default = show_default_items_button->is_pressed();25892590focusables.clear();25912592// Colors.2593{2594for (int i = color_items_list->get_child_count() - 1; i >= 0; i--) {2595Node *node = color_items_list->get_child(i);2596node->queue_free();2597color_items_list->remove_child(node);2598}25992600HashMap<StringName, bool> color_items = _get_type_items(edited_type, Theme::DATA_TYPE_COLOR, show_default);2601for (const KeyValue<StringName, bool> &E : color_items) {2602HBoxContainer *item_control = _create_property_control(Theme::DATA_TYPE_COLOR, E.key, E.value);2603ColorPickerButton *item_editor = memnew(ColorPickerButton);2604item_editor->set_h_size_flags(SIZE_EXPAND_FILL);2605item_control->add_child(item_editor);26062607if (E.value) {2608item_editor->set_pick_color(edited_theme->get_color(E.key, edited_type));2609item_editor->connect("color_changed", callable_mp(this, &ThemeTypeEditor::_color_item_changed).bind(E.key));2610item_editor->get_popup()->connect("about_to_popup", callable_mp(EditorNode::get_singleton(), &EditorNode::setup_color_picker).bind(item_editor->get_picker()));2611} else {2612item_editor->set_pick_color(ThemeDB::get_singleton()->get_default_theme()->get_color(E.key, edited_type));2613item_editor->set_disabled(true);2614}26152616_add_focusable(item_editor);2617color_items_list->add_child(item_control);2618}2619}26202621// Constants.2622{2623for (int i = constant_items_list->get_child_count() - 1; i >= 0; i--) {2624Node *node = constant_items_list->get_child(i);2625node->queue_free();2626constant_items_list->remove_child(node);2627}26282629HashMap<StringName, bool> constant_items = _get_type_items(edited_type, Theme::DATA_TYPE_CONSTANT, show_default);2630for (const KeyValue<StringName, bool> &E : constant_items) {2631HBoxContainer *item_control = _create_property_control(Theme::DATA_TYPE_CONSTANT, E.key, E.value);2632SpinBox *item_editor = memnew(SpinBox);2633item_editor->set_h_size_flags(SIZE_EXPAND_FILL);2634item_editor->set_min(-100000);2635item_editor->set_max(100000);2636item_editor->set_step(1);2637item_editor->set_allow_lesser(true);2638item_editor->set_allow_greater(true);2639item_control->add_child(item_editor);26402641if (E.value) {2642item_editor->set_value(edited_theme->get_constant(E.key, edited_type));2643item_editor->connect(SceneStringName(value_changed), callable_mp(this, &ThemeTypeEditor::_constant_item_changed).bind(E.key));2644} else {2645item_editor->set_value(ThemeDB::get_singleton()->get_default_theme()->get_constant(E.key, edited_type));2646item_editor->set_editable(false);2647}26482649_add_focusable(item_editor);2650constant_items_list->add_child(item_control);2651}2652}26532654// Fonts.2655{2656for (int i = font_items_list->get_child_count() - 1; i >= 0; i--) {2657Node *node = font_items_list->get_child(i);2658node->queue_free();2659font_items_list->remove_child(node);2660}26612662HashMap<StringName, bool> font_items = _get_type_items(edited_type, Theme::DATA_TYPE_FONT, show_default);2663for (const KeyValue<StringName, bool> &E : font_items) {2664HBoxContainer *item_control = _create_property_control(Theme::DATA_TYPE_FONT, E.key, E.value);2665EditorResourcePicker *item_editor = memnew(EditorResourcePicker);2666item_editor->set_h_size_flags(SIZE_EXPAND_FILL);2667item_editor->set_base_type("Font");2668item_editor->set_resource_owner(*edited_theme);2669item_control->add_child(item_editor);26702671if (E.value) {2672if (edited_theme->has_font(E.key, edited_type)) {2673item_editor->set_edited_resource(edited_theme->get_font(E.key, edited_type));2674} else {2675item_editor->set_edited_resource(Ref<Resource>());2676}2677item_editor->connect("resource_selected", callable_mp(this, &ThemeTypeEditor::_edit_resource_item));2678item_editor->connect("resource_changed", callable_mp(this, &ThemeTypeEditor::_font_item_changed).bind(E.key));2679} else {2680if (ThemeDB::get_singleton()->get_default_theme()->has_font(E.key, edited_type)) {2681item_editor->set_edited_resource(ThemeDB::get_singleton()->get_default_theme()->get_font(E.key, edited_type));2682} else {2683item_editor->set_edited_resource(Ref<Resource>());2684}2685item_editor->set_editable(false);2686}26872688_add_focusable(item_editor);2689font_items_list->add_child(item_control);2690}2691}26922693// Fonts sizes.2694{2695for (int i = font_size_items_list->get_child_count() - 1; i >= 0; i--) {2696Node *node = font_size_items_list->get_child(i);2697node->queue_free();2698font_size_items_list->remove_child(node);2699}27002701HashMap<StringName, bool> font_size_items = _get_type_items(edited_type, Theme::DATA_TYPE_FONT_SIZE, show_default);2702for (const KeyValue<StringName, bool> &E : font_size_items) {2703HBoxContainer *item_control = _create_property_control(Theme::DATA_TYPE_FONT_SIZE, E.key, E.value);2704SpinBox *item_editor = memnew(SpinBox);2705item_editor->set_h_size_flags(SIZE_EXPAND_FILL);2706item_editor->set_min(-100000);2707item_editor->set_max(100000);2708item_editor->set_step(1);2709item_editor->set_allow_lesser(true);2710item_editor->set_allow_greater(true);2711item_control->add_child(item_editor);27122713if (E.value) {2714item_editor->set_value(edited_theme->get_font_size(E.key, edited_type));2715item_editor->connect(SceneStringName(value_changed), callable_mp(this, &ThemeTypeEditor::_font_size_item_changed).bind(E.key));2716} else {2717item_editor->set_value(ThemeDB::get_singleton()->get_default_theme()->get_font_size(E.key, edited_type));2718item_editor->set_editable(false);2719}27202721_add_focusable(item_editor);2722font_size_items_list->add_child(item_control);2723}2724}27252726// Icons.2727{2728for (int i = icon_items_list->get_child_count() - 1; i >= 0; i--) {2729Node *node = icon_items_list->get_child(i);2730node->queue_free();2731icon_items_list->remove_child(node);2732}27332734HashMap<StringName, bool> icon_items = _get_type_items(edited_type, Theme::DATA_TYPE_ICON, show_default);2735for (const KeyValue<StringName, bool> &E : icon_items) {2736HBoxContainer *item_control = _create_property_control(Theme::DATA_TYPE_ICON, E.key, E.value);2737EditorResourcePicker *item_editor = memnew(EditorResourcePicker);2738item_editor->set_h_size_flags(SIZE_EXPAND_FILL);2739item_editor->set_base_type("Texture2D");2740item_editor->set_resource_owner(*edited_theme);2741item_control->add_child(item_editor);27422743if (E.value) {2744if (edited_theme->has_icon(E.key, edited_type)) {2745item_editor->set_edited_resource(edited_theme->get_icon(E.key, edited_type));2746} else {2747item_editor->set_edited_resource(Ref<Resource>());2748}2749item_editor->connect("resource_selected", callable_mp(this, &ThemeTypeEditor::_edit_resource_item));2750item_editor->connect("resource_changed", callable_mp(this, &ThemeTypeEditor::_icon_item_changed).bind(E.key));2751} else {2752if (ThemeDB::get_singleton()->get_default_theme()->has_icon(E.key, edited_type)) {2753item_editor->set_edited_resource(ThemeDB::get_singleton()->get_default_theme()->get_icon(E.key, edited_type));2754} else {2755item_editor->set_edited_resource(Ref<Resource>());2756}2757item_editor->set_editable(false);2758}27592760_add_focusable(item_editor);2761icon_items_list->add_child(item_control);2762}2763}27642765// Styleboxes.2766{2767for (int i = stylebox_items_list->get_child_count() - 1; i >= 0; i--) {2768Node *node = stylebox_items_list->get_child(i);2769node->queue_free();2770stylebox_items_list->remove_child(node);2771}27722773if (leading_stylebox.pinned) {2774HBoxContainer *item_control = _create_property_control(Theme::DATA_TYPE_STYLEBOX, leading_stylebox.item_name, true);2775EditorResourcePicker *item_editor = memnew(EditorResourcePicker);2776item_editor->set_h_size_flags(SIZE_EXPAND_FILL);2777item_editor->set_stretch_ratio(1.5);2778item_editor->set_base_type("StyleBox");2779item_editor->set_resource_owner(*edited_theme);27802781Button *pin_leader_button = memnew(Button);2782pin_leader_button->set_flat(true);2783pin_leader_button->set_toggle_mode(true);2784pin_leader_button->set_pressed(true);2785pin_leader_button->set_button_icon(get_editor_theme_icon(SNAME("Pin")));2786pin_leader_button->set_tooltip_text(TTR("Unpin this StyleBox as a main style."));2787item_control->add_child(pin_leader_button);2788pin_leader_button->connect(SceneStringName(pressed), callable_mp(this, &ThemeTypeEditor::_on_unpin_leader_button_pressed));27892790item_control->add_child(item_editor);27912792if (edited_theme->has_stylebox(leading_stylebox.item_name, edited_type)) {2793item_editor->set_edited_resource(leading_stylebox.stylebox);2794} else {2795item_editor->set_edited_resource(Ref<Resource>());2796}2797item_editor->connect("resource_selected", callable_mp(this, &ThemeTypeEditor::_edit_resource_item));2798item_editor->connect("resource_changed", callable_mp(this, &ThemeTypeEditor::_stylebox_item_changed).bind(leading_stylebox.item_name));27992800stylebox_items_list->add_child(item_control);2801stylebox_items_list->add_child(memnew(HSeparator));2802}28032804HashMap<StringName, bool> stylebox_items = _get_type_items(edited_type, Theme::DATA_TYPE_STYLEBOX, show_default);2805for (const KeyValue<StringName, bool> &E : stylebox_items) {2806if (leading_stylebox.pinned && leading_stylebox.item_name == E.key) {2807continue;2808}28092810HBoxContainer *item_control = _create_property_control(Theme::DATA_TYPE_STYLEBOX, E.key, E.value);2811EditorResourcePicker *item_editor = memnew(EditorResourcePicker);2812item_editor->set_h_size_flags(SIZE_EXPAND_FILL);2813item_editor->set_stretch_ratio(1.5);2814item_editor->set_base_type("StyleBox");2815item_editor->set_resource_owner(*edited_theme);28162817if (E.value) {2818if (edited_theme->has_stylebox(E.key, edited_type)) {2819item_editor->set_edited_resource(edited_theme->get_stylebox(E.key, edited_type));2820} else {2821item_editor->set_edited_resource(Ref<Resource>());2822}2823item_editor->connect("resource_selected", callable_mp(this, &ThemeTypeEditor::_edit_resource_item));2824item_editor->connect("resource_changed", callable_mp(this, &ThemeTypeEditor::_stylebox_item_changed).bind(E.key));28252826Button *pin_leader_button = memnew(Button);2827pin_leader_button->set_flat(true);2828pin_leader_button->set_toggle_mode(true);2829pin_leader_button->set_button_icon(get_editor_theme_icon(SNAME("Pin")));2830pin_leader_button->set_tooltip_text(TTR("Pin this StyleBox as a main style. Editing its properties will update the same properties in all other StyleBoxes of this type."));2831pin_leader_button->set_accessibility_name(TTRC("Pin this StyleBox as a main style."));2832item_control->add_child(pin_leader_button);2833pin_leader_button->connect(SceneStringName(pressed), callable_mp(this, &ThemeTypeEditor::_on_pin_leader_button_pressed).bind(item_editor, E.key));2834} else {2835if (ThemeDB::get_singleton()->get_default_theme()->has_stylebox(E.key, edited_type)) {2836item_editor->set_edited_resource(ThemeDB::get_singleton()->get_default_theme()->get_stylebox(E.key, edited_type));2837} else {2838item_editor->set_edited_resource(Ref<Resource>());2839}2840item_editor->set_editable(false);2841}28422843item_control->add_child(item_editor);2844_add_focusable(item_editor);2845stylebox_items_list->add_child(item_control);2846}2847}28482849// Various type settings.2850if (edited_type.is_empty() || ClassDB::class_exists(edited_type)) {2851type_variation_edit->set_editable(false);2852type_variation_edit->set_text("");2853type_variation_button->hide();2854type_variation_locked->set_visible(!edited_type.is_empty());2855} else {2856type_variation_edit->set_editable(true);2857type_variation_edit->set_text(edited_theme->get_type_variation_base(edited_type));2858_add_focusable(type_variation_edit);2859type_variation_button->show();2860type_variation_locked->hide();2861}2862}28632864void ThemeTypeEditor::_list_type_selected(int p_index) {2865edited_type = theme_type_list->get_item_text(p_index);2866_update_type_items();2867}28682869void ThemeTypeEditor::_add_type_button_cbk() {2870add_type_mode = ADD_THEME_TYPE;2871add_type_dialog->set_title(TTR("Add Item Type"));2872add_type_dialog->set_ok_button_text(TTR("Add Type"));2873add_type_dialog->set_include_own_types(false);2874add_type_dialog->popup_centered(Size2(560, 420) * EDSCALE);2875}28762877void ThemeTypeEditor::_rename_type_button_cbk() {2878theme_type_rename_line_edit->set_text(edited_type);2879theme_type_rename_dialog->reset_size();2880theme_type_rename_dialog->popup_centered();2881theme_type_rename_line_edit->grab_focus();2882}28832884void ThemeTypeEditor::_theme_type_rename_dialog_confirmed() {2885const String &new_type_name = Theme::validate_type_name(theme_type_rename_line_edit->get_text());2886if (edited_type == new_type_name) {2887return;2888}28892890List<StringName> theme_types;2891edited_theme->get_type_list(&theme_types);2892if (theme_types.find(new_type_name) != nullptr) {2893return;2894}28952896EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();2897ur->create_action(TTR("Rename Theme Type"));28982899_rename_theme_type(ur, *edited_theme, edited_type, new_type_name);29002901ur->add_do_method(this, "select_type", new_type_name);2902ur->add_undo_method(this, "select_type", edited_type);29032904ur->commit_action();2905}29062907void ThemeTypeEditor::_remove_type_button_cbk() {2908Ref<Theme> old_snapshot = edited_theme->duplicate();29092910EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();2911ur->create_action(TTR("Remove Theme Type"));29122913ur->add_do_method(*edited_theme, "remove_type", edited_type);2914// If the type was empty, it cannot be restored with merge, but thankfully we can fake it.2915ur->add_undo_method(*edited_theme, "add_type", edited_type);2916ur->add_undo_method(*edited_theme, "merge_with", old_snapshot);29172918ur->commit_action();2919}29202921void ThemeTypeEditor::_add_default_type_items() {2922List<StringName> names;2923String default_type = edited_type;2924if (edited_theme->get_type_variation_base(edited_type) != StringName()) {2925default_type = edited_theme->get_type_variation_base(edited_type);2926}29272928Ref<Theme> old_snapshot = edited_theme->duplicate();2929Ref<Theme> new_snapshot = edited_theme->duplicate();29302931updating = true;29322933{2934names.clear();2935ThemeDB::get_singleton()->get_default_theme()->get_icon_list(default_type, &names);2936for (const StringName &E : names) {2937if (!new_snapshot->has_icon(E, edited_type)) {2938new_snapshot->set_icon(E, edited_type, ThemeDB::get_singleton()->get_default_theme()->get_icon(E, edited_type));2939}2940}2941}2942{2943names.clear();2944ThemeDB::get_singleton()->get_default_theme()->get_stylebox_list(default_type, &names);2945for (const StringName &E : names) {2946if (!new_snapshot->has_stylebox(E, edited_type)) {2947new_snapshot->set_stylebox(E, edited_type, ThemeDB::get_singleton()->get_default_theme()->get_stylebox(E, edited_type));2948}2949}2950}2951{2952names.clear();2953ThemeDB::get_singleton()->get_default_theme()->get_font_list(default_type, &names);2954for (const StringName &E : names) {2955if (!new_snapshot->has_font(E, edited_type)) {2956new_snapshot->set_font(E, edited_type, ThemeDB::get_singleton()->get_default_theme()->get_font(E, edited_type));2957}2958}2959}2960{2961names.clear();2962ThemeDB::get_singleton()->get_default_theme()->get_font_size_list(default_type, &names);2963for (const StringName &E : names) {2964if (!new_snapshot->has_font_size(E, edited_type)) {2965new_snapshot->set_font_size(E, edited_type, ThemeDB::get_singleton()->get_default_theme()->get_font_size(E, edited_type));2966}2967}2968}2969{2970names.clear();2971ThemeDB::get_singleton()->get_default_theme()->get_color_list(default_type, &names);2972for (const StringName &E : names) {2973if (!new_snapshot->has_color(E, edited_type)) {2974new_snapshot->set_color(E, edited_type, ThemeDB::get_singleton()->get_default_theme()->get_color(E, edited_type));2975}2976}2977}2978{2979names.clear();2980ThemeDB::get_singleton()->get_default_theme()->get_constant_list(default_type, &names);2981for (const StringName &E : names) {2982if (!new_snapshot->has_constant(E, edited_type)) {2983new_snapshot->set_constant(E, edited_type, ThemeDB::get_singleton()->get_default_theme()->get_constant(E, edited_type));2984}2985}2986}29872988updating = false;29892990EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();2991ur->create_action(TTR("Override All Default Theme Items"));29922993ur->add_do_method(*edited_theme, "merge_with", new_snapshot);2994ur->add_undo_method(*edited_theme, "clear");2995ur->add_undo_method(*edited_theme, "merge_with", old_snapshot);29962997ur->add_do_method(this, "_update_type_items");2998ur->add_undo_method(this, "_update_type_items");29993000ur->commit_action();3001}30023003void ThemeTypeEditor::_update_add_button(const String &p_text, LineEdit *p_for_edit) {3004Button *button = Object::cast_to<Button>(p_for_edit->get_meta("button"));3005button->set_disabled(p_text.strip_edges().is_empty());3006}30073008void ThemeTypeEditor::_item_add_cbk(int p_data_type, Control *p_control) {3009LineEdit *le = Object::cast_to<LineEdit>(p_control);3010if (le->get_text().strip_edges().is_empty()) {3011return;3012}30133014const String item_name = le->get_text().strip_edges().validate_ascii_identifier();30153016EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();3017ur->create_action(TTR("Add Theme Item"));30183019switch (p_data_type) {3020case Theme::DATA_TYPE_COLOR: {3021ur->add_do_method(*edited_theme, "set_color", item_name, edited_type, Color());3022ur->add_undo_method(*edited_theme, "clear_color", item_name, edited_type);3023} break;3024case Theme::DATA_TYPE_CONSTANT: {3025ur->add_do_method(*edited_theme, "set_constant", item_name, edited_type, 0);3026ur->add_undo_method(*edited_theme, "clear_constant", item_name, edited_type);3027} break;3028case Theme::DATA_TYPE_FONT: {3029ur->add_do_method(*edited_theme, "set_font", item_name, edited_type, Ref<Font>());3030ur->add_undo_method(*edited_theme, "clear_font", item_name, edited_type);3031} break;3032case Theme::DATA_TYPE_FONT_SIZE: {3033ur->add_do_method(*edited_theme, "set_font_size", item_name, edited_type, -1);3034ur->add_undo_method(*edited_theme, "clear_font_size", item_name, edited_type);3035} break;3036case Theme::DATA_TYPE_ICON: {3037ur->add_do_method(*edited_theme, "set_icon", item_name, edited_type, Ref<Texture2D>());3038ur->add_undo_method(*edited_theme, "clear_icon", item_name, edited_type);3039} break;3040case Theme::DATA_TYPE_STYLEBOX: {3041Ref<StyleBox> sb;3042ur->add_do_method(*edited_theme, "set_stylebox", item_name, edited_type, sb);3043ur->add_undo_method(*edited_theme, "clear_stylebox", item_name, edited_type);30443045if (is_stylebox_pinned(sb)) {3046ur->add_undo_method(this, "_unpin_leading_stylebox");3047}3048} break;3049}30503051ur->commit_action();30523053le->set_text("");3054_update_add_button("", le);3055}30563057void ThemeTypeEditor::_item_add_lineedit_cbk(String p_value, int p_data_type, Control *p_control) {3058_item_add_cbk(p_data_type, p_control);3059}30603061void ThemeTypeEditor::_item_override_cbk(int p_data_type, String p_item_name) {3062EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();3063ur->create_action(TTR("Override Theme Item"));30643065switch (p_data_type) {3066case Theme::DATA_TYPE_COLOR: {3067ur->add_do_method(*edited_theme, "set_color", p_item_name, edited_type, ThemeDB::get_singleton()->get_default_theme()->get_color(p_item_name, edited_type));3068ur->add_undo_method(*edited_theme, "clear_color", p_item_name, edited_type);3069} break;3070case Theme::DATA_TYPE_CONSTANT: {3071ur->add_do_method(*edited_theme, "set_constant", p_item_name, edited_type, ThemeDB::get_singleton()->get_default_theme()->get_constant(p_item_name, edited_type));3072ur->add_undo_method(*edited_theme, "clear_constant", p_item_name, edited_type);3073} break;3074case Theme::DATA_TYPE_FONT: {3075ur->add_do_method(*edited_theme, "set_font", p_item_name, edited_type, Ref<Font>());3076ur->add_undo_method(*edited_theme, "clear_font", p_item_name, edited_type);3077} break;3078case Theme::DATA_TYPE_FONT_SIZE: {3079ur->add_do_method(*edited_theme, "set_font_size", p_item_name, edited_type, ThemeDB::get_singleton()->get_default_theme()->get_font_size(p_item_name, edited_type));3080ur->add_undo_method(*edited_theme, "clear_font_size", p_item_name, edited_type);3081} break;3082case Theme::DATA_TYPE_ICON: {3083ur->add_do_method(*edited_theme, "set_icon", p_item_name, edited_type, Ref<Texture2D>());3084ur->add_undo_method(*edited_theme, "clear_icon", p_item_name, edited_type);3085} break;3086case Theme::DATA_TYPE_STYLEBOX: {3087Ref<StyleBox> sb;3088ur->add_do_method(*edited_theme, "set_stylebox", p_item_name, edited_type, sb);3089ur->add_undo_method(*edited_theme, "clear_stylebox", p_item_name, edited_type);30903091if (is_stylebox_pinned(sb)) {3092ur->add_undo_method(this, "_unpin_leading_stylebox");3093}3094} break;3095}30963097ur->commit_action();3098}30993100void ThemeTypeEditor::_item_remove_cbk(int p_data_type, String p_item_name) {3101EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();3102ur->create_action(TTR("Remove Theme Item"));31033104switch (p_data_type) {3105case Theme::DATA_TYPE_COLOR: {3106ur->add_do_method(*edited_theme, "clear_color", p_item_name, edited_type);3107ur->add_undo_method(*edited_theme, "set_color", p_item_name, edited_type, edited_theme->get_color(p_item_name, edited_type));3108} break;3109case Theme::DATA_TYPE_CONSTANT: {3110ur->add_do_method(*edited_theme, "clear_constant", p_item_name, edited_type);3111ur->add_undo_method(*edited_theme, "set_constant", p_item_name, edited_type, edited_theme->get_constant(p_item_name, edited_type));3112} break;3113case Theme::DATA_TYPE_FONT: {3114ur->add_do_method(*edited_theme, "clear_font", p_item_name, edited_type);3115if (edited_theme->has_font(p_item_name, edited_type)) {3116ur->add_undo_method(*edited_theme, "set_font", p_item_name, edited_type, edited_theme->get_font(p_item_name, edited_type));3117} else {3118ur->add_undo_method(*edited_theme, "set_font", p_item_name, edited_type, Ref<Font>());3119}3120} break;3121case Theme::DATA_TYPE_FONT_SIZE: {3122ur->add_do_method(*edited_theme, "clear_font_size", p_item_name, edited_type);3123ur->add_undo_method(*edited_theme, "set_font_size", p_item_name, edited_type, edited_theme->get_font_size(p_item_name, edited_type));3124} break;3125case Theme::DATA_TYPE_ICON: {3126ur->add_do_method(*edited_theme, "clear_icon", p_item_name, edited_type);3127if (edited_theme->has_icon(p_item_name, edited_type)) {3128ur->add_undo_method(*edited_theme, "set_icon", p_item_name, edited_type, edited_theme->get_icon(p_item_name, edited_type));3129} else {3130ur->add_undo_method(*edited_theme, "set_icon", p_item_name, edited_type, Ref<Texture2D>());3131}3132} break;3133case Theme::DATA_TYPE_STYLEBOX: {3134Ref<StyleBox> sb = edited_theme->get_stylebox(p_item_name, edited_type);3135ur->add_do_method(*edited_theme, "clear_stylebox", p_item_name, edited_type);3136if (edited_theme->has_stylebox(p_item_name, edited_type)) {3137ur->add_undo_method(*edited_theme, "set_stylebox", p_item_name, edited_type, sb);3138} else {3139ur->add_undo_method(*edited_theme, "set_stylebox", p_item_name, edited_type, Ref<StyleBox>());3140}31413142if (is_stylebox_pinned(sb)) {3143ur->add_do_method(this, "_unpin_leading_stylebox");3144ur->add_undo_method(this, "_pin_leading_stylebox", p_item_name, sb);3145}3146} break;3147}31483149ur->commit_action();3150}31513152void ThemeTypeEditor::_item_rename_cbk(int p_data_type, String p_item_name, Control *p_control) {3153// Label3154Object::cast_to<Label>(p_control->get_child(0))->hide();3155// Label buttons3156Object::cast_to<Button>(p_control->get_child(2))->hide();3157Object::cast_to<Button>(p_control->get_child(3))->hide();31583159// LineEdit3160Object::cast_to<LineEdit>(p_control->get_child(1))->set_text(p_item_name);3161Object::cast_to<LineEdit>(p_control->get_child(1))->show();3162// LineEdit buttons3163Object::cast_to<Button>(p_control->get_child(4))->show();3164Object::cast_to<Button>(p_control->get_child(5))->show();3165}31663167void ThemeTypeEditor::_item_rename_confirmed(int p_data_type, String p_item_name, Control *p_control) {3168LineEdit *le = Object::cast_to<LineEdit>(p_control->get_child(1));3169if (le->get_text().strip_edges().is_empty()) {3170return;3171}31723173const String new_name = le->get_text().strip_edges().validate_ascii_identifier();3174if (new_name == p_item_name) {3175_item_rename_canceled(p_data_type, p_item_name, p_control);3176return;3177}31783179EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();3180ur->create_action(TTR("Rename Theme Item"));31813182switch (p_data_type) {3183case Theme::DATA_TYPE_COLOR: {3184ur->add_do_method(*edited_theme, "rename_color", p_item_name, new_name, edited_type);3185ur->add_undo_method(*edited_theme, "rename_color", new_name, p_item_name, edited_type);3186} break;3187case Theme::DATA_TYPE_CONSTANT: {3188ur->add_do_method(*edited_theme, "rename_constant", p_item_name, new_name, edited_type);3189ur->add_undo_method(*edited_theme, "rename_constant", new_name, p_item_name, edited_type);3190} break;3191case Theme::DATA_TYPE_FONT: {3192ur->add_do_method(*edited_theme, "rename_font", p_item_name, new_name, edited_type);3193ur->add_undo_method(*edited_theme, "rename_font", new_name, p_item_name, edited_type);3194} break;3195case Theme::DATA_TYPE_FONT_SIZE: {3196ur->add_do_method(*edited_theme, "rename_font_size", p_item_name, new_name, edited_type);3197ur->add_undo_method(*edited_theme, "rename_font_size", new_name, p_item_name, edited_type);3198} break;3199case Theme::DATA_TYPE_ICON: {3200ur->add_do_method(*edited_theme, "rename_icon", p_item_name, new_name, edited_type);3201ur->add_undo_method(*edited_theme, "rename_icon", new_name, p_item_name, edited_type);3202} break;3203case Theme::DATA_TYPE_STYLEBOX: {3204ur->add_do_method(*edited_theme, "rename_stylebox", p_item_name, new_name, edited_type);3205ur->add_undo_method(*edited_theme, "rename_stylebox", new_name, p_item_name, edited_type);32063207if (leading_stylebox.pinned && leading_stylebox.item_name == p_item_name) {3208leading_stylebox.item_name = new_name;3209}3210} break;3211}32123213ur->commit_action();3214}32153216void ThemeTypeEditor::_item_rename_entered(String p_value, int p_data_type, String p_item_name, Control *p_control) {3217_item_rename_confirmed(p_data_type, p_item_name, p_control);3218}32193220void ThemeTypeEditor::_item_rename_canceled(int p_data_type, String p_item_name, Control *p_control) {3221// LineEdit3222Object::cast_to<LineEdit>(p_control->get_child(1))->hide();3223// LineEdit buttons3224Object::cast_to<Button>(p_control->get_child(4))->hide();3225Object::cast_to<Button>(p_control->get_child(5))->hide();32263227// Label3228Object::cast_to<Label>(p_control->get_child(0))->show();3229// Label buttons3230Object::cast_to<Button>(p_control->get_child(2))->show();3231Object::cast_to<Button>(p_control->get_child(3))->show();3232}32333234void ThemeTypeEditor::_color_item_changed(Color p_value, String p_item_name) {3235EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();3236ur->create_action(TTR("Set Color Item in Theme"), UndoRedo::MERGE_ENDS);3237ur->add_do_method(*edited_theme, "set_color", p_item_name, edited_type, p_value);3238ur->add_undo_method(*edited_theme, "set_color", p_item_name, edited_type, edited_theme->get_color(p_item_name, edited_type));3239ur->commit_action();3240}32413242void ThemeTypeEditor::_constant_item_changed(float p_value, String p_item_name) {3243EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();3244ur->create_action(TTR("Set Constant Item in Theme"));3245ur->add_do_method(*edited_theme, "set_constant", p_item_name, edited_type, p_value);3246ur->add_undo_method(*edited_theme, "set_constant", p_item_name, edited_type, edited_theme->get_constant(p_item_name, edited_type));3247ur->commit_action();3248}32493250void ThemeTypeEditor::_font_size_item_changed(float p_value, String p_item_name) {3251EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();3252ur->create_action(TTR("Set Font Size Item in Theme"));3253ur->add_do_method(*edited_theme, "set_font_size", p_item_name, edited_type, p_value);3254ur->add_undo_method(*edited_theme, "set_font_size", p_item_name, edited_type, edited_theme->get_font_size(p_item_name, edited_type));3255ur->commit_action();3256}32573258void ThemeTypeEditor::_edit_resource_item(Ref<Resource> p_resource, bool p_edit) {3259EditorNode::get_singleton()->edit_resource(p_resource);3260}32613262void ThemeTypeEditor::_font_item_changed(Ref<Font> p_value, String p_item_name) {3263EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();3264ur->create_action(TTR("Set Font Item in Theme"));32653266ur->add_do_method(*edited_theme, "set_font", p_item_name, edited_type, p_value.is_valid() ? p_value : Ref<Font>());3267if (edited_theme->has_font(p_item_name, edited_type)) {3268ur->add_undo_method(*edited_theme, "set_font", p_item_name, edited_type, edited_theme->get_font(p_item_name, edited_type));3269} else {3270ur->add_undo_method(*edited_theme, "set_font", p_item_name, edited_type, Ref<Font>());3271}32723273ur->add_do_method(this, CoreStringName(call_deferred), "_update_type_items");3274ur->add_undo_method(this, CoreStringName(call_deferred), "_update_type_items");32753276ur->commit_action();3277}32783279void ThemeTypeEditor::_icon_item_changed(Ref<Texture2D> p_value, String p_item_name) {3280EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();3281ur->create_action(TTR("Set Icon Item in Theme"));32823283ur->add_do_method(*edited_theme, "set_icon", p_item_name, edited_type, p_value.is_valid() ? p_value : Ref<Texture2D>());3284if (edited_theme->has_icon(p_item_name, edited_type)) {3285ur->add_undo_method(*edited_theme, "set_icon", p_item_name, edited_type, edited_theme->get_icon(p_item_name, edited_type));3286} else {3287ur->add_undo_method(*edited_theme, "set_icon", p_item_name, edited_type, Ref<Texture2D>());3288}32893290ur->add_do_method(this, CoreStringName(call_deferred), "_update_type_items");3291ur->add_undo_method(this, CoreStringName(call_deferred), "_update_type_items");32923293ur->commit_action();3294}32953296void ThemeTypeEditor::_stylebox_item_changed(Ref<StyleBox> p_value, String p_item_name) {3297EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();3298ur->create_action(TTR("Set Stylebox Item in Theme"));32993300ur->add_do_method(*edited_theme, "set_stylebox", p_item_name, edited_type, p_value.is_valid() ? p_value : Ref<StyleBox>());3301if (edited_theme->has_stylebox(p_item_name, edited_type)) {3302ur->add_undo_method(*edited_theme, "set_stylebox", p_item_name, edited_type, edited_theme->get_stylebox(p_item_name, edited_type));3303} else {3304ur->add_undo_method(*edited_theme, "set_stylebox", p_item_name, edited_type, Ref<StyleBox>());3305}33063307ur->add_do_method(this, "_change_pinned_stylebox");3308ur->add_undo_method(this, "_change_pinned_stylebox");33093310ur->add_do_method(this, CoreStringName(call_deferred), "_update_type_items");3311ur->add_undo_method(this, CoreStringName(call_deferred), "_update_type_items");33123313ur->commit_action();3314}33153316void ThemeTypeEditor::_change_pinned_stylebox() {3317if (leading_stylebox.pinned) {3318if (leading_stylebox.stylebox.is_valid()) {3319leading_stylebox.stylebox->disconnect_changed(callable_mp(this, &ThemeTypeEditor::_update_stylebox_from_leading));3320}33213322Ref<StyleBox> new_stylebox = edited_theme->get_stylebox(leading_stylebox.item_name, edited_type);3323leading_stylebox.stylebox = new_stylebox;3324leading_stylebox.ref_stylebox = (new_stylebox.is_valid() ? new_stylebox->duplicate() : Ref<Resource>());33253326if (leading_stylebox.stylebox.is_valid()) {3327new_stylebox->connect_changed(callable_mp(this, &ThemeTypeEditor::_update_stylebox_from_leading));3328}3329} else if (leading_stylebox.stylebox.is_valid()) {3330leading_stylebox.stylebox->disconnect_changed(callable_mp(this, &ThemeTypeEditor::_update_stylebox_from_leading));3331}3332}33333334void ThemeTypeEditor::_on_pin_leader_button_pressed(Control *p_editor, String p_item_name) {3335Ref<StyleBox> stylebox;3336if (Object::cast_to<EditorResourcePicker>(p_editor)) {3337stylebox = Object::cast_to<EditorResourcePicker>(p_editor)->get_edited_resource();3338}33393340EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();3341ur->create_action(TTR("Pin Stylebox"));3342ur->add_do_method(this, "_pin_leading_stylebox", p_item_name, stylebox);33433344if (leading_stylebox.pinned) {3345ur->add_undo_method(this, "_pin_leading_stylebox", leading_stylebox.item_name, leading_stylebox.stylebox);3346} else {3347ur->add_undo_method(this, "_unpin_leading_stylebox");3348}33493350ur->commit_action();3351}33523353void ThemeTypeEditor::_pin_leading_stylebox(String p_item_name, Ref<StyleBox> p_stylebox) {3354if (leading_stylebox.stylebox.is_valid()) {3355leading_stylebox.stylebox->disconnect_changed(callable_mp(this, &ThemeTypeEditor::_update_stylebox_from_leading));3356}33573358LeadingStylebox leader;3359leader.pinned = true;3360leader.item_name = p_item_name;3361leader.stylebox = p_stylebox;3362leader.ref_stylebox = (p_stylebox.is_valid() ? p_stylebox->duplicate() : Ref<Resource>());33633364leading_stylebox = leader;3365if (p_stylebox.is_valid()) {3366p_stylebox->connect_changed(callable_mp(this, &ThemeTypeEditor::_update_stylebox_from_leading));3367}33683369_update_type_items();3370}33713372void ThemeTypeEditor::_on_unpin_leader_button_pressed() {3373EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();3374ur->create_action(TTR("Unpin Stylebox"));3375ur->add_do_method(this, "_unpin_leading_stylebox");3376ur->add_undo_method(this, "_pin_leading_stylebox", leading_stylebox.item_name, leading_stylebox.stylebox);3377ur->commit_action();3378}33793380void ThemeTypeEditor::_unpin_leading_stylebox() {3381if (leading_stylebox.stylebox.is_valid()) {3382leading_stylebox.stylebox->disconnect_changed(callable_mp(this, &ThemeTypeEditor::_update_stylebox_from_leading));3383}33843385LeadingStylebox leader;3386leader.pinned = false;3387leading_stylebox = leader;33883389_update_type_items();3390}33913392void ThemeTypeEditor::_update_stylebox_from_leading() {3393if (!leading_stylebox.pinned || leading_stylebox.stylebox.is_null()) {3394return;3395}3396ERR_FAIL_COND_MSG(edited_theme.is_null(), "Leading stylebox does not have an edited theme to update");33973398// Prevent changes from immediately being reported while the operation is still ongoing.3399edited_theme->_freeze_change_propagation();34003401List<StringName> names;3402edited_theme->get_stylebox_list(edited_type, &names);3403List<Ref<StyleBox>> styleboxes;3404for (const StringName &E : names) {3405Ref<StyleBox> sb = edited_theme->get_stylebox(E, edited_type);34063407// Avoid itself, stylebox can be shared between items.3408if (sb == leading_stylebox.stylebox) {3409continue;3410}34113412if (sb->get_class() == leading_stylebox.stylebox->get_class()) {3413styleboxes.push_back(sb);3414}3415}34163417List<PropertyInfo> props;3418leading_stylebox.stylebox->get_property_list(&props);3419for (const PropertyInfo &E : props) {3420if (!(E.usage & PROPERTY_USAGE_STORAGE)) {3421continue;3422}34233424Variant value = leading_stylebox.stylebox->get(E.name);3425Variant ref_value = leading_stylebox.ref_stylebox->get(E.name);3426if (value == ref_value) {3427continue;3428}34293430for (const Ref<StyleBox> &F : styleboxes) {3431Ref<StyleBox> sb = F;3432sb->set(E.name, value);3433}3434}34353436leading_stylebox.ref_stylebox = leading_stylebox.stylebox->duplicate();34373438// Allow changes to be reported now that the operation is finished.3439edited_theme->_unfreeze_and_propagate_changes();3440}34413442void ThemeTypeEditor::_type_variation_changed(const String p_value) {3443EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();3444ur->create_action(TTR("Set Theme Type Variation"));34453446if (p_value.is_empty()) {3447ur->add_do_method(*edited_theme, "clear_type_variation", edited_type);3448} else {3449ur->add_do_method(*edited_theme, "set_type_variation", edited_type, StringName(p_value));3450}34513452if (edited_theme->get_type_variation_base(edited_type) == "") {3453ur->add_undo_method(*edited_theme, "clear_type_variation", edited_type);3454} else {3455ur->add_undo_method(*edited_theme, "set_type_variation", edited_type, edited_theme->get_type_variation_base(edited_type));3456}34573458ur->commit_action();3459}34603461void ThemeTypeEditor::_add_type_variation_cbk() {3462add_type_mode = ADD_VARIATION_BASE;3463add_type_dialog->set_title(TTR("Set Variation Base Type"));3464add_type_dialog->set_ok_button_text(TTR("Set Base Type"));3465add_type_dialog->set_include_own_types(true);3466add_type_dialog->popup_centered(Size2(560, 420) * EDSCALE);3467}34683469void ThemeTypeEditor::_add_type_dialog_selected(const String p_type_name) {3470if (add_type_mode == ADD_THEME_TYPE) {3471select_type(p_type_name);3472} else if (add_type_mode == ADD_VARIATION_BASE) {3473_type_variation_changed(p_type_name);3474}3475}34763477void ThemeTypeEditor::_notification(int p_what) {3478switch (p_what) {3479case NOTIFICATION_THEME_CHANGED: {3480add_type_button->set_button_icon(get_editor_theme_icon(SNAME("Add")));3481rename_type_button->set_button_icon(get_editor_theme_icon(SNAME("Rename")));3482remove_type_button->set_button_icon(get_editor_theme_icon(SNAME("Remove")));34833484data_type_tabs->set_tab_icon(0, get_editor_theme_icon(SNAME("Color")));3485data_type_tabs->set_tab_icon(1, get_editor_theme_icon(SNAME("MemberConstant")));3486data_type_tabs->set_tab_icon(2, get_editor_theme_icon(SNAME("FontItem")));3487data_type_tabs->set_tab_icon(3, get_editor_theme_icon(SNAME("FontSize")));3488data_type_tabs->set_tab_icon(4, get_editor_theme_icon(SNAME("ImageTexture")));3489data_type_tabs->set_tab_icon(5, get_editor_theme_icon(SNAME("StyleBoxFlat")));3490data_type_tabs->set_tab_icon(6, get_editor_theme_icon(SNAME("Tools")));34913492type_variation_button->set_button_icon(get_editor_theme_icon(SNAME("Add")));3493} break;3494}3495}34963497void ThemeTypeEditor::_bind_methods() {3498ClassDB::bind_method(D_METHOD("_update_type_items"), &ThemeTypeEditor::_update_type_items);3499ClassDB::bind_method(D_METHOD("_pin_leading_stylebox"), &ThemeTypeEditor::_pin_leading_stylebox);3500ClassDB::bind_method(D_METHOD("_unpin_leading_stylebox"), &ThemeTypeEditor::_unpin_leading_stylebox);3501ClassDB::bind_method(D_METHOD("_change_pinned_stylebox"), &ThemeTypeEditor::_change_pinned_stylebox);3502ClassDB::bind_method(D_METHOD("select_type", "type_name"), &ThemeTypeEditor::select_type);3503}35043505void ThemeTypeEditor::set_edited_theme(const Ref<Theme> &p_theme) {3506if (edited_theme.is_valid()) {3507edited_theme->disconnect_changed(callable_mp(this, &ThemeTypeEditor::_update_type_list_debounced));3508}35093510edited_theme = p_theme;3511if (edited_theme.is_valid()) {3512edited_theme->connect_changed(callable_mp(this, &ThemeTypeEditor::_update_type_list_debounced));3513_update_type_list();3514}35153516add_type_dialog->set_edited_theme(edited_theme);3517}35183519void ThemeTypeEditor::select_type(String p_type_name) {3520edited_type = p_type_name;3521bool type_exists = false;35223523for (int i = 0; i < theme_type_list->get_item_count(); i++) {3524String type_name = theme_type_list->get_item_text(i);3525if (type_name == edited_type) {3526theme_type_list->select(i);3527type_exists = true;3528break;3529}3530}35313532if (type_exists) {3533_update_type_items();3534} else {3535edited_theme->add_icon_type(edited_type);3536edited_theme->add_stylebox_type(edited_type);3537edited_theme->add_font_type(edited_type);3538edited_theme->add_font_size_type(edited_type);3539edited_theme->add_color_type(edited_type);3540edited_theme->add_constant_type(edited_type);35413542_update_type_list();3543}3544}35453546bool ThemeTypeEditor::is_stylebox_pinned(Ref<StyleBox> p_stylebox) {3547return leading_stylebox.pinned && leading_stylebox.stylebox == p_stylebox;3548}35493550ThemeTypeEditor::ThemeTypeEditor() {3551VBoxContainer *main_vb = memnew(VBoxContainer);3552add_child(main_vb);35533554HBoxContainer *type_list_hb = memnew(HBoxContainer);3555main_vb->add_child(type_list_hb);35563557Label *type_list_label = memnew(Label);3558type_list_label->set_text(TTR("Type:"));3559type_list_hb->add_child(type_list_label);35603561theme_type_list = memnew(OptionButton);3562theme_type_list->set_h_size_flags(SIZE_EXPAND_FILL);3563theme_type_list->set_text_overrun_behavior(TextServer::OVERRUN_TRIM_ELLIPSIS);3564theme_type_list->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED);3565theme_type_list->set_accessibility_name(TTRC("Type"));3566type_list_hb->add_child(theme_type_list);3567theme_type_list->connect(SceneStringName(item_selected), callable_mp(this, &ThemeTypeEditor::_list_type_selected));35683569add_type_button = memnew(Button);3570add_type_button->set_tooltip_text(TTR("Add a type from a list of available types or create a new one."));3571type_list_hb->add_child(add_type_button);3572add_type_button->connect(SceneStringName(pressed), callable_mp(this, &ThemeTypeEditor::_add_type_button_cbk));35733574rename_type_button = memnew(Button);3575rename_type_button->set_disabled(true);3576rename_type_button->set_tooltip_text(TTRC("Rename current type."));3577type_list_hb->add_child(rename_type_button);3578rename_type_button->connect(SceneStringName(pressed), callable_mp(this, &ThemeTypeEditor::_rename_type_button_cbk));35793580theme_type_rename_dialog = memnew(ConfirmationDialog);3581theme_type_rename_dialog->set_title(TTRC("Rename Theme Type"));3582theme_type_rename_dialog->set_min_size(Size2(256, 64) * EDSCALE);3583add_child(theme_type_rename_dialog);3584theme_type_rename_dialog->connect(SceneStringName(confirmed), callable_mp(this, &ThemeTypeEditor::_theme_type_rename_dialog_confirmed));35853586theme_type_rename_line_edit = memnew(LineEdit);3587theme_type_rename_line_edit->set_select_all_on_focus(true);3588theme_type_rename_dialog->add_child(theme_type_rename_line_edit);3589theme_type_rename_dialog->register_text_enter(theme_type_rename_line_edit);35903591remove_type_button = memnew(Button);3592remove_type_button->set_disabled(true);3593remove_type_button->set_tooltip_text(TTRC("Remove current type."));3594remove_type_button->set_accessibility_name(TTRC("Remove current type."));3595type_list_hb->add_child(remove_type_button);3596remove_type_button->connect(SceneStringName(pressed), callable_mp(this, &ThemeTypeEditor::_remove_type_button_cbk));35973598HBoxContainer *type_controls = memnew(HBoxContainer);3599main_vb->add_child(type_controls);36003601show_default_items_button = memnew(CheckButton);3602show_default_items_button->set_h_size_flags(SIZE_EXPAND_FILL);3603show_default_items_button->set_text(TTR("Show Default"));3604show_default_items_button->set_tooltip_text(TTR("Show default type items alongside items that have been overridden."));3605show_default_items_button->set_pressed(true);3606type_controls->add_child(show_default_items_button);3607show_default_items_button->connect(SceneStringName(pressed), callable_mp(this, &ThemeTypeEditor::_update_type_items));36083609Button *add_default_items_button = memnew(Button);3610add_default_items_button->set_h_size_flags(SIZE_EXPAND_FILL);3611add_default_items_button->set_text(TTR("Override All"));3612add_default_items_button->set_tooltip_text(TTR("Override all default type items."));3613type_controls->add_child(add_default_items_button);3614add_default_items_button->connect(SceneStringName(pressed), callable_mp(this, &ThemeTypeEditor::_add_default_type_items));36153616data_type_tabs = memnew(TabContainer);3617data_type_tabs->set_tab_alignment(TabBar::ALIGNMENT_CENTER);3618main_vb->add_child(data_type_tabs);3619data_type_tabs->set_v_size_flags(SIZE_EXPAND_FILL);3620data_type_tabs->set_use_hidden_tabs_for_min_size(true);3621data_type_tabs->set_theme_type_variation("TabContainerOdd");36223623color_items_list = _create_item_list(Theme::DATA_TYPE_COLOR);3624constant_items_list = _create_item_list(Theme::DATA_TYPE_CONSTANT);3625font_items_list = _create_item_list(Theme::DATA_TYPE_FONT);3626font_size_items_list = _create_item_list(Theme::DATA_TYPE_FONT_SIZE);3627icon_items_list = _create_item_list(Theme::DATA_TYPE_ICON);3628stylebox_items_list = _create_item_list(Theme::DATA_TYPE_STYLEBOX);36293630VBoxContainer *type_settings_tab = memnew(VBoxContainer);3631type_settings_tab->set_custom_minimum_size(Size2(0, 160) * EDSCALE);3632data_type_tabs->add_child(type_settings_tab);3633data_type_tabs->set_tab_title(data_type_tabs->get_tab_count() - 1, "");36343635ScrollContainer *type_settings_sc = memnew(ScrollContainer);3636type_settings_sc->set_v_size_flags(SIZE_EXPAND_FILL);3637type_settings_sc->set_horizontal_scroll_mode(ScrollContainer::SCROLL_MODE_DISABLED);3638type_settings_tab->add_child(type_settings_sc);3639VBoxContainer *type_settings_list = memnew(VBoxContainer);3640type_settings_list->set_h_size_flags(SIZE_EXPAND_FILL);3641type_settings_sc->add_child(type_settings_list);36423643VBoxContainer *type_variation_vb = memnew(VBoxContainer);3644type_settings_list->add_child(type_variation_vb);36453646HBoxContainer *type_variation_hb = memnew(HBoxContainer);3647type_variation_vb->add_child(type_variation_hb);3648Label *type_variation_label = memnew(Label);3649type_variation_hb->add_child(type_variation_label);3650type_variation_label->set_text(TTR("Base Type"));3651type_variation_label->set_h_size_flags(Control::SIZE_EXPAND_FILL);3652type_variation_edit = memnew(LineEdit);3653type_variation_hb->add_child(type_variation_edit);3654type_variation_edit->set_h_size_flags(Control::SIZE_EXPAND_FILL);3655type_variation_edit->connect(SceneStringName(text_changed), callable_mp(this, &ThemeTypeEditor::_type_variation_changed));3656type_variation_edit->connect(SceneStringName(focus_exited), callable_mp(this, &ThemeTypeEditor::_update_type_items));3657type_variation_edit->set_accessibility_name(TTRC("Base Type"));3658type_variation_button = memnew(Button);3659type_variation_hb->add_child(type_variation_button);3660type_variation_button->set_tooltip_text(TTR("Select the variation base type from a list of available types."));3661type_variation_button->connect(SceneStringName(pressed), callable_mp(this, &ThemeTypeEditor::_add_type_variation_cbk));36623663type_variation_locked = memnew(Label);3664type_variation_vb->add_child(type_variation_locked);3665type_variation_locked->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_CENTER);3666type_variation_locked->set_autowrap_mode(TextServer::AUTOWRAP_WORD);3667type_variation_locked->set_text(TTR("A type associated with a built-in class cannot be marked as a variation of another type."));3668type_variation_locked->hide();36693670add_type_dialog = memnew(ThemeTypeDialog);3671add_child(add_type_dialog);3672add_type_dialog->connect("type_selected", callable_mp(this, &ThemeTypeEditor::_add_type_dialog_selected));36733674update_debounce_timer = memnew(Timer);3675update_debounce_timer->set_one_shot(true);3676update_debounce_timer->set_wait_time(0.5);3677update_debounce_timer->connect("timeout", callable_mp(this, &ThemeTypeEditor::_update_type_list));3678add_child(update_debounce_timer);3679}36803681///////////////////////36823683void ThemeEditor::edit(const Ref<Theme> &p_theme) {3684if (theme == p_theme) {3685return;3686}36873688theme = p_theme;3689theme_type_editor->set_edited_theme(p_theme);3690theme_edit_dialog->set_edited_theme(p_theme);36913692for (int i = 0; i < preview_tabs_content->get_child_count(); i++) {3693ThemeEditorPreview *preview_tab = Object::cast_to<ThemeEditorPreview>(preview_tabs_content->get_child(i));3694if (!preview_tab) {3695continue;3696}36973698preview_tab->set_preview_theme(p_theme);3699}37003701if (theme.is_valid()) {3702_update_theme_name(theme->get_path().get_file());3703}3704}37053706Ref<Theme> ThemeEditor::get_edited_theme() {3707return theme;3708}37093710void ThemeEditor::_theme_save_button_cbk(bool p_save_as) {3711ERR_FAIL_COND_MSG(theme.is_null(), "Invalid state of the Theme Editor; the Theme resource is missing.");37123713if (p_save_as) {3714EditorNode::get_singleton()->save_resource_as(theme);3715} else {3716EditorNode::get_singleton()->save_resource(theme);3717}3718}37193720void ThemeEditor::_theme_edit_button_cbk() {3721theme_edit_dialog->popup_centered(Size2(850, 700) * EDSCALE);3722}37233724void ThemeEditor::_theme_close_button_cbk() {3725plugin->make_visible(false); // Enables auto hide.3726if (theme.is_valid() && InspectorDock::get_inspector_singleton()->get_edited_object() == theme.ptr()) {3727EditorNode::get_singleton()->push_item(nullptr);3728} else {3729theme = Ref<Theme>();3730EditorNode::get_singleton()->hide_unused_editors(plugin);3731}3732}37333734void ThemeEditor::_scene_closed(const String &p_path) {3735if (theme.is_valid() && theme->is_built_in() && theme->get_path().get_slice("::", 0) == p_path) {3736theme = Ref<Theme>();3737EditorNode::get_singleton()->hide_unused_editors(plugin);3738}3739}37403741void ThemeEditor::_resource_saved(const Ref<Resource> &p_resource) {3742if (theme.is_valid() && theme == p_resource) {3743_update_theme_name(theme->get_path().get_file());3744}3745}37463747void ThemeEditor::_files_moved(const String &p_old_path, const String &p_new_path) {3748// Theme's path may not have been updated to new path yet - need to check both old and new.3749if (theme.is_valid() && (theme->get_path() == p_old_path || theme->get_path() == p_new_path)) {3750_update_theme_name(p_new_path.get_file());3751}3752}37533754void ThemeEditor::_update_theme_name(const String &p_name) {3755theme_name->set_text(TTR("Theme:") + " " + p_name);3756}37573758void ThemeEditor::_add_preview_button_cbk() {3759preview_scene_dialog->popup_file_dialog();3760}37613762void ThemeEditor::_preview_scene_dialog_cbk(const String &p_path) {3763SceneThemeEditorPreview *preview_tab = memnew(SceneThemeEditorPreview);3764if (!preview_tab->set_preview_scene(p_path)) {3765memdelete(preview_tab);3766return;3767}37683769_add_preview_tab(preview_tab, p_path.get_file(), get_editor_theme_icon(SNAME("PackedScene")));3770preview_tab->connect("scene_invalidated", callable_mp(this, &ThemeEditor::_remove_preview_tab_invalid).bind(preview_tab));3771preview_tab->connect("scene_reloaded", callable_mp(this, &ThemeEditor::_update_preview_tab).bind(preview_tab));3772}37733774void ThemeEditor::_add_preview_tab(ThemeEditorPreview *p_preview_tab, const String &p_preview_name, const Ref<Texture2D> &p_icon) {3775p_preview_tab->set_preview_theme(theme);37763777preview_tabs->add_tab(p_preview_name, p_icon);3778preview_tabs_content->add_child(p_preview_tab);3779preview_tabs->set_tab_button_icon(preview_tabs->get_tab_count() - 1, EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("close"), SNAME("TabBar")));3780p_preview_tab->connect("control_picked", callable_mp(this, &ThemeEditor::_preview_control_picked));37813782preview_tabs->set_current_tab(preview_tabs->get_tab_count() - 1);3783}37843785void ThemeEditor::_change_preview_tab(int p_tab) {3786ERR_FAIL_INDEX_MSG(p_tab, preview_tabs_content->get_child_count(), "Attempting to open a preview tab that doesn't exist.");37873788for (int i = 0; i < preview_tabs_content->get_child_count(); i++) {3789Control *c = Object::cast_to<Control>(preview_tabs_content->get_child(i));3790if (!c) {3791continue;3792}37933794c->set_visible(i == p_tab);3795}3796}37973798void ThemeEditor::_remove_preview_tab(int p_tab) {3799ERR_FAIL_INDEX_MSG(p_tab, preview_tabs_content->get_child_count(), "Attempting to remove a preview tab that doesn't exist.");38003801ThemeEditorPreview *preview_tab = Object::cast_to<ThemeEditorPreview>(preview_tabs_content->get_child(p_tab));3802ERR_FAIL_COND_MSG(Object::cast_to<DefaultThemeEditorPreview>(preview_tab), "Attemptying to remove the default preview tab.");38033804if (preview_tab) {3805preview_tab->disconnect("control_picked", callable_mp(this, &ThemeEditor::_preview_control_picked));3806if (preview_tab->is_connected("scene_invalidated", callable_mp(this, &ThemeEditor::_remove_preview_tab_invalid))) {3807preview_tab->disconnect("scene_invalidated", callable_mp(this, &ThemeEditor::_remove_preview_tab_invalid));3808}3809if (preview_tab->is_connected("scene_reloaded", callable_mp(this, &ThemeEditor::_update_preview_tab))) {3810preview_tab->disconnect("scene_reloaded", callable_mp(this, &ThemeEditor::_update_preview_tab));3811}38123813preview_tabs_content->remove_child(preview_tab);3814preview_tab->queue_free();38153816preview_tabs->remove_tab(p_tab);3817_change_preview_tab(preview_tabs->get_current_tab());3818}3819}38203821void ThemeEditor::_remove_preview_tab_invalid(Node *p_tab_control) {3822int tab_index = p_tab_control->get_index();3823_remove_preview_tab(tab_index);3824}38253826void ThemeEditor::_update_preview_tab(Node *p_tab_control) {3827if (!Object::cast_to<SceneThemeEditorPreview>(p_tab_control)) {3828return;3829}38303831int tab_index = p_tab_control->get_index();3832SceneThemeEditorPreview *scene_preview = Object::cast_to<SceneThemeEditorPreview>(p_tab_control);3833preview_tabs->set_tab_title(tab_index, scene_preview->get_preview_scene_path().get_file());3834}38353836void ThemeEditor::_preview_control_picked(String p_class_name) {3837theme_type_editor->select_type(p_class_name);3838}38393840bool ThemeEditor::can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) {3841const Dictionary d = p_data;3842if (!d.has("type")) {3843return false;3844}38453846if (String(d["type"]) == "files") {3847const Vector<String> files = d["files"];38483849if (files.size() != 1) {3850return false;3851}38523853const String ftype = EditorFileSystem::get_singleton()->get_file_type(files[0]);3854return ftype == "PackedScene";3855}3856return false;3857}38583859void ThemeEditor::drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) {3860Dictionary d = p_data;3861Vector<String> files = d["files"];3862const String &path = files[0];38633864SceneThemeEditorPreview *preview_tab = memnew(SceneThemeEditorPreview);3865if (!preview_tab->set_preview_scene(path)) {3866memdelete(preview_tab);3867return;3868}38693870Ref<Texture2D> icon = get_editor_theme_icon(SNAME("PackedScene"));38713872preview_tab->set_preview_theme(theme);38733874preview_tabs->add_tab(path.get_file(), icon);3875preview_tabs_content->add_child(preview_tab);3876preview_tabs->set_tab_button_icon(preview_tabs->get_tab_count() - 1, EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("close"), SNAME("TabBar")));3877preview_tab->connect("control_picked", callable_mp(this, &ThemeEditor::_preview_control_picked));38783879preview_tabs->set_current_tab(preview_tabs->get_tab_count() - 1);3880preview_tab->connect("scene_invalidated", callable_mp(this, &ThemeEditor::_remove_preview_tab_invalid).bind(preview_tab));3881preview_tab->connect("scene_reloaded", callable_mp(this, &ThemeEditor::_update_preview_tab).bind(preview_tab));3882}38833884void ThemeEditor::_notification(int p_what) {3885switch (p_what) {3886case NOTIFICATION_READY: {3887EditorNode::get_singleton()->connect("scene_closed", callable_mp(this, &ThemeEditor::_scene_closed));3888EditorNode::get_singleton()->connect("resource_saved", callable_mp(this, &ThemeEditor::_resource_saved));3889FileSystemDock::get_singleton()->connect("files_moved", callable_mp(this, &ThemeEditor::_files_moved));3890} break;38913892case NOTIFICATION_THEME_CHANGED: {3893preview_tabs->add_theme_style_override("tab_selected", get_theme_stylebox(SNAME("ThemeEditorPreviewFG"), EditorStringName(EditorStyles)));3894preview_tabs->add_theme_style_override("tab_unselected", get_theme_stylebox(SNAME("ThemeEditorPreviewBG"), EditorStringName(EditorStyles)));3895preview_tabs_content->add_theme_style_override(SceneStringName(panel), get_theme_stylebox(SceneStringName(panel), SNAME("TabContainerOdd")));38963897add_preview_button->set_button_icon(get_editor_theme_icon(SNAME("Add")));3898} break;3899}3900}39013902ThemeEditor::ThemeEditor() {3903HBoxContainer *top_menu = memnew(HBoxContainer);3904add_child(top_menu);39053906theme_name = memnew(Label);3907theme_name->set_text(TTR("Theme:"));3908theme_name->set_theme_type_variation("HeaderSmall");3909top_menu->add_child(theme_name);39103911top_menu->add_spacer(false);39123913Button *theme_save_button = memnew(Button);3914theme_save_button->set_text(TTR("Save"));3915theme_save_button->set_flat(true);3916theme_save_button->connect(SceneStringName(pressed), callable_mp(this, &ThemeEditor::_theme_save_button_cbk).bind(false));3917top_menu->add_child(theme_save_button);39183919Button *theme_save_as_button = memnew(Button);3920theme_save_as_button->set_text(TTR("Save As..."));3921theme_save_as_button->set_flat(true);3922theme_save_as_button->connect(SceneStringName(pressed), callable_mp(this, &ThemeEditor::_theme_save_button_cbk).bind(true));3923top_menu->add_child(theme_save_as_button);39243925Button *theme_close_button = memnew(Button);3926theme_close_button->set_text(TTR("Close"));3927theme_close_button->set_flat(true);3928theme_close_button->connect(SceneStringName(pressed), callable_mp(this, &ThemeEditor::_theme_close_button_cbk));3929top_menu->add_child(theme_close_button);39303931top_menu->add_child(memnew(VSeparator));39323933Button *theme_edit_button = memnew(Button);3934theme_edit_button->set_text(TTR("Manage Items..."));3935theme_edit_button->set_tooltip_text(TTR("Add, remove, organize and import Theme items."));3936theme_edit_button->set_flat(true);3937theme_edit_button->connect(SceneStringName(pressed), callable_mp(this, &ThemeEditor::_theme_edit_button_cbk));3938top_menu->add_child(theme_edit_button);39393940theme_type_editor = memnew(ThemeTypeEditor);39413942theme_edit_dialog = memnew(ThemeItemEditorDialog(theme_type_editor));3943theme_edit_dialog->hide();3944top_menu->add_child(theme_edit_dialog);39453946HSplitContainer *main_hs = memnew(HSplitContainer);3947main_hs->set_v_size_flags(SIZE_EXPAND_FILL);3948add_child(main_hs);39493950main_hs->set_split_offset(520 * EDSCALE);39513952VBoxContainer *preview_tabs_vb = memnew(VBoxContainer);3953preview_tabs_vb->set_h_size_flags(SIZE_EXPAND_FILL);3954preview_tabs_vb->add_theme_constant_override("separation", 2 * EDSCALE);3955main_hs->add_child(preview_tabs_vb);3956HBoxContainer *preview_tabbar_hb = memnew(HBoxContainer);3957preview_tabs_vb->add_child(preview_tabbar_hb);3958preview_tabs_content = memnew(PanelContainer);3959preview_tabs_content->set_v_size_flags(SIZE_EXPAND_FILL);3960preview_tabs_content->set_draw_behind_parent(true);3961preview_tabs_vb->add_child(preview_tabs_content);39623963preview_tabs = memnew(TabBar);3964preview_tabs->set_h_size_flags(SIZE_EXPAND_FILL);3965preview_tabbar_hb->add_child(preview_tabs);3966preview_tabs->connect("tab_changed", callable_mp(this, &ThemeEditor::_change_preview_tab));3967preview_tabs->connect("tab_button_pressed", callable_mp(this, &ThemeEditor::_remove_preview_tab));39683969HBoxContainer *add_preview_button_hb = memnew(HBoxContainer);3970preview_tabbar_hb->add_child(add_preview_button_hb);3971add_preview_button = memnew(Button);3972add_preview_button->set_text(TTR("Add Preview"));3973add_preview_button_hb->add_child(add_preview_button);3974add_preview_button->connect(SceneStringName(pressed), callable_mp(this, &ThemeEditor::_add_preview_button_cbk));39753976DefaultThemeEditorPreview *default_preview_tab = memnew(DefaultThemeEditorPreview);3977preview_tabs_content->add_child(default_preview_tab);3978default_preview_tab->connect("control_picked", callable_mp(this, &ThemeEditor::_preview_control_picked));3979preview_tabs->add_tab(TTR("Default Preview"));39803981preview_scene_dialog = memnew(EditorFileDialog);3982preview_scene_dialog->set_file_mode(EditorFileDialog::FILE_MODE_OPEN_FILE);3983preview_scene_dialog->set_title(TTR("Select UI Scene:"));3984List<String> ext;3985ResourceLoader::get_recognized_extensions_for_type("PackedScene", &ext);3986for (const String &E : ext) {3987preview_scene_dialog->add_filter("*." + E, TTR("Scene"));3988}3989main_hs->add_child(preview_scene_dialog);3990preview_scene_dialog->connect("file_selected", callable_mp(this, &ThemeEditor::_preview_scene_dialog_cbk));39913992main_hs->add_child(theme_type_editor);3993theme_type_editor->set_custom_minimum_size(Size2(280, 0) * EDSCALE);39943995SET_DRAG_FORWARDING_CD(top_menu, ThemeEditor);3996SET_DRAG_FORWARDING_CD(preview_tabs, ThemeEditor);3997}39983999///////////////////////40004001void ThemeEditorPlugin::edit(Object *p_object) {4002theme_editor->edit(Ref<Theme>(p_object));4003}40044005bool ThemeEditorPlugin::handles(Object *p_object) const {4006return Object::cast_to<Theme>(p_object) != nullptr;4007}40084009void ThemeEditorPlugin::make_visible(bool p_visible) {4010if (p_visible) {4011button->show();4012EditorNode::get_bottom_panel()->make_item_visible(theme_editor);4013} else {4014if (theme_editor->is_visible_in_tree()) {4015EditorNode::get_bottom_panel()->hide_bottom_panel();4016}40174018button->hide();4019}4020}40214022bool ThemeEditorPlugin::can_auto_hide() const {4023return theme_editor->theme.is_null();4024}40254026ThemeEditorPlugin::ThemeEditorPlugin() {4027theme_editor = memnew(ThemeEditor);4028theme_editor->plugin = this;4029theme_editor->set_custom_minimum_size(Size2(0, 200) * EDSCALE);40304031button = EditorNode::get_bottom_panel()->add_item(TTRC("Theme"), theme_editor, ED_SHORTCUT_AND_COMMAND("bottom_panels/toggle_theme_bottom_panel", TTRC("Toggle Theme Bottom Panel")));4032button->hide();4033}403440354036