Path: blob/master/editor/scene/gui/theme_editor_plugin.cpp
20804 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/editor_dock_manager.h"34#include "editor/docks/filesystem_dock.h"35#include "editor/docks/inspector_dock.h"36#include "editor/editor_node.h"37#include "editor/editor_string_names.h"38#include "editor/editor_undo_redo_manager.h"39#include "editor/file_system/editor_file_system.h"40#include "editor/gui/editor_bottom_panel.h"41#include "editor/gui/editor_file_dialog.h"42#include "editor/gui/editor_spin_slider.h"43#include "editor/gui/filter_line_edit.h"44#include "editor/gui/progress_dialog.h"45#include "editor/inspector/editor_resource_picker.h"46#include "editor/settings/editor_command_palette.h"47#include "editor/settings/editor_settings.h"48#include "editor/themes/editor_scale.h"49#include "scene/gui/check_button.h"50#include "scene/gui/color_picker.h"51#include "scene/gui/item_list.h"52#include "scene/gui/option_button.h"53#include "scene/gui/panel_container.h"54#include "scene/gui/scroll_container.h"55#include "scene/gui/separator.h"56#include "scene/gui/split_container.h"57#include "scene/gui/tab_bar.h"58#include "scene/gui/tab_container.h"59#include "scene/gui/texture_rect.h"60#include "scene/theme/theme_db.h"6162static void _rename_theme_type(EditorUndoRedoManager *p_ur, Theme *p_theme, const String &p_old_theme_type, const String &p_new_theme_type) {63p_ur->add_do_method(p_theme, "rename_type", p_old_theme_type, p_new_theme_type);64p_ur->add_undo_method(p_theme, "rename_type", p_new_theme_type, p_old_theme_type);6566// Renaming a theme type to an empty name or a variation to a type associated with a built-in class67// removes type variation connections in a way that cannot be undone by reversing the rename alone.68const StringName old_base_type = p_theme->get_type_variation_base(p_old_theme_type);69if ((!p_old_theme_type.is_empty() && p_new_theme_type.is_empty()) || (old_base_type != StringName() && ClassDB::class_exists(p_new_theme_type))) {70if (old_base_type != StringName()) {71p_ur->add_undo_method(p_theme, "set_type_variation", p_old_theme_type, old_base_type);72}7374List<StringName> names;75p_theme->get_type_variation_list(p_old_theme_type, &names);76for (const StringName &E : names) {77p_ur->add_undo_method(p_theme, "set_type_variation", E, p_old_theme_type);78}79}80}8182///////////////////////8384void ThemeItemImportTree::_update_items_tree() {85import_items_tree->clear();86TreeItem *root = import_items_tree->create_item();8788if (base_theme.is_null()) {89return;90}9192String filter_text = import_items_filter->get_text();9394List<StringName> types;95List<StringName> names;96List<StringName> filtered_names;97base_theme->get_type_list(&types);98types.sort_custom<StringName::AlphCompare>();99100int color_amount = 0;101int constant_amount = 0;102int font_amount = 0;103int font_size_amount = 0;104int icon_amount = 0;105int stylebox_amount = 0;106107tree_color_items.clear();108tree_constant_items.clear();109tree_font_items.clear();110tree_font_size_items.clear();111tree_icon_items.clear();112tree_stylebox_items.clear();113114for (const StringName &E : types) {115String type_name = (String)E;116117Ref<Texture2D> type_icon;118if (E == "") {119type_icon = get_editor_theme_icon(SNAME("NodeDisabled"));120} else {121type_icon = EditorNode::get_singleton()->get_class_icon(E, "NodeDisabled");122}123124TreeItem *type_node = import_items_tree->create_item(root);125type_node->set_meta("_can_be_imported", false);126type_node->set_collapsed(true);127type_node->set_icon(0, type_icon);128type_node->set_text(0, type_name);129type_node->set_cell_mode(IMPORT_ITEM, TreeItem::CELL_MODE_CHECK);130type_node->set_checked(IMPORT_ITEM, false);131type_node->set_editable(IMPORT_ITEM, true);132type_node->set_cell_mode(IMPORT_ITEM_DATA, TreeItem::CELL_MODE_CHECK);133type_node->set_checked(IMPORT_ITEM_DATA, false);134type_node->set_editable(IMPORT_ITEM_DATA, true);135136bool is_matching_filter = (filter_text.is_empty() || type_name.containsn(filter_text));137bool has_filtered_items = false;138139for (int i = 0; i < Theme::DATA_TYPE_MAX; i++) {140Theme::DataType dt = (Theme::DataType)i;141142names.clear();143filtered_names.clear();144base_theme->get_theme_item_list(dt, E, &names);145146bool data_type_has_filtered_items = false;147148for (const StringName &F : names) {149String item_name = (String)F;150bool is_item_matching_filter = item_name.containsn(filter_text);151if (!filter_text.is_empty() && !is_matching_filter && !is_item_matching_filter) {152continue;153}154155// Only mark this if actual items match the filter and not just the type group.156if (!filter_text.is_empty() && is_item_matching_filter) {157has_filtered_items = true;158data_type_has_filtered_items = true;159}160filtered_names.push_back(F);161}162163if (filtered_names.is_empty()) {164continue;165}166167TreeItem *data_type_node = import_items_tree->create_item(type_node);168data_type_node->set_meta("_can_be_imported", false);169data_type_node->set_metadata(0, i);170data_type_node->set_collapsed(!data_type_has_filtered_items);171data_type_node->set_cell_mode(IMPORT_ITEM, TreeItem::CELL_MODE_CHECK);172data_type_node->set_checked(IMPORT_ITEM, false);173data_type_node->set_editable(IMPORT_ITEM, true);174data_type_node->set_cell_mode(IMPORT_ITEM_DATA, TreeItem::CELL_MODE_CHECK);175data_type_node->set_checked(IMPORT_ITEM_DATA, false);176data_type_node->set_editable(IMPORT_ITEM_DATA, true);177178List<TreeItem *> *item_list = nullptr;179180switch (dt) {181case Theme::DATA_TYPE_COLOR:182data_type_node->set_icon(0, get_editor_theme_icon(SNAME("Color")));183data_type_node->set_text(0, TTR("Colors"));184185item_list = &tree_color_items;186color_amount += filtered_names.size();187break;188189case Theme::DATA_TYPE_CONSTANT:190data_type_node->set_icon(0, get_editor_theme_icon(SNAME("MemberConstant")));191data_type_node->set_text(0, TTR("Constants"));192193item_list = &tree_constant_items;194constant_amount += filtered_names.size();195break;196197case Theme::DATA_TYPE_FONT:198data_type_node->set_icon(0, get_editor_theme_icon(SNAME("FontItem")));199data_type_node->set_text(0, TTR("Fonts"));200201item_list = &tree_font_items;202font_amount += filtered_names.size();203break;204205case Theme::DATA_TYPE_FONT_SIZE:206data_type_node->set_icon(0, get_editor_theme_icon(SNAME("FontSize")));207data_type_node->set_text(0, TTR("Font Sizes"));208209item_list = &tree_font_size_items;210font_size_amount += filtered_names.size();211break;212213case Theme::DATA_TYPE_ICON:214data_type_node->set_icon(0, get_editor_theme_icon(SNAME("ImageTexture")));215data_type_node->set_text(0, TTR("Icons"));216217item_list = &tree_icon_items;218icon_amount += filtered_names.size();219break;220221case Theme::DATA_TYPE_STYLEBOX:222data_type_node->set_icon(0, get_editor_theme_icon(SNAME("StyleBoxFlat")));223data_type_node->set_text(0, TTR("Styleboxes"));224225item_list = &tree_stylebox_items;226stylebox_amount += filtered_names.size();227break;228229case Theme::DATA_TYPE_MAX:230break; // Can't happen, but silences warning.231}232233filtered_names.sort_custom<StringName::AlphCompare>();234for (const StringName &F : filtered_names) {235TreeItem *item_node = import_items_tree->create_item(data_type_node);236item_node->set_meta("_can_be_imported", true);237item_node->set_text(0, F);238item_node->set_cell_mode(IMPORT_ITEM, TreeItem::CELL_MODE_CHECK);239item_node->set_checked(IMPORT_ITEM, false);240item_node->set_editable(IMPORT_ITEM, true);241item_node->set_cell_mode(IMPORT_ITEM_DATA, TreeItem::CELL_MODE_CHECK);242item_node->set_checked(IMPORT_ITEM_DATA, false);243item_node->set_editable(IMPORT_ITEM_DATA, true);244245_restore_selected_item(item_node);246item_node->propagate_check(IMPORT_ITEM, false);247item_node->propagate_check(IMPORT_ITEM_DATA, false);248249item_list->push_back(item_node);250}251}252253// Remove the item if it doesn't match the filter in any way.254if (!is_matching_filter && !has_filtered_items) {255root->remove_child(type_node);256memdelete(type_node);257continue;258}259260// Show one level inside of a type group if there are matches in items.261if (!filter_text.is_empty() && has_filtered_items) {262type_node->set_collapsed(false);263}264}265266if (color_amount > 0) {267Array arr = { color_amount };268select_colors_label->set_text(TTRN("1 color", "{num} colors", color_amount).format(arr, "{num}"));269select_all_colors_button->set_visible(true);270select_full_colors_button->set_visible(true);271deselect_all_colors_button->set_visible(true);272} else {273select_colors_label->set_text(TTR("No colors found."));274select_all_colors_button->set_visible(false);275select_full_colors_button->set_visible(false);276deselect_all_colors_button->set_visible(false);277}278279if (constant_amount > 0) {280Array arr = { constant_amount };281select_constants_label->set_text(TTRN("1 constant", "{num} constants", constant_amount).format(arr, "{num}"));282select_all_constants_button->set_visible(true);283select_full_constants_button->set_visible(true);284deselect_all_constants_button->set_visible(true);285} else {286select_constants_label->set_text(TTR("No constants found."));287select_all_constants_button->set_visible(false);288select_full_constants_button->set_visible(false);289deselect_all_constants_button->set_visible(false);290}291292if (font_amount > 0) {293Array arr = { font_amount };294select_fonts_label->set_text(TTRN("1 font", "{num} fonts", font_amount).format(arr, "{num}"));295select_all_fonts_button->set_visible(true);296select_full_fonts_button->set_visible(true);297deselect_all_fonts_button->set_visible(true);298} else {299select_fonts_label->set_text(TTR("No fonts found."));300select_all_fonts_button->set_visible(false);301select_full_fonts_button->set_visible(false);302deselect_all_fonts_button->set_visible(false);303}304305if (font_size_amount > 0) {306Array arr = { font_size_amount };307select_font_sizes_label->set_text(TTRN("1 font size", "{num} font sizes", font_size_amount).format(arr, "{num}"));308select_all_font_sizes_button->set_visible(true);309select_full_font_sizes_button->set_visible(true);310deselect_all_font_sizes_button->set_visible(true);311} else {312select_font_sizes_label->set_text(TTR("No font sizes found."));313select_all_font_sizes_button->set_visible(false);314select_full_font_sizes_button->set_visible(false);315deselect_all_font_sizes_button->set_visible(false);316}317318if (icon_amount > 0) {319Array arr = { icon_amount };320select_icons_label->set_text(TTRN("1 icon", "{num} icons", icon_amount).format(arr, "{num}"));321select_all_icons_button->set_visible(true);322select_full_icons_button->set_visible(true);323deselect_all_icons_button->set_visible(true);324select_icons_warning_hb->set_visible(true);325} else {326select_icons_label->set_text(TTR("No icons found."));327select_all_icons_button->set_visible(false);328select_full_icons_button->set_visible(false);329deselect_all_icons_button->set_visible(false);330select_icons_warning_hb->set_visible(false);331}332333if (stylebox_amount > 0) {334Array arr = { stylebox_amount };335select_styleboxes_label->set_text(TTRN("1 stylebox", "{num} styleboxes", stylebox_amount).format(arr, "{num}"));336select_all_styleboxes_button->set_visible(true);337select_full_styleboxes_button->set_visible(true);338deselect_all_styleboxes_button->set_visible(true);339} else {340select_styleboxes_label->set_text(TTR("No styleboxes found."));341select_all_styleboxes_button->set_visible(false);342select_full_styleboxes_button->set_visible(false);343deselect_all_styleboxes_button->set_visible(false);344}345}346347void ThemeItemImportTree::_toggle_type_items(bool p_collapse) {348TreeItem *root = import_items_tree->get_root();349if (!root) {350return;351}352353TreeItem *type_node = root->get_first_child();354while (type_node) {355type_node->set_collapsed(p_collapse);356type_node = type_node->get_next();357}358}359360void ThemeItemImportTree::_filter_text_changed(const String &p_value) {361_update_items_tree();362}363364void ThemeItemImportTree::_store_selected_item(TreeItem *p_tree_item) {365if (!p_tree_item->get_meta("_can_be_imported")) {366return;367}368369TreeItem *data_type_node = p_tree_item->get_parent();370if (!data_type_node || data_type_node == import_items_tree->get_root()) {371return;372}373374TreeItem *type_node = data_type_node->get_parent();375if (!type_node || type_node == import_items_tree->get_root()) {376return;377}378379ThemeItem ti;380ti.item_name = p_tree_item->get_text(0);381ti.data_type = (Theme::DataType)(int)data_type_node->get_metadata(0);382ti.type_name = type_node->get_text(0);383384bool import = p_tree_item->is_checked(IMPORT_ITEM);385bool with_data = p_tree_item->is_checked(IMPORT_ITEM_DATA);386387if (import && with_data) {388selected_items[ti] = SELECT_IMPORT_FULL;389} else if (import) {390selected_items[ti] = SELECT_IMPORT_DEFINITION;391} else {392selected_items.erase(ti);393}394395_update_total_selected(ti.data_type);396}397398void ThemeItemImportTree::_restore_selected_item(TreeItem *p_tree_item) {399if (!p_tree_item->get_meta("_can_be_imported")) {400return;401}402403TreeItem *data_type_node = p_tree_item->get_parent();404if (!data_type_node || data_type_node == import_items_tree->get_root()) {405return;406}407408TreeItem *type_node = data_type_node->get_parent();409if (!type_node || type_node == import_items_tree->get_root()) {410return;411}412413ThemeItem ti;414ti.item_name = p_tree_item->get_text(0);415ti.data_type = (Theme::DataType)(int)data_type_node->get_metadata(0);416ti.type_name = type_node->get_text(0);417418if (!selected_items.has(ti)) {419p_tree_item->set_checked(IMPORT_ITEM, false);420p_tree_item->set_checked(IMPORT_ITEM_DATA, false);421return;422}423424if (selected_items[ti] == SELECT_IMPORT_FULL) {425p_tree_item->set_checked(IMPORT_ITEM, true);426p_tree_item->set_checked(IMPORT_ITEM_DATA, true);427} else if (selected_items[ti] == SELECT_IMPORT_DEFINITION) {428p_tree_item->set_checked(IMPORT_ITEM, true);429p_tree_item->set_checked(IMPORT_ITEM_DATA, false);430}431}432433void ThemeItemImportTree::_update_total_selected(Theme::DataType p_data_type) {434ERR_FAIL_INDEX_MSG(p_data_type, Theme::DATA_TYPE_MAX, "Theme item data type is out of bounds.");435436Label *total_selected_items_label = nullptr;437switch (p_data_type) {438case Theme::DATA_TYPE_COLOR:439total_selected_items_label = total_selected_colors_label;440break;441442case Theme::DATA_TYPE_CONSTANT:443total_selected_items_label = total_selected_constants_label;444break;445446case Theme::DATA_TYPE_FONT:447total_selected_items_label = total_selected_fonts_label;448break;449450case Theme::DATA_TYPE_FONT_SIZE:451total_selected_items_label = total_selected_font_sizes_label;452break;453454case Theme::DATA_TYPE_ICON:455total_selected_items_label = total_selected_icons_label;456break;457458case Theme::DATA_TYPE_STYLEBOX:459total_selected_items_label = total_selected_styleboxes_label;460break;461462case Theme::DATA_TYPE_MAX:463return; // Can't happen, but silences warning.464}465466if (!total_selected_items_label) {467return;468}469470int count = 0;471for (const KeyValue<ThemeItem, ItemCheckedState> &E : selected_items) {472ThemeItem ti = E.key;473if (ti.data_type == p_data_type) {474count++;475}476}477478if (count == 0) {479total_selected_items_label->hide();480} else {481Array arr = { count };482total_selected_items_label->set_text(TTRN("{num} currently selected", "{num} currently selected", count).format(arr, "{num}"));483total_selected_items_label->show();484}485}486487void ThemeItemImportTree::_tree_item_edited() {488if (updating_tree) {489return;490}491492TreeItem *edited_item = import_items_tree->get_edited();493if (!edited_item) {494return;495}496497updating_tree = true;498499int edited_column = import_items_tree->get_edited_column();500bool is_checked = edited_item->is_checked(edited_column);501if (is_checked) {502if (edited_column == IMPORT_ITEM_DATA) {503edited_item->set_checked(IMPORT_ITEM, true);504edited_item->propagate_check(IMPORT_ITEM);505}506} else {507if (edited_column == IMPORT_ITEM) {508edited_item->set_checked(IMPORT_ITEM_DATA, false);509edited_item->propagate_check(IMPORT_ITEM_DATA);510}511}512edited_item->propagate_check(edited_column);513updating_tree = false;514}515516void ThemeItemImportTree::_check_propagated_to_tree_item(Object *p_obj, int p_column) {517TreeItem *item = Object::cast_to<TreeItem>(p_obj);518// Skip "category" tree items by checking for children.519if (item && !item->get_first_child()) {520_store_selected_item(item);521}522}523524void ThemeItemImportTree::_select_all_subitems(TreeItem *p_root_item, bool p_select_with_data) {525TreeItem *child_item = p_root_item->get_first_child();526while (child_item) {527child_item->set_checked(IMPORT_ITEM, true);528if (p_select_with_data) {529child_item->set_checked(IMPORT_ITEM_DATA, true);530}531_store_selected_item(child_item);532533_select_all_subitems(child_item, p_select_with_data);534child_item = child_item->get_next();535}536}537538void ThemeItemImportTree::_deselect_all_subitems(TreeItem *p_root_item, bool p_deselect_completely) {539TreeItem *child_item = p_root_item->get_first_child();540while (child_item) {541child_item->set_checked(IMPORT_ITEM_DATA, false);542if (p_deselect_completely) {543child_item->set_checked(IMPORT_ITEM, false);544}545_store_selected_item(child_item);546547_deselect_all_subitems(child_item, p_deselect_completely);548child_item = child_item->get_next();549}550}551552void ThemeItemImportTree::_select_all_items_pressed() {553if (updating_tree) {554return;555}556557updating_tree = true;558559TreeItem *root = import_items_tree->get_root();560_select_all_subitems(root, false);561562updating_tree = false;563}564565void ThemeItemImportTree::_select_full_items_pressed() {566if (updating_tree) {567return;568}569570updating_tree = true;571572TreeItem *root = import_items_tree->get_root();573_select_all_subitems(root, true);574575updating_tree = false;576}577578void ThemeItemImportTree::_deselect_all_items_pressed() {579if (updating_tree) {580return;581}582583updating_tree = true;584585TreeItem *root = import_items_tree->get_root();586_deselect_all_subitems(root, true);587588updating_tree = false;589}590591void ThemeItemImportTree::_select_all_data_type_pressed(int p_data_type) {592ERR_FAIL_INDEX_MSG(p_data_type, Theme::DATA_TYPE_MAX, "Theme item data type is out of bounds.");593594if (updating_tree) {595return;596}597598Theme::DataType data_type = (Theme::DataType)p_data_type;599List<TreeItem *> *item_list = nullptr;600601switch (data_type) {602case Theme::DATA_TYPE_COLOR:603item_list = &tree_color_items;604break;605606case Theme::DATA_TYPE_CONSTANT:607item_list = &tree_constant_items;608break;609610case Theme::DATA_TYPE_FONT:611item_list = &tree_font_items;612break;613614case Theme::DATA_TYPE_FONT_SIZE:615item_list = &tree_font_size_items;616break;617618case Theme::DATA_TYPE_ICON:619item_list = &tree_icon_items;620break;621622case Theme::DATA_TYPE_STYLEBOX:623item_list = &tree_stylebox_items;624break;625626case Theme::DATA_TYPE_MAX:627return; // Can't happen, but silences warning.628}629630updating_tree = true;631632for (List<TreeItem *>::Element *E = item_list->front(); E; E = E->next()) {633TreeItem *child_item = E->get();634if (!child_item) {635continue;636}637638child_item->set_checked(IMPORT_ITEM, true);639child_item->propagate_check(IMPORT_ITEM, false);640_store_selected_item(child_item);641}642643updating_tree = false;644}645646void ThemeItemImportTree::_select_full_data_type_pressed(int p_data_type) {647ERR_FAIL_INDEX_MSG(p_data_type, Theme::DATA_TYPE_MAX, "Theme item data type is out of bounds.");648649if (updating_tree) {650return;651}652653Theme::DataType data_type = (Theme::DataType)p_data_type;654List<TreeItem *> *item_list = nullptr;655656switch (data_type) {657case Theme::DATA_TYPE_COLOR:658item_list = &tree_color_items;659break;660661case Theme::DATA_TYPE_CONSTANT:662item_list = &tree_constant_items;663break;664665case Theme::DATA_TYPE_FONT:666item_list = &tree_font_items;667break;668669case Theme::DATA_TYPE_FONT_SIZE:670item_list = &tree_font_size_items;671break;672673case Theme::DATA_TYPE_ICON:674item_list = &tree_icon_items;675break;676677case Theme::DATA_TYPE_STYLEBOX:678item_list = &tree_stylebox_items;679break;680681case Theme::DATA_TYPE_MAX:682return; // Can't happen, but silences warning.683}684685updating_tree = true;686687for (List<TreeItem *>::Element *E = item_list->front(); E; E = E->next()) {688TreeItem *child_item = E->get();689if (!child_item) {690continue;691}692693child_item->set_checked(IMPORT_ITEM, true);694child_item->set_checked(IMPORT_ITEM_DATA, true);695child_item->propagate_check(IMPORT_ITEM, false);696child_item->propagate_check(IMPORT_ITEM_DATA, false);697_store_selected_item(child_item);698}699700updating_tree = false;701}702703void ThemeItemImportTree::_deselect_all_data_type_pressed(int p_data_type) {704ERR_FAIL_INDEX_MSG(p_data_type, Theme::DATA_TYPE_MAX, "Theme item data type is out of bounds.");705706if (updating_tree) {707return;708}709710Theme::DataType data_type = (Theme::DataType)p_data_type;711List<TreeItem *> *item_list = nullptr;712713switch (data_type) {714case Theme::DATA_TYPE_COLOR:715item_list = &tree_color_items;716break;717718case Theme::DATA_TYPE_CONSTANT:719item_list = &tree_constant_items;720break;721722case Theme::DATA_TYPE_FONT:723item_list = &tree_font_items;724break;725726case Theme::DATA_TYPE_FONT_SIZE:727item_list = &tree_font_size_items;728break;729730case Theme::DATA_TYPE_ICON:731item_list = &tree_icon_items;732break;733734case Theme::DATA_TYPE_STYLEBOX:735item_list = &tree_stylebox_items;736break;737738case Theme::DATA_TYPE_MAX:739return; // Can't happen, but silences warning.740}741742updating_tree = true;743744for (List<TreeItem *>::Element *E = item_list->front(); E; E = E->next()) {745TreeItem *child_item = E->get();746if (!child_item) {747continue;748}749750child_item->set_checked(IMPORT_ITEM, false);751child_item->set_checked(IMPORT_ITEM_DATA, false);752child_item->propagate_check(IMPORT_ITEM, false);753child_item->propagate_check(IMPORT_ITEM_DATA, false);754_store_selected_item(child_item);755}756757updating_tree = false;758}759760void ThemeItemImportTree::_import_selected() {761if (selected_items.is_empty()) {762EditorNode::get_singleton()->show_accept(TTR("Nothing was selected for the import."), TTR("OK"));763return;764}765766Ref<Theme> old_snapshot = edited_theme->duplicate();767Ref<Theme> new_snapshot = edited_theme->duplicate();768769ProgressDialog::get_singleton()->add_task("import_theme_items", TTR("Importing Theme Items"), selected_items.size() + 2);770771int idx = 0;772for (KeyValue<ThemeItem, ItemCheckedState> &E : selected_items) {773// Arbitrary number of items to skip from reporting.774// Reduces the number of UI updates that this causes when copying large themes.775if (idx % 10 == 0) {776Array arr = { idx + 1, selected_items.size() };777ProgressDialog::get_singleton()->task_step("import_theme_items", TTR("Importing items {n}/{n}").format(arr, "{n}"), idx);778}779780ItemCheckedState cs = E.value;781ThemeItem ti = E.key;782783if (cs == SELECT_IMPORT_DEFINITION || cs == SELECT_IMPORT_FULL) {784Variant item_value = Variant();785786if (cs == SELECT_IMPORT_FULL) {787item_value = base_theme->get_theme_item(ti.data_type, ti.item_name, ti.type_name);788} else {789switch (ti.data_type) {790case Theme::DATA_TYPE_COLOR:791item_value = Color();792break;793794case Theme::DATA_TYPE_CONSTANT:795item_value = 0;796break;797798case Theme::DATA_TYPE_FONT:799item_value = Ref<Font>();800break;801802case Theme::DATA_TYPE_FONT_SIZE:803item_value = -1;804break;805806case Theme::DATA_TYPE_ICON:807item_value = Ref<Texture2D>();808break;809810case Theme::DATA_TYPE_STYLEBOX:811item_value = Ref<StyleBox>();812break;813814case Theme::DATA_TYPE_MAX:815break; // Can't happen, but silences warning.816}817}818819new_snapshot->set_theme_item(ti.data_type, ti.item_name, ti.type_name, item_value);820}821822idx++;823}824825// Allow changes to be reported now that the operation is finished.826ProgressDialog::get_singleton()->task_step("import_theme_items", TTR("Updating the editor"), idx++);827828// Make sure the task is not ended before the editor freezes to update the Inspector.829ProgressDialog::get_singleton()->task_step("import_theme_items", TTR("Finalizing"), idx++);830831ProgressDialog::get_singleton()->end_task("import_theme_items");832833EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();834ur->create_action(TTR("Import Theme Items"));835836ur->add_do_method(*edited_theme, "clear");837ur->add_do_method(*edited_theme, "merge_with", new_snapshot);838ur->add_undo_method(*edited_theme, "clear");839ur->add_undo_method(*edited_theme, "merge_with", old_snapshot);840841ur->add_do_method(this, "emit_signal", SNAME("items_imported"));842ur->add_undo_method(this, "emit_signal", SNAME("items_imported"));843844ur->commit_action();845}846847void ThemeItemImportTree::set_edited_theme(const Ref<Theme> &p_theme) {848edited_theme = p_theme;849}850851void ThemeItemImportTree::set_base_theme(const Ref<Theme> &p_theme) {852base_theme = p_theme;853}854855void ThemeItemImportTree::reset_item_tree() {856import_items_filter->clear();857selected_items.clear();858859total_selected_colors_label->hide();860total_selected_constants_label->hide();861total_selected_fonts_label->hide();862total_selected_font_sizes_label->hide();863total_selected_icons_label->hide();864total_selected_styleboxes_label->hide();865866_update_items_tree();867}868869bool ThemeItemImportTree::has_selected_items() const {870return (selected_items.size() > 0);871}872873void ThemeItemImportTree::_notification(int p_what) {874switch (p_what) {875case NOTIFICATION_THEME_CHANGED: {876select_icons_warning_icon->set_texture(get_editor_theme_icon(SNAME("StatusWarning")));877select_icons_warning->add_theme_color_override(SceneStringName(font_color), get_theme_color(SNAME("font_disabled_color"), EditorStringName(Editor)));878879import_items_filter->set_right_icon(get_editor_theme_icon(SNAME("Search")));880881// Bottom panel buttons.882import_collapse_types_button->set_button_icon(get_editor_theme_icon(SNAME("CollapseTree")));883import_expand_types_button->set_button_icon(get_editor_theme_icon(SNAME("ExpandTree")));884885import_select_all_button->set_button_icon(get_editor_theme_icon(SNAME("ThemeSelectAll")));886import_select_full_button->set_button_icon(get_editor_theme_icon(SNAME("ThemeSelectFull")));887import_deselect_all_button->set_button_icon(get_editor_theme_icon(SNAME("ThemeDeselectAll")));888889// Side panel buttons.890select_colors_icon->set_texture(get_editor_theme_icon(SNAME("Color")));891deselect_all_colors_button->set_button_icon(get_editor_theme_icon(SNAME("ThemeDeselectAll")));892select_all_colors_button->set_button_icon(get_editor_theme_icon(SNAME("ThemeSelectAll")));893select_full_colors_button->set_button_icon(get_editor_theme_icon(SNAME("ThemeSelectFull")));894895select_constants_icon->set_texture(get_editor_theme_icon(SNAME("MemberConstant")));896deselect_all_constants_button->set_button_icon(get_editor_theme_icon(SNAME("ThemeDeselectAll")));897select_all_constants_button->set_button_icon(get_editor_theme_icon(SNAME("ThemeSelectAll")));898select_full_constants_button->set_button_icon(get_editor_theme_icon(SNAME("ThemeSelectFull")));899900select_fonts_icon->set_texture(get_editor_theme_icon(SNAME("FontItem")));901deselect_all_fonts_button->set_button_icon(get_editor_theme_icon(SNAME("ThemeDeselectAll")));902select_all_fonts_button->set_button_icon(get_editor_theme_icon(SNAME("ThemeSelectAll")));903select_full_fonts_button->set_button_icon(get_editor_theme_icon(SNAME("ThemeSelectFull")));904905select_font_sizes_icon->set_texture(get_editor_theme_icon(SNAME("FontSize")));906deselect_all_font_sizes_button->set_button_icon(get_editor_theme_icon(SNAME("ThemeDeselectAll")));907select_all_font_sizes_button->set_button_icon(get_editor_theme_icon(SNAME("ThemeSelectAll")));908select_full_font_sizes_button->set_button_icon(get_editor_theme_icon(SNAME("ThemeSelectFull")));909910select_icons_icon->set_texture(get_editor_theme_icon(SNAME("ImageTexture")));911deselect_all_icons_button->set_button_icon(get_editor_theme_icon(SNAME("ThemeDeselectAll")));912select_all_icons_button->set_button_icon(get_editor_theme_icon(SNAME("ThemeSelectAll")));913select_full_icons_button->set_button_icon(get_editor_theme_icon(SNAME("ThemeSelectFull")));914915select_styleboxes_icon->set_texture(get_editor_theme_icon(SNAME("StyleBoxFlat")));916deselect_all_styleboxes_button->set_button_icon(get_editor_theme_icon(SNAME("ThemeDeselectAll")));917select_all_styleboxes_button->set_button_icon(get_editor_theme_icon(SNAME("ThemeSelectAll")));918select_full_styleboxes_button->set_button_icon(get_editor_theme_icon(SNAME("ThemeSelectFull")));919} break;920}921}922923void ThemeItemImportTree::_bind_methods() {924ADD_SIGNAL(MethodInfo("items_imported"));925}926927ThemeItemImportTree::ThemeItemImportTree() {928import_items_filter = memnew(LineEdit);929import_items_filter->set_placeholder(TTR("Filter Items"));930import_items_filter->set_clear_button_enabled(true);931add_child(import_items_filter);932import_items_filter->connect(SceneStringName(text_changed), callable_mp(this, &ThemeItemImportTree::_filter_text_changed));933934HBoxContainer *import_main_hb = memnew(HBoxContainer);935import_main_hb->set_v_size_flags(Control::SIZE_EXPAND_FILL);936add_child(import_main_hb);937938import_items_tree = memnew(Tree);939import_items_tree->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED);940import_items_tree->set_hide_root(true);941import_items_tree->set_h_size_flags(Control::SIZE_EXPAND_FILL);942import_main_hb->add_child(import_items_tree);943import_items_tree->connect("item_edited", callable_mp(this, &ThemeItemImportTree::_tree_item_edited));944import_items_tree->connect("check_propagated_to_item", callable_mp(this, &ThemeItemImportTree::_check_propagated_to_tree_item));945946import_items_tree->set_columns(3);947import_items_tree->set_column_titles_visible(true);948import_items_tree->set_column_title(IMPORT_ITEM, TTR("Import"));949import_items_tree->set_column_title(IMPORT_ITEM_DATA, TTR("With Data"));950import_items_tree->set_column_expand(0, true);951import_items_tree->set_column_clip_content(0, true);952import_items_tree->set_column_expand(IMPORT_ITEM, false);953import_items_tree->set_column_expand(IMPORT_ITEM_DATA, false);954import_items_tree->set_column_custom_minimum_width(0, 160 * EDSCALE);955import_items_tree->set_column_custom_minimum_width(IMPORT_ITEM, 80 * EDSCALE);956import_items_tree->set_column_custom_minimum_width(IMPORT_ITEM_DATA, 80 * EDSCALE);957import_items_tree->set_column_clip_content(1, true);958import_items_tree->set_column_clip_content(2, true);959import_items_tree->set_theme_type_variation("TreeSecondary");960961ScrollContainer *import_bulk_sc = memnew(ScrollContainer);962import_bulk_sc->set_custom_minimum_size(Size2(260.0, 0.0) * EDSCALE);963import_bulk_sc->set_horizontal_scroll_mode(ScrollContainer::SCROLL_MODE_DISABLED);964import_bulk_sc->set_theme_type_variation("ScrollContainerSecondary");965import_main_hb->add_child(import_bulk_sc);966VBoxContainer *import_bulk_vb = memnew(VBoxContainer);967import_bulk_vb->set_h_size_flags(Control::SIZE_EXPAND_FILL);968import_bulk_sc->add_child(import_bulk_vb);969970Label *import_bulk_label = memnew(Label);971import_bulk_label->set_text(TTR("Select by data type:"));972import_bulk_vb->add_child(import_bulk_label);973974select_colors_icon = memnew(TextureRect);975select_colors_label = memnew(Label);976deselect_all_colors_button = memnew(Button);977select_all_colors_button = memnew(Button);978select_full_colors_button = memnew(Button);979total_selected_colors_label = memnew(Label);980981select_constants_icon = memnew(TextureRect);982select_constants_label = memnew(Label);983deselect_all_constants_button = memnew(Button);984select_all_constants_button = memnew(Button);985select_full_constants_button = memnew(Button);986total_selected_constants_label = memnew(Label);987988select_fonts_icon = memnew(TextureRect);989select_fonts_label = memnew(Label);990deselect_all_fonts_button = memnew(Button);991select_all_fonts_button = memnew(Button);992select_full_fonts_button = memnew(Button);993total_selected_fonts_label = memnew(Label);994995select_font_sizes_icon = memnew(TextureRect);996select_font_sizes_label = memnew(Label);997deselect_all_font_sizes_button = memnew(Button);998select_all_font_sizes_button = memnew(Button);999select_full_font_sizes_button = memnew(Button);1000total_selected_font_sizes_label = memnew(Label);10011002select_icons_icon = memnew(TextureRect);1003select_icons_label = memnew(Label);1004deselect_all_icons_button = memnew(Button);1005select_all_icons_button = memnew(Button);1006select_full_icons_button = memnew(Button);1007total_selected_icons_label = memnew(Label);10081009select_styleboxes_icon = memnew(TextureRect);1010select_styleboxes_label = memnew(Label);1011deselect_all_styleboxes_button = memnew(Button);1012select_all_styleboxes_button = memnew(Button);1013select_full_styleboxes_button = memnew(Button);1014total_selected_styleboxes_label = memnew(Label);10151016for (int i = 0; i < Theme::DATA_TYPE_MAX; i++) {1017Theme::DataType dt = (Theme::DataType)i;10181019TextureRect *select_items_icon = nullptr;1020Label *select_items_label = nullptr;1021Button *deselect_all_items_button = nullptr;1022Button *select_all_items_button = nullptr;1023Button *select_full_items_button = nullptr;1024Label *total_selected_items_label = nullptr;10251026String items_title;1027String select_all_items_tooltip;1028String select_full_items_tooltip;1029String deselect_all_items_tooltip;10301031switch (dt) {1032case Theme::DATA_TYPE_COLOR:1033select_items_icon = select_colors_icon;1034select_items_label = select_colors_label;1035deselect_all_items_button = deselect_all_colors_button;1036select_all_items_button = select_all_colors_button;1037select_full_items_button = select_full_colors_button;1038total_selected_items_label = total_selected_colors_label;10391040items_title = TTR("Colors");1041select_all_items_tooltip = TTR("Select all visible color items.");1042select_full_items_tooltip = TTR("Select all visible color items and their data.");1043deselect_all_items_tooltip = TTR("Deselect all visible color items.");1044break;10451046case Theme::DATA_TYPE_CONSTANT:1047select_items_icon = select_constants_icon;1048select_items_label = select_constants_label;1049deselect_all_items_button = deselect_all_constants_button;1050select_all_items_button = select_all_constants_button;1051select_full_items_button = select_full_constants_button;1052total_selected_items_label = total_selected_constants_label;10531054items_title = TTR("Constants");1055select_all_items_tooltip = TTR("Select all visible constant items.");1056select_full_items_tooltip = TTR("Select all visible constant items and their data.");1057deselect_all_items_tooltip = TTR("Deselect all visible constant items.");1058break;10591060case Theme::DATA_TYPE_FONT:1061select_items_icon = select_fonts_icon;1062select_items_label = select_fonts_label;1063deselect_all_items_button = deselect_all_fonts_button;1064select_all_items_button = select_all_fonts_button;1065select_full_items_button = select_full_fonts_button;1066total_selected_items_label = total_selected_fonts_label;10671068items_title = TTR("Fonts");1069select_all_items_tooltip = TTR("Select all visible font items.");1070select_full_items_tooltip = TTR("Select all visible font items and their data.");1071deselect_all_items_tooltip = TTR("Deselect all visible font items.");1072break;10731074case Theme::DATA_TYPE_FONT_SIZE:1075select_items_icon = select_font_sizes_icon;1076select_items_label = select_font_sizes_label;1077deselect_all_items_button = deselect_all_font_sizes_button;1078select_all_items_button = select_all_font_sizes_button;1079select_full_items_button = select_full_font_sizes_button;1080total_selected_items_label = total_selected_font_sizes_label;10811082items_title = TTR("Font sizes");1083select_all_items_tooltip = TTR("Select all visible font size items.");1084select_full_items_tooltip = TTR("Select all visible font size items and their data.");1085deselect_all_items_tooltip = TTR("Deselect all visible font size items.");1086break;10871088case Theme::DATA_TYPE_ICON:1089select_items_icon = select_icons_icon;1090select_items_label = select_icons_label;1091deselect_all_items_button = deselect_all_icons_button;1092select_all_items_button = select_all_icons_button;1093select_full_items_button = select_full_icons_button;1094total_selected_items_label = total_selected_icons_label;10951096items_title = TTR("Icons");1097select_all_items_tooltip = TTR("Select all visible icon items.");1098select_full_items_tooltip = TTR("Select all visible icon items and their data.");1099deselect_all_items_tooltip = TTR("Deselect all visible icon items.");1100break;11011102case Theme::DATA_TYPE_STYLEBOX:1103select_items_icon = select_styleboxes_icon;1104select_items_label = select_styleboxes_label;1105deselect_all_items_button = deselect_all_styleboxes_button;1106select_all_items_button = select_all_styleboxes_button;1107select_full_items_button = select_full_styleboxes_button;1108total_selected_items_label = total_selected_styleboxes_label;11091110items_title = TTR("Styleboxes");1111select_all_items_tooltip = TTR("Select all visible stylebox items.");1112select_full_items_tooltip = TTR("Select all visible stylebox items and their data.");1113deselect_all_items_tooltip = TTR("Deselect all visible stylebox items.");1114break;11151116case Theme::DATA_TYPE_MAX:1117continue; // Can't happen, but silences warning.1118}11191120if (i > 0) {1121import_bulk_vb->add_child(memnew(HSeparator));1122}11231124HBoxContainer *all_set = memnew(HBoxContainer);1125import_bulk_vb->add_child(all_set);11261127HBoxContainer *label_set = memnew(HBoxContainer);1128label_set->set_h_size_flags(Control::SIZE_EXPAND_FILL);1129all_set->add_child(label_set);1130select_items_icon->set_v_size_flags(Control::SIZE_SHRINK_CENTER);1131label_set->add_child(select_items_icon);1132select_items_label->set_h_size_flags(Control::SIZE_EXPAND_FILL);1133select_items_label->set_clip_text(true);1134select_items_label->set_text(items_title);1135label_set->add_child(select_items_label);11361137HBoxContainer *button_set = memnew(HBoxContainer);1138button_set->set_alignment(BoxContainer::ALIGNMENT_END);1139all_set->add_child(button_set);1140select_all_items_button->set_flat(true);1141select_all_items_button->set_tooltip_text(select_all_items_tooltip);1142button_set->add_child(select_all_items_button);1143select_all_items_button->connect(SceneStringName(pressed), callable_mp(this, &ThemeItemImportTree::_select_all_data_type_pressed).bind(i));1144select_full_items_button->set_flat(true);1145select_full_items_button->set_tooltip_text(select_full_items_tooltip);1146button_set->add_child(select_full_items_button);1147select_full_items_button->connect(SceneStringName(pressed), callable_mp(this, &ThemeItemImportTree::_select_full_data_type_pressed).bind(i));1148deselect_all_items_button->set_flat(true);1149deselect_all_items_button->set_tooltip_text(deselect_all_items_tooltip);1150button_set->add_child(deselect_all_items_button);1151deselect_all_items_button->connect(SceneStringName(pressed), callable_mp(this, &ThemeItemImportTree::_deselect_all_data_type_pressed).bind(i));11521153total_selected_items_label->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_RIGHT);1154total_selected_items_label->hide();1155import_bulk_vb->add_child(total_selected_items_label);11561157if (dt == Theme::DATA_TYPE_ICON) {1158select_icons_warning_hb = memnew(HBoxContainer);1159import_bulk_vb->add_child(select_icons_warning_hb);11601161select_icons_warning_icon = memnew(TextureRect);1162select_icons_warning_icon->set_v_size_flags(Control::SIZE_SHRINK_CENTER);1163select_icons_warning_hb->add_child(select_icons_warning_icon);11641165select_icons_warning = memnew(Label);1166select_icons_warning->set_text(TTR("Caution: Adding icon data may considerably increase the size of your Theme resource."));1167select_icons_warning->set_autowrap_mode(TextServer::AUTOWRAP_WORD_SMART);1168select_icons_warning->set_h_size_flags(Control::SIZE_EXPAND_FILL);1169select_icons_warning_hb->add_child(select_icons_warning);1170}1171}11721173HBoxContainer *import_buttons = memnew(HBoxContainer);1174add_child(import_buttons);11751176import_collapse_types_button = memnew(Button);1177import_collapse_types_button->set_flat(true);1178import_collapse_types_button->set_tooltip_text(TTR("Collapse types."));1179import_buttons->add_child(import_collapse_types_button);1180import_collapse_types_button->connect(SceneStringName(pressed), callable_mp(this, &ThemeItemImportTree::_toggle_type_items).bind(true));1181import_expand_types_button = memnew(Button);1182import_expand_types_button->set_flat(true);1183import_expand_types_button->set_tooltip_text(TTR("Expand types."));1184import_buttons->add_child(import_expand_types_button);1185import_expand_types_button->connect(SceneStringName(pressed), callable_mp(this, &ThemeItemImportTree::_toggle_type_items).bind(false));11861187import_buttons->add_child(memnew(VSeparator));11881189import_select_all_button = memnew(Button);1190import_select_all_button->set_flat(true);1191import_select_all_button->set_text(TTR("Select All"));1192import_select_all_button->set_tooltip_text(TTR("Select all Theme items."));1193import_buttons->add_child(import_select_all_button);1194import_select_all_button->connect(SceneStringName(pressed), callable_mp(this, &ThemeItemImportTree::_select_all_items_pressed));1195import_select_full_button = memnew(Button);1196import_select_full_button->set_flat(true);1197import_select_full_button->set_text(TTR("Select With Data"));1198import_select_full_button->set_tooltip_text(TTR("Select all Theme items with item data."));1199import_buttons->add_child(import_select_full_button);1200import_select_full_button->connect(SceneStringName(pressed), callable_mp(this, &ThemeItemImportTree::_select_full_items_pressed));1201import_deselect_all_button = memnew(Button);1202import_deselect_all_button->set_flat(true);1203import_deselect_all_button->set_text(TTR("Deselect All"));1204import_deselect_all_button->set_tooltip_text(TTR("Deselect all Theme items."));1205import_buttons->add_child(import_deselect_all_button);1206import_deselect_all_button->connect(SceneStringName(pressed), callable_mp(this, &ThemeItemImportTree::_deselect_all_items_pressed));12071208import_buttons->add_spacer();12091210Button *import_add_selected_button = memnew(Button);1211import_add_selected_button->set_text(TTR("Import Selected"));1212import_buttons->add_child(import_add_selected_button);1213import_add_selected_button->connect(SceneStringName(pressed), callable_mp(this, &ThemeItemImportTree::_import_selected));1214}12151216///////////////////////12171218void ThemeItemEditorDialog::ok_pressed() {1219if (import_default_theme_items->has_selected_items() || import_editor_theme_items->has_selected_items() || import_other_theme_items->has_selected_items()) {1220confirm_closing_dialog->set_text(TTR("Import Items tab has some items selected. Selection will be lost upon closing this window.\nClose anyway?"));1221confirm_closing_dialog->popup_centered(Size2(380, 120) * EDSCALE);1222return;1223}12241225hide();1226}12271228void ThemeItemEditorDialog::_close_dialog() {1229hide();1230}12311232void ThemeItemEditorDialog::_dialog_about_to_show() {1233ERR_FAIL_COND_MSG(edited_theme.is_null(), "Invalid state of the Theme Editor; the Theme resource is missing.");12341235_update_edit_types();12361237import_default_theme_items->set_edited_theme(edited_theme);1238import_default_theme_items->set_base_theme(ThemeDB::get_singleton()->get_default_theme());1239import_default_theme_items->reset_item_tree();12401241import_editor_theme_items->set_edited_theme(edited_theme);1242import_editor_theme_items->set_base_theme(EditorNode::get_singleton()->get_editor_theme());1243import_editor_theme_items->reset_item_tree();12441245import_other_theme_items->set_edited_theme(edited_theme);1246import_other_theme_items->reset_item_tree();1247}12481249void ThemeItemEditorDialog::_update_edit_types() {1250Ref<Theme> base_theme = ThemeDB::get_singleton()->get_default_theme();12511252List<StringName> theme_types;1253edited_theme->get_type_list(&theme_types);1254theme_types.sort_custom<StringName::AlphCompare>();12551256bool item_reselected = false;1257edit_type_list->clear();1258TreeItem *list_root = edit_type_list->create_item();12591260for (const StringName &E : theme_types) {1261Ref<Texture2D> item_icon;1262if (E == "") {1263item_icon = get_editor_theme_icon(SNAME("NodeDisabled"));1264} else {1265item_icon = EditorNode::get_singleton()->get_class_icon(E, "NodeDisabled");1266}1267TreeItem *list_item = edit_type_list->create_item(list_root);1268list_item->set_text(0, E);1269list_item->set_metadata(0, E);1270list_item->set_editable(0, true);1271list_item->set_icon(0, item_icon);1272list_item->add_button(0, get_editor_theme_icon(SNAME("Remove")), TYPES_TREE_REMOVE_ITEM, false, TTRC("Remove Type"));12731274if (E == edited_item_type) {1275list_item->select(0);1276item_reselected = true;1277}1278}1279if (!item_reselected) {1280edited_item_type = "";12811282if (list_root->get_child_count() > 0) {1283list_root->get_child(0)->select(0);1284}1285}12861287List<StringName> default_types;1288base_theme->get_type_list(&default_types);1289default_types.sort_custom<StringName::AlphCompare>();12901291String selected_type = "";1292TreeItem *selected_item = edit_type_list->get_selected();1293if (selected_item) {1294selected_type = selected_item->get_text(0);12951296edit_items_add_color->set_disabled(false);1297edit_items_add_constant->set_disabled(false);1298edit_items_add_font->set_disabled(false);1299edit_items_add_font_size->set_disabled(false);1300edit_items_add_icon->set_disabled(false);1301edit_items_add_stylebox->set_disabled(false);13021303edit_items_remove_class->set_disabled(false);1304edit_items_remove_custom->set_disabled(false);1305edit_items_remove_all->set_disabled(false);13061307edit_items_message->set_text("");1308edit_items_message->hide();1309} else {1310edit_items_add_color->set_disabled(true);1311edit_items_add_constant->set_disabled(true);1312edit_items_add_font->set_disabled(true);1313edit_items_add_font_size->set_disabled(true);1314edit_items_add_icon->set_disabled(true);1315edit_items_add_stylebox->set_disabled(true);13161317edit_items_remove_class->set_disabled(true);1318edit_items_remove_custom->set_disabled(true);1319edit_items_remove_all->set_disabled(true);13201321edit_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."));1322edit_items_message->show();1323}13241325_update_edit_item_tree(selected_type);1326}13271328void ThemeItemEditorDialog::_edited_type_selected() {1329TreeItem *selected_item = edit_type_list->get_selected();1330String selected_type = selected_item->get_text(0);1331_update_edit_item_tree(selected_type);1332}13331334void ThemeItemEditorDialog::_edited_type_edited() {1335TreeItem *edited_item = edit_type_list->get_selected();1336const String old_type_name = edited_item->get_metadata(0);13371338const String &new_type_name = Theme::validate_type_name(edited_item->get_text(0));1339if (old_type_name == new_type_name) {1340edited_item->set_text(0, old_type_name);1341return;1342}13431344List<StringName> theme_types;1345edited_theme->get_type_list(&theme_types);1346if (theme_types.find(new_type_name) != nullptr) {1347edited_item->set_text(0, old_type_name);1348return;1349}13501351// The list will be recreated, but let's update the item just in case.1352edited_item->set_metadata(0, new_type_name);1353edited_item->set_text(0, new_type_name);13541355EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();1356ur->create_action(TTR("Rename Theme Type"));13571358_rename_theme_type(ur, *edited_theme, old_type_name, new_type_name);13591360// Set `edited_item_type`.1361ur->add_do_method(this, "_update_edit_item_tree", new_type_name);1362ur->add_undo_method(this, "_update_edit_item_tree", old_type_name);13631364ur->add_do_method(this, "_update_edit_types");1365ur->add_undo_method(this, "_update_edit_types");13661367ur->commit_action();1368}13691370void ThemeItemEditorDialog::_edited_type_button_pressed(Object *p_item, int p_column, int p_id, MouseButton p_button) {1371if (p_button != MouseButton::LEFT) {1372return;1373}13741375TreeItem *item = Object::cast_to<TreeItem>(p_item);1376if (!item) {1377return;1378}13791380switch (p_id) {1381case TYPES_TREE_REMOVE_ITEM: {1382String type_name = item->get_text(0);1383_remove_theme_type(type_name);1384} break;1385}1386}13871388void ThemeItemEditorDialog::_update_edit_item_tree(String p_item_type) {1389edited_item_type = p_item_type;13901391edit_items_tree->clear();1392TreeItem *root = edit_items_tree->create_item();13931394List<StringName> names;1395bool has_any_items = false;13961397{ // Colors.1398names.clear();1399edited_theme->get_color_list(p_item_type, &names);14001401if (names.size() > 0) {1402TreeItem *color_root = edit_items_tree->create_item(root);1403color_root->set_metadata(0, Theme::DATA_TYPE_COLOR);1404color_root->set_icon(0, get_editor_theme_icon(SNAME("Color")));1405color_root->set_text(0, TTR("Colors"));1406color_root->add_button(0, get_editor_theme_icon(SNAME("Clear")), ITEMS_TREE_REMOVE_DATA_TYPE, false, TTR("Remove All Color Items"));14071408names.sort_custom<StringName::AlphCompare>();1409for (const StringName &E : names) {1410TreeItem *item = edit_items_tree->create_item(color_root);1411item->set_text(0, E);1412item->add_button(0, get_editor_theme_icon(SNAME("Edit")), ITEMS_TREE_RENAME_ITEM, false, TTR("Rename Item"));1413item->add_button(0, get_editor_theme_icon(SNAME("Remove")), ITEMS_TREE_REMOVE_ITEM, false, TTR("Remove Item"));1414}14151416has_any_items = true;1417}1418}14191420{ // Constants.1421names.clear();1422edited_theme->get_constant_list(p_item_type, &names);14231424if (names.size() > 0) {1425TreeItem *constant_root = edit_items_tree->create_item(root);1426constant_root->set_metadata(0, Theme::DATA_TYPE_CONSTANT);1427constant_root->set_icon(0, get_editor_theme_icon(SNAME("MemberConstant")));1428constant_root->set_text(0, TTR("Constants"));1429constant_root->add_button(0, get_editor_theme_icon(SNAME("Clear")), ITEMS_TREE_REMOVE_DATA_TYPE, false, TTR("Remove All Constant Items"));14301431names.sort_custom<StringName::AlphCompare>();1432for (const StringName &E : names) {1433TreeItem *item = edit_items_tree->create_item(constant_root);1434item->set_text(0, E);1435item->add_button(0, get_editor_theme_icon(SNAME("Edit")), ITEMS_TREE_RENAME_ITEM, false, TTR("Rename Item"));1436item->add_button(0, get_editor_theme_icon(SNAME("Remove")), ITEMS_TREE_REMOVE_ITEM, false, TTR("Remove Item"));1437}14381439has_any_items = true;1440}1441}14421443{ // Fonts.1444names.clear();1445edited_theme->get_font_list(p_item_type, &names);14461447if (names.size() > 0) {1448TreeItem *font_root = edit_items_tree->create_item(root);1449font_root->set_metadata(0, Theme::DATA_TYPE_FONT);1450font_root->set_icon(0, get_editor_theme_icon(SNAME("FontItem")));1451font_root->set_text(0, TTR("Fonts"));1452font_root->add_button(0, get_editor_theme_icon(SNAME("Clear")), ITEMS_TREE_REMOVE_DATA_TYPE, false, TTR("Remove All Font Items"));14531454names.sort_custom<StringName::AlphCompare>();1455for (const StringName &E : names) {1456TreeItem *item = edit_items_tree->create_item(font_root);1457item->set_text(0, E);1458item->add_button(0, get_editor_theme_icon(SNAME("Edit")), ITEMS_TREE_RENAME_ITEM, false, TTR("Rename Item"));1459item->add_button(0, get_editor_theme_icon(SNAME("Remove")), ITEMS_TREE_REMOVE_ITEM, false, TTR("Remove Item"));1460}14611462has_any_items = true;1463}1464}14651466{ // Font sizes.1467names.clear();1468edited_theme->get_font_size_list(p_item_type, &names);14691470if (names.size() > 0) {1471TreeItem *font_size_root = edit_items_tree->create_item(root);1472font_size_root->set_metadata(0, Theme::DATA_TYPE_FONT_SIZE);1473font_size_root->set_icon(0, get_editor_theme_icon(SNAME("FontSize")));1474font_size_root->set_text(0, TTR("Font Sizes"));1475font_size_root->add_button(0, get_editor_theme_icon(SNAME("Clear")), ITEMS_TREE_REMOVE_DATA_TYPE, false, TTR("Remove All Font Size Items"));14761477names.sort_custom<StringName::AlphCompare>();1478for (const StringName &E : names) {1479TreeItem *item = edit_items_tree->create_item(font_size_root);1480item->set_text(0, E);1481item->add_button(0, get_editor_theme_icon(SNAME("Edit")), ITEMS_TREE_RENAME_ITEM, false, TTR("Rename Item"));1482item->add_button(0, get_editor_theme_icon(SNAME("Remove")), ITEMS_TREE_REMOVE_ITEM, false, TTR("Remove Item"));1483}14841485has_any_items = true;1486}1487}14881489{ // Icons.1490names.clear();1491edited_theme->get_icon_list(p_item_type, &names);14921493if (names.size() > 0) {1494TreeItem *icon_root = edit_items_tree->create_item(root);1495icon_root->set_metadata(0, Theme::DATA_TYPE_ICON);1496icon_root->set_icon(0, get_editor_theme_icon(SNAME("ImageTexture")));1497icon_root->set_text(0, TTR("Icons"));1498icon_root->add_button(0, get_editor_theme_icon(SNAME("Clear")), ITEMS_TREE_REMOVE_DATA_TYPE, false, TTR("Remove All Icon Items"));14991500names.sort_custom<StringName::AlphCompare>();1501for (const StringName &E : names) {1502TreeItem *item = edit_items_tree->create_item(icon_root);1503item->set_text(0, E);1504item->add_button(0, get_editor_theme_icon(SNAME("Edit")), ITEMS_TREE_RENAME_ITEM, false, TTR("Rename Item"));1505item->add_button(0, get_editor_theme_icon(SNAME("Remove")), ITEMS_TREE_REMOVE_ITEM, false, TTR("Remove Item"));1506}15071508has_any_items = true;1509}1510}15111512{ // Styleboxes.1513names.clear();1514edited_theme->get_stylebox_list(p_item_type, &names);15151516if (names.size() > 0) {1517TreeItem *stylebox_root = edit_items_tree->create_item(root);1518stylebox_root->set_metadata(0, Theme::DATA_TYPE_STYLEBOX);1519stylebox_root->set_icon(0, get_editor_theme_icon(SNAME("StyleBoxFlat")));1520stylebox_root->set_text(0, TTR("Styleboxes"));1521stylebox_root->add_button(0, get_editor_theme_icon(SNAME("Clear")), ITEMS_TREE_REMOVE_DATA_TYPE, false, TTR("Remove All StyleBox Items"));15221523names.sort_custom<StringName::AlphCompare>();1524for (const StringName &E : names) {1525TreeItem *item = edit_items_tree->create_item(stylebox_root);1526item->set_text(0, E);1527item->add_button(0, get_editor_theme_icon(SNAME("Edit")), ITEMS_TREE_RENAME_ITEM, false, TTR("Rename Item"));1528item->add_button(0, get_editor_theme_icon(SNAME("Remove")), ITEMS_TREE_REMOVE_ITEM, false, TTR("Remove Item"));1529}15301531has_any_items = true;1532}1533}15341535// If some type is selected, but it doesn't seem to have any items, show a guiding message.1536TreeItem *selected_item = edit_type_list->get_selected();1537if (selected_item) {1538if (!has_any_items) {1539edit_items_message->set_text(TTR("This theme type is empty.\nAdd more items to it manually or by importing from another theme."));1540edit_items_message->show();1541} else {1542edit_items_message->set_text("");1543edit_items_message->hide();1544}1545}1546}15471548void ThemeItemEditorDialog::_item_tree_button_pressed(Object *p_item, int p_column, int p_id, MouseButton p_button) {1549if (p_button != MouseButton::LEFT) {1550return;1551}15521553TreeItem *item = Object::cast_to<TreeItem>(p_item);1554if (!item) {1555return;1556}15571558switch (p_id) {1559case ITEMS_TREE_RENAME_ITEM: {1560String item_name = item->get_text(0);1561int data_type = item->get_parent()->get_metadata(0);1562_open_rename_theme_item_dialog((Theme::DataType)data_type, item_name);1563_update_edit_item_tree(edited_item_type);1564} break;1565case ITEMS_TREE_REMOVE_ITEM: {1566String item_name = item->get_text(0);1567int data_type = item->get_parent()->get_metadata(0);15681569EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();1570ur->create_action(TTR("Remove Theme Item"));1571ur->add_do_method(*edited_theme, "clear_theme_item", (Theme::DataType)data_type, item_name, edited_item_type);1572ur->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));1573ur->add_do_method(this, "_update_edit_item_tree", edited_item_type);1574ur->add_undo_method(this, "_update_edit_item_tree", edited_item_type);1575ur->commit_action();1576} break;1577case ITEMS_TREE_REMOVE_DATA_TYPE: {1578int data_type = item->get_metadata(0);1579_remove_data_type_items((Theme::DataType)data_type, edited_item_type);1580} break;1581}1582}15831584void ThemeItemEditorDialog::_add_theme_type() {1585const String &new_type_name = Theme::validate_type_name(edit_add_type_value->get_text());1586edit_add_type_value->clear();15871588EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();1589ur->create_action(TTR("Add Theme Type"));15901591ur->add_do_method(*edited_theme, "add_type", new_type_name);1592ur->add_undo_method(*edited_theme, "remove_type", new_type_name);15931594ur->add_do_method(this, "_update_edit_types");1595ur->add_undo_method(this, "_update_edit_types");15961597ur->commit_action();1598}15991600void ThemeItemEditorDialog::_add_theme_item(Theme::DataType p_data_type, const String &p_item_name, const String &p_item_type) {1601EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();1602ur->create_action(TTR("Create Theme Item"));16031604switch (p_data_type) {1605case Theme::DATA_TYPE_ICON:1606ur->add_do_method(*edited_theme, "set_icon", p_item_name, p_item_type, Ref<Texture2D>());1607ur->add_undo_method(*edited_theme, "clear_icon", p_item_name, p_item_type);1608break;1609case Theme::DATA_TYPE_STYLEBOX:1610ur->add_do_method(*edited_theme, "set_stylebox", p_item_name, p_item_type, Ref<StyleBox>());1611ur->add_undo_method(*edited_theme, "clear_stylebox", p_item_name, p_item_type);16121613if (theme_type_editor->is_stylebox_pinned(edited_theme->get_stylebox(p_item_name, p_item_type))) {1614ur->add_undo_method(theme_type_editor, "_unpin_leading_stylebox");1615}1616break;1617case Theme::DATA_TYPE_FONT:1618ur->add_do_method(*edited_theme, "set_font", p_item_name, p_item_type, Ref<Font>());1619ur->add_undo_method(*edited_theme, "clear_font", p_item_name, p_item_type);1620break;1621case Theme::DATA_TYPE_FONT_SIZE:1622ur->add_do_method(*edited_theme, "set_font_size", p_item_name, p_item_type, -1);1623ur->add_undo_method(*edited_theme, "clear_font_size", p_item_name, p_item_type);1624break;1625case Theme::DATA_TYPE_COLOR:1626ur->add_do_method(*edited_theme, "set_color", p_item_name, p_item_type, Color());1627ur->add_undo_method(*edited_theme, "clear_color", p_item_name, p_item_type);1628break;1629case Theme::DATA_TYPE_CONSTANT:1630ur->add_do_method(*edited_theme, "set_constant", p_item_name, p_item_type, 0);1631ur->add_undo_method(*edited_theme, "clear_constant", p_item_name, p_item_type);1632break;1633case Theme::DATA_TYPE_MAX:1634break; // Can't happen, but silences warning.1635}16361637ur->add_do_method(this, "_update_edit_item_tree", edited_item_type);1638ur->add_undo_method(this, "_update_edit_item_tree", edited_item_type);1639ur->commit_action();1640}16411642void ThemeItemEditorDialog::_remove_theme_type(const String &p_theme_type) {1643Ref<Theme> old_snapshot = edited_theme->duplicate();16441645EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();1646ur->create_action(TTR("Remove Theme Type"));16471648ur->add_do_method(*edited_theme, "remove_type", p_theme_type);1649// If the type was empty, it cannot be restored with merge, but thankfully we can fake it.1650ur->add_undo_method(*edited_theme, "add_type", p_theme_type);1651ur->add_undo_method(*edited_theme, "merge_with", old_snapshot);16521653ur->add_do_method(this, "_update_edit_types");1654ur->add_undo_method(this, "_update_edit_types");16551656ur->commit_action();1657}16581659void ThemeItemEditorDialog::_remove_data_type_items(Theme::DataType p_data_type, String p_item_type) {1660List<StringName> names;16611662Ref<Theme> old_snapshot = edited_theme->duplicate();1663Ref<Theme> new_snapshot = edited_theme->duplicate();16641665EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();1666ur->create_action(TTR("Remove Data Type Items From Theme"));16671668new_snapshot->get_theme_item_list(p_data_type, p_item_type, &names);1669for (const StringName &E : names) {1670new_snapshot->clear_theme_item(p_data_type, E, edited_item_type);16711672if (p_data_type == Theme::DATA_TYPE_STYLEBOX && theme_type_editor->is_stylebox_pinned(edited_theme->get_stylebox(E, p_item_type))) {1673ur->add_do_method(theme_type_editor, "_unpin_leading_stylebox");1674ur->add_undo_method(theme_type_editor, "_pin_leading_stylebox", E, edited_theme->get_stylebox(E, p_item_type));1675}1676}16771678ur->add_do_method(*edited_theme, "clear");1679ur->add_do_method(*edited_theme, "merge_with", new_snapshot);1680ur->add_undo_method(*edited_theme, "merge_with", old_snapshot);16811682ur->add_do_method(this, "_update_edit_item_tree", edited_item_type);1683ur->add_undo_method(this, "_update_edit_item_tree", edited_item_type);16841685ur->commit_action();1686}16871688void ThemeItemEditorDialog::_remove_class_items() {1689List<StringName> names;16901691Ref<Theme> old_snapshot = edited_theme->duplicate();1692Ref<Theme> new_snapshot = edited_theme->duplicate();16931694EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();1695ur->create_action(TTR("Remove Class Items From Theme"));16961697for (int dt = 0; dt < Theme::DATA_TYPE_MAX; dt++) {1698Theme::DataType data_type = (Theme::DataType)dt;16991700names.clear();1701ThemeDB::get_singleton()->get_default_theme()->get_theme_item_list(data_type, edited_item_type, &names);1702for (const StringName &E : names) {1703if (new_snapshot->has_theme_item_nocheck(data_type, E, edited_item_type)) {1704new_snapshot->clear_theme_item(data_type, E, edited_item_type);17051706if (dt == Theme::DATA_TYPE_STYLEBOX && theme_type_editor->is_stylebox_pinned(edited_theme->get_stylebox(E, edited_item_type))) {1707ur->add_do_method(theme_type_editor, "_unpin_leading_stylebox");1708ur->add_undo_method(theme_type_editor, "_pin_leading_stylebox", E, edited_theme->get_stylebox(E, edited_item_type));1709}1710}1711}1712}17131714ur->add_do_method(*edited_theme, "clear");1715ur->add_do_method(*edited_theme, "merge_with", new_snapshot);1716ur->add_undo_method(*edited_theme, "merge_with", old_snapshot);17171718ur->add_do_method(this, "_update_edit_item_tree", edited_item_type);1719ur->add_undo_method(this, "_update_edit_item_tree", edited_item_type);17201721ur->commit_action();1722}17231724void ThemeItemEditorDialog::_remove_custom_items() {1725List<StringName> names;17261727Ref<Theme> old_snapshot = edited_theme->duplicate();1728Ref<Theme> new_snapshot = edited_theme->duplicate();17291730EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();1731ur->create_action(TTR("Remove Custom Items From Theme"));17321733for (int dt = 0; dt < Theme::DATA_TYPE_MAX; dt++) {1734Theme::DataType data_type = (Theme::DataType)dt;17351736names.clear();1737new_snapshot->get_theme_item_list(data_type, edited_item_type, &names);1738for (const StringName &E : names) {1739if (!ThemeDB::get_singleton()->get_default_theme()->has_theme_item_nocheck(data_type, E, edited_item_type)) {1740new_snapshot->clear_theme_item(data_type, E, edited_item_type);17411742if (dt == Theme::DATA_TYPE_STYLEBOX && theme_type_editor->is_stylebox_pinned(edited_theme->get_stylebox(E, edited_item_type))) {1743ur->add_do_method(theme_type_editor, "_unpin_leading_stylebox");1744ur->add_undo_method(theme_type_editor, "_pin_leading_stylebox", E, edited_theme->get_stylebox(E, edited_item_type));1745}1746}1747}1748}17491750ur->add_do_method(*edited_theme, "clear");1751ur->add_do_method(*edited_theme, "merge_with", new_snapshot);1752ur->add_undo_method(*edited_theme, "merge_with", old_snapshot);17531754ur->add_do_method(this, "_update_edit_item_tree", edited_item_type);1755ur->add_undo_method(this, "_update_edit_item_tree", edited_item_type);17561757ur->commit_action();1758}17591760void ThemeItemEditorDialog::_remove_all_items() {1761List<StringName> names;17621763Ref<Theme> old_snapshot = edited_theme->duplicate();1764Ref<Theme> new_snapshot = edited_theme->duplicate();17651766EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();1767ur->create_action(TTR("Remove All Items From Theme"));17681769for (int dt = 0; dt < Theme::DATA_TYPE_MAX; dt++) {1770Theme::DataType data_type = (Theme::DataType)dt;17711772names.clear();1773new_snapshot->get_theme_item_list(data_type, edited_item_type, &names);1774for (const StringName &E : names) {1775new_snapshot->clear_theme_item(data_type, E, edited_item_type);17761777if (dt == Theme::DATA_TYPE_STYLEBOX && theme_type_editor->is_stylebox_pinned(edited_theme->get_stylebox(E, edited_item_type))) {1778ur->add_do_method(theme_type_editor, "_unpin_leading_stylebox");1779ur->add_undo_method(theme_type_editor, "_pin_leading_stylebox", E, edited_theme->get_stylebox(E, edited_item_type));1780}1781}1782}17831784ur->add_do_method(*edited_theme, "clear");1785ur->add_do_method(*edited_theme, "merge_with", new_snapshot);1786ur->add_undo_method(*edited_theme, "merge_with", old_snapshot);17871788ur->add_do_method(this, "_update_edit_item_tree", edited_item_type);1789ur->add_undo_method(this, "_update_edit_item_tree", edited_item_type);17901791ur->commit_action();1792}17931794void ThemeItemEditorDialog::_open_add_theme_item_dialog(int p_data_type) {1795ERR_FAIL_INDEX_MSG(p_data_type, Theme::DATA_TYPE_MAX, "Theme item data type is out of bounds.");17961797item_popup_mode = CREATE_THEME_ITEM;1798edit_item_data_type = (Theme::DataType)p_data_type;17991800switch (edit_item_data_type) {1801case Theme::DATA_TYPE_COLOR:1802edit_theme_item_dialog->set_title(TTR("Add Color Item"));1803break;1804case Theme::DATA_TYPE_CONSTANT:1805edit_theme_item_dialog->set_title(TTR("Add Constant Item"));1806break;1807case Theme::DATA_TYPE_FONT:1808edit_theme_item_dialog->set_title(TTR("Add Font Item"));1809break;1810case Theme::DATA_TYPE_FONT_SIZE:1811edit_theme_item_dialog->set_title(TTR("Add Font Size Item"));1812break;1813case Theme::DATA_TYPE_ICON:1814edit_theme_item_dialog->set_title(TTR("Add Icon Item"));1815break;1816case Theme::DATA_TYPE_STYLEBOX:1817edit_theme_item_dialog->set_title(TTR("Add Stylebox Item"));1818break;1819case Theme::DATA_TYPE_MAX:1820break; // Can't happen, but silences warning.1821}18221823edit_theme_item_old_vb->hide();1824theme_item_name->clear();1825edit_theme_item_dialog->popup_centered(Size2(380, 110) * EDSCALE);1826theme_item_name->grab_focus();1827}18281829void ThemeItemEditorDialog::_open_rename_theme_item_dialog(Theme::DataType p_data_type, String p_item_name) {1830ERR_FAIL_INDEX_MSG(p_data_type, Theme::DATA_TYPE_MAX, "Theme item data type is out of bounds.");18311832item_popup_mode = RENAME_THEME_ITEM;1833edit_item_data_type = p_data_type;1834edit_item_old_name = p_item_name;18351836switch (edit_item_data_type) {1837case Theme::DATA_TYPE_COLOR:1838edit_theme_item_dialog->set_title(TTR("Rename Color Item"));1839break;1840case Theme::DATA_TYPE_CONSTANT:1841edit_theme_item_dialog->set_title(TTR("Rename Constant Item"));1842break;1843case Theme::DATA_TYPE_FONT:1844edit_theme_item_dialog->set_title(TTR("Rename Font Item"));1845break;1846case Theme::DATA_TYPE_FONT_SIZE:1847edit_theme_item_dialog->set_title(TTR("Rename Font Size Item"));1848break;1849case Theme::DATA_TYPE_ICON:1850edit_theme_item_dialog->set_title(TTR("Rename Icon Item"));1851break;1852case Theme::DATA_TYPE_STYLEBOX:1853edit_theme_item_dialog->set_title(TTR("Rename Stylebox Item"));1854break;1855case Theme::DATA_TYPE_MAX:1856break; // Can't happen, but silences warning.1857}18581859edit_theme_item_old_vb->show();1860theme_item_old_name->set_text(p_item_name);1861theme_item_name->set_text(p_item_name);1862edit_theme_item_dialog->popup_centered(Size2(380, 140) * EDSCALE);1863theme_item_name->grab_focus();1864}18651866void ThemeItemEditorDialog::_confirm_edit_theme_item() {1867const String new_item_name = theme_item_name->get_text().strip_edges().validate_ascii_identifier();18681869if (item_popup_mode == CREATE_THEME_ITEM) {1870_add_theme_item(edit_item_data_type, new_item_name, edited_item_type);1871} else if (item_popup_mode == RENAME_THEME_ITEM) {1872EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();1873ur->create_action(TTR("Rename Theme Item"));18741875ur->add_do_method(*edited_theme, "rename_theme_item", edit_item_data_type, edit_item_old_name, new_item_name, edited_item_type);1876ur->add_undo_method(*edited_theme, "rename_theme_item", edit_item_data_type, new_item_name, edit_item_old_name, edited_item_type);18771878ur->add_do_method(this, "_update_edit_item_tree", edited_item_type);1879ur->add_undo_method(this, "_update_edit_item_tree", edited_item_type);18801881ur->commit_action();1882}18831884item_popup_mode = ITEM_POPUP_MODE_MAX;1885edit_item_data_type = Theme::DATA_TYPE_MAX;1886edit_item_old_name = "";1887}18881889void ThemeItemEditorDialog::_edit_theme_item_gui_input(const Ref<InputEvent> &p_event) {1890Ref<InputEventKey> k = p_event;18911892if (k.is_valid()) {1893if (!k->is_pressed()) {1894return;1895}18961897if (k->is_action_pressed(SNAME("ui_text_submit"), false, true)) {1898_confirm_edit_theme_item();1899edit_theme_item_dialog->hide();1900edit_theme_item_dialog->set_input_as_handled();1901} else if (k->is_action_pressed(SNAME("ui_cancel"), false, true)) {1902edit_theme_item_dialog->hide();1903edit_theme_item_dialog->set_input_as_handled();1904}1905}1906}19071908void ThemeItemEditorDialog::_open_select_another_theme() {1909import_another_theme_dialog->popup_file_dialog();1910}19111912void ThemeItemEditorDialog::_select_another_theme_cbk(const String &p_path) {1913Ref<Theme> loaded_theme = ResourceLoader::load(p_path);1914if (loaded_theme.is_null()) {1915EditorNode::get_singleton()->show_warning(TTR("Invalid file, not a Theme resource."));1916return;1917}1918if (loaded_theme == edited_theme) {1919EditorNode::get_singleton()->show_warning(TTR("Invalid file, same as the edited Theme resource."));1920return;1921}19221923import_another_theme_value->set_text(p_path);1924import_other_theme_items->set_base_theme(loaded_theme);1925import_other_theme_items->reset_item_tree();1926}19271928void ThemeItemEditorDialog::_notification(int p_what) {1929switch (p_what) {1930case NOTIFICATION_POSTINITIALIZE: {1931connect("about_to_popup", callable_mp(this, &ThemeItemEditorDialog::_dialog_about_to_show));1932} break;19331934case NOTIFICATION_THEME_CHANGED: {1935edit_items_add_color->set_button_icon(get_editor_theme_icon(SNAME("Color")));1936edit_items_add_constant->set_button_icon(get_editor_theme_icon(SNAME("MemberConstant")));1937edit_items_add_font->set_button_icon(get_editor_theme_icon(SNAME("FontItem")));1938edit_items_add_font_size->set_button_icon(get_editor_theme_icon(SNAME("FontSize")));1939edit_items_add_icon->set_button_icon(get_editor_theme_icon(SNAME("ImageTexture")));1940edit_items_add_stylebox->set_button_icon(get_editor_theme_icon(SNAME("StyleBoxFlat")));19411942edit_items_remove_class->set_button_icon(get_editor_theme_icon(SNAME("Control")));1943edit_items_remove_custom->set_button_icon(get_editor_theme_icon(SNAME("ThemeRemoveCustomItems")));1944edit_items_remove_all->set_button_icon(get_editor_theme_icon(SNAME("ThemeRemoveAllItems")));19451946edit_add_type_button->set_button_icon(get_editor_theme_icon(SNAME("Add")));19471948import_another_theme_button->set_button_icon(get_editor_theme_icon(SNAME("Folder")));1949} break;1950}1951}19521953void ThemeItemEditorDialog::_bind_methods() {1954ClassDB::bind_method(D_METHOD("_update_edit_types"), &ThemeItemEditorDialog::_update_edit_types);1955ClassDB::bind_method(D_METHOD("_update_edit_item_tree"), &ThemeItemEditorDialog::_update_edit_item_tree);1956}19571958void ThemeItemEditorDialog::set_edited_theme(const Ref<Theme> &p_theme) {1959edited_theme = p_theme;1960}19611962ThemeItemEditorDialog::ThemeItemEditorDialog(ThemeTypeEditor *p_theme_type_editor) {1963set_title(TTR("Manage Theme Items"));1964set_ok_button_text(TTR("Close"));1965set_hide_on_ok(false); // Closing may require a confirmation in some cases.19661967theme_type_editor = p_theme_type_editor;19681969tc = memnew(TabContainer);1970add_child(tc);1971tc->set_theme_type_variation("TabContainerOdd");19721973// Edit Items tab.1974HSplitContainer *edit_dialog_hs = memnew(HSplitContainer);1975tc->add_child(edit_dialog_hs);1976tc->set_tab_title(0, TTR("Edit Items"));19771978VBoxContainer *edit_dialog_side_vb = memnew(VBoxContainer);1979edit_dialog_side_vb->set_custom_minimum_size(Size2(200.0, 0.0) * EDSCALE);1980edit_dialog_hs->add_child(edit_dialog_side_vb);19811982Label *edit_type_label = memnew(Label);1983edit_type_label->set_text(TTR("Types:"));1984edit_dialog_side_vb->add_child(edit_type_label);19851986edit_type_list = memnew(Tree);1987edit_type_list->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED);1988edit_type_list->set_hide_root(true);1989edit_type_list->set_hide_folding(true);1990edit_type_list->set_columns(1);1991edit_type_list->set_v_size_flags(Control::SIZE_EXPAND_FILL);1992edit_dialog_side_vb->add_child(edit_type_list);1993edit_type_list->connect(SceneStringName(item_selected), callable_mp(this, &ThemeItemEditorDialog::_edited_type_selected));1994edit_type_list->connect("item_edited", callable_mp(this, &ThemeItemEditorDialog::_edited_type_edited));1995edit_type_list->connect("button_clicked", callable_mp(this, &ThemeItemEditorDialog::_edited_type_button_pressed));1996edit_type_list->set_theme_type_variation("TreeSecondary");19971998Label *edit_add_type_label = memnew(Label);1999edit_add_type_label->set_text(TTR("Add Type:"));2000edit_dialog_side_vb->add_child(edit_add_type_label);20012002HBoxContainer *edit_add_type_hb = memnew(HBoxContainer);2003edit_dialog_side_vb->add_child(edit_add_type_hb);2004edit_add_type_value = memnew(LineEdit);2005edit_add_type_value->set_h_size_flags(Control::SIZE_EXPAND_FILL);2006edit_add_type_value->connect(SceneStringName(text_submitted), callable_mp(this, &ThemeItemEditorDialog::_add_theme_type).unbind(1));2007edit_add_type_hb->add_child(edit_add_type_value);2008edit_add_type_button = memnew(Button);2009edit_add_type_hb->add_child(edit_add_type_button);2010edit_add_type_button->connect(SceneStringName(pressed), callable_mp(this, &ThemeItemEditorDialog::_add_theme_type));20112012VBoxContainer *edit_items_vb = memnew(VBoxContainer);2013edit_items_vb->set_h_size_flags(Control::SIZE_EXPAND_FILL);2014edit_dialog_hs->add_child(edit_items_vb);20152016HBoxContainer *edit_items_toolbar = memnew(HBoxContainer);2017edit_items_vb->add_child(edit_items_toolbar);20182019Label *edit_items_toolbar_add_label = memnew(Label);2020edit_items_toolbar_add_label->set_text(TTR("Add Item:"));2021edit_items_toolbar->add_child(edit_items_toolbar_add_label);20222023edit_items_add_color = memnew(Button);2024edit_items_add_color->set_tooltip_text(TTR("Add Color Item"));2025edit_items_add_color->set_flat(true);2026edit_items_add_color->set_disabled(true);2027edit_items_toolbar->add_child(edit_items_add_color);2028edit_items_add_color->connect(SceneStringName(pressed), callable_mp(this, &ThemeItemEditorDialog::_open_add_theme_item_dialog).bind(Theme::DATA_TYPE_COLOR));20292030edit_items_add_constant = memnew(Button);2031edit_items_add_constant->set_tooltip_text(TTR("Add Constant Item"));2032edit_items_add_constant->set_flat(true);2033edit_items_add_constant->set_disabled(true);2034edit_items_toolbar->add_child(edit_items_add_constant);2035edit_items_add_constant->connect(SceneStringName(pressed), callable_mp(this, &ThemeItemEditorDialog::_open_add_theme_item_dialog).bind(Theme::DATA_TYPE_CONSTANT));20362037edit_items_add_font = memnew(Button);2038edit_items_add_font->set_tooltip_text(TTR("Add Font Item"));2039edit_items_add_font->set_flat(true);2040edit_items_add_font->set_disabled(true);2041edit_items_toolbar->add_child(edit_items_add_font);2042edit_items_add_font->connect(SceneStringName(pressed), callable_mp(this, &ThemeItemEditorDialog::_open_add_theme_item_dialog).bind(Theme::DATA_TYPE_FONT));20432044edit_items_add_font_size = memnew(Button);2045edit_items_add_font_size->set_tooltip_text(TTR("Add Font Size Item"));2046edit_items_add_font_size->set_flat(true);2047edit_items_add_font_size->set_disabled(true);2048edit_items_toolbar->add_child(edit_items_add_font_size);2049edit_items_add_font_size->connect(SceneStringName(pressed), callable_mp(this, &ThemeItemEditorDialog::_open_add_theme_item_dialog).bind(Theme::DATA_TYPE_FONT_SIZE));20502051edit_items_add_icon = memnew(Button);2052edit_items_add_icon->set_tooltip_text(TTR("Add Icon Item"));2053edit_items_add_icon->set_flat(true);2054edit_items_add_icon->set_disabled(true);2055edit_items_toolbar->add_child(edit_items_add_icon);2056edit_items_add_icon->connect(SceneStringName(pressed), callable_mp(this, &ThemeItemEditorDialog::_open_add_theme_item_dialog).bind(Theme::DATA_TYPE_ICON));20572058edit_items_add_stylebox = memnew(Button);2059edit_items_add_stylebox->set_tooltip_text(TTR("Add StyleBox Item"));2060edit_items_add_stylebox->set_flat(true);2061edit_items_add_stylebox->set_disabled(true);2062edit_items_toolbar->add_child(edit_items_add_stylebox);2063edit_items_add_stylebox->connect(SceneStringName(pressed), callable_mp(this, &ThemeItemEditorDialog::_open_add_theme_item_dialog).bind(Theme::DATA_TYPE_STYLEBOX));20642065edit_items_toolbar->add_child(memnew(VSeparator));20662067Label *edit_items_toolbar_remove_label = memnew(Label);2068edit_items_toolbar_remove_label->set_text(TTR("Remove Items:"));2069edit_items_toolbar->add_child(edit_items_toolbar_remove_label);20702071edit_items_remove_class = memnew(Button);2072edit_items_remove_class->set_tooltip_text(TTR("Remove Class Items"));2073edit_items_remove_class->set_flat(true);2074edit_items_remove_class->set_disabled(true);2075edit_items_toolbar->add_child(edit_items_remove_class);2076edit_items_remove_class->connect(SceneStringName(pressed), callable_mp(this, &ThemeItemEditorDialog::_remove_class_items));20772078edit_items_remove_custom = memnew(Button);2079edit_items_remove_custom->set_tooltip_text(TTR("Remove Custom Items"));2080edit_items_remove_custom->set_flat(true);2081edit_items_remove_custom->set_disabled(true);2082edit_items_toolbar->add_child(edit_items_remove_custom);2083edit_items_remove_custom->connect(SceneStringName(pressed), callable_mp(this, &ThemeItemEditorDialog::_remove_custom_items));20842085edit_items_remove_all = memnew(Button);2086edit_items_remove_all->set_tooltip_text(TTR("Remove All Items"));2087edit_items_remove_all->set_flat(true);2088edit_items_remove_all->set_disabled(true);2089edit_items_toolbar->add_child(edit_items_remove_all);2090edit_items_remove_all->connect(SceneStringName(pressed), callable_mp(this, &ThemeItemEditorDialog::_remove_all_items));20912092edit_items_tree = memnew(Tree);2093edit_items_tree->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED);2094edit_items_tree->set_v_size_flags(Control::SIZE_EXPAND_FILL);2095edit_items_tree->set_hide_root(true);2096edit_items_tree->set_columns(1);2097edit_items_tree->set_theme_type_variation("TreeSecondary");2098edit_items_vb->add_child(edit_items_tree);2099edit_items_tree->connect("button_clicked", callable_mp(this, &ThemeItemEditorDialog::_item_tree_button_pressed));21002101edit_items_message = memnew(Label);2102edit_items_message->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT);2103edit_items_message->set_mouse_filter(Control::MOUSE_FILTER_STOP);2104edit_items_message->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_CENTER);2105edit_items_message->set_vertical_alignment(VERTICAL_ALIGNMENT_CENTER);2106edit_items_message->set_autowrap_mode(TextServer::AUTOWRAP_WORD);2107edit_items_tree->add_child(edit_items_message);21082109edit_theme_item_dialog = memnew(ConfirmationDialog);2110edit_theme_item_dialog->set_title(TTR("Add Theme Item"));2111add_child(edit_theme_item_dialog);2112VBoxContainer *edit_theme_item_vb = memnew(VBoxContainer);2113edit_theme_item_dialog->add_child(edit_theme_item_vb);21142115edit_theme_item_old_vb = memnew(VBoxContainer);2116edit_theme_item_vb->add_child(edit_theme_item_old_vb);2117Label *edit_theme_item_old = memnew(Label);2118edit_theme_item_old->set_text(TTR("Old Name:"));2119edit_theme_item_old_vb->add_child(edit_theme_item_old);2120theme_item_old_name = memnew(Label);2121edit_theme_item_old_vb->add_child(theme_item_old_name);21222123Label *edit_theme_item_label = memnew(Label);2124edit_theme_item_label->set_text(TTR("Name:"));2125edit_theme_item_vb->add_child(edit_theme_item_label);2126theme_item_name = memnew(LineEdit);2127edit_theme_item_vb->add_child(theme_item_name);2128theme_item_name->connect(SceneStringName(gui_input), callable_mp(this, &ThemeItemEditorDialog::_edit_theme_item_gui_input));2129edit_theme_item_dialog->connect(SceneStringName(confirmed), callable_mp(this, &ThemeItemEditorDialog::_confirm_edit_theme_item));21302131// Import Items tab.2132TabContainer *import_tc = memnew(TabContainer);2133import_tc->set_theme_type_variation("TabContainerInner");2134import_tc->set_tab_alignment(TabBar::ALIGNMENT_CENTER);2135tc->add_child(import_tc);2136tc->set_tab_title(1, TTR("Import Items"));21372138import_default_theme_items = memnew(ThemeItemImportTree);2139import_tc->add_child(import_default_theme_items);2140import_tc->set_tab_title(0, TTR("Default Theme"));2141import_default_theme_items->connect("items_imported", callable_mp(this, &ThemeItemEditorDialog::_update_edit_types));21422143import_editor_theme_items = memnew(ThemeItemImportTree);2144import_tc->add_child(import_editor_theme_items);2145import_tc->set_tab_title(1, TTR("Editor Theme"));2146import_editor_theme_items->connect("items_imported", callable_mp(this, &ThemeItemEditorDialog::_update_edit_types));21472148VBoxContainer *import_another_theme_vb = memnew(VBoxContainer);21492150HBoxContainer *import_another_file_hb = memnew(HBoxContainer);2151import_another_theme_vb->add_child(import_another_file_hb);2152import_another_theme_value = memnew(LineEdit);2153import_another_theme_value->set_h_size_flags(Control::SIZE_EXPAND_FILL);2154import_another_theme_value->set_editable(false);2155import_another_file_hb->add_child(import_another_theme_value);2156import_another_theme_button = memnew(Button);2157import_another_file_hb->add_child(import_another_theme_button);2158import_another_theme_button->connect(SceneStringName(pressed), callable_mp(this, &ThemeItemEditorDialog::_open_select_another_theme));21592160import_another_theme_dialog = memnew(EditorFileDialog);2161import_another_theme_dialog->set_file_mode(EditorFileDialog::FILE_MODE_OPEN_FILE);2162import_another_theme_dialog->set_title(TTR("Select Another Theme Resource:"));2163List<String> ext;2164ResourceLoader::get_recognized_extensions_for_type("Theme", &ext);2165for (const String &E : ext) {2166import_another_theme_dialog->add_filter("*." + E, TTR("Theme Resource"));2167}2168import_another_file_hb->add_child(import_another_theme_dialog);2169import_another_theme_dialog->connect("file_selected", callable_mp(this, &ThemeItemEditorDialog::_select_another_theme_cbk));21702171import_other_theme_items = memnew(ThemeItemImportTree);2172import_other_theme_items->set_v_size_flags(Control::SIZE_EXPAND_FILL);2173import_another_theme_vb->add_child(import_other_theme_items);21742175import_tc->add_child(import_another_theme_vb);2176import_tc->set_tab_title(2, TTR("Another Theme"));2177import_other_theme_items->connect("items_imported", callable_mp(this, &ThemeItemEditorDialog::_update_edit_types));21782179confirm_closing_dialog = memnew(ConfirmationDialog);2180confirm_closing_dialog->set_autowrap(true);2181add_child(confirm_closing_dialog);2182confirm_closing_dialog->connect(SceneStringName(confirmed), callable_mp(this, &ThemeItemEditorDialog::_close_dialog));2183}21842185///////////////////////21862187void ThemeTypeDialog::_dialog_about_to_show() {2188add_type_filter->set_text("");2189add_type_filter->grab_focus();21902191_update_add_type_options();2192}21932194void ThemeTypeDialog::ok_pressed() {2195_add_type_selected(add_type_filter->get_text().strip_edges());2196}21972198void ThemeTypeDialog::_update_add_type_options(const String &p_filter) {2199add_type_options->clear();22002201List<StringName> names;2202ThemeDB::get_singleton()->get_default_theme()->get_type_list(&names);2203if (include_own_types) {2204edited_theme->get_type_list(&names);2205}2206names.sort_custom<StringName::AlphCompare>();22072208Vector<StringName> unique_names;2209for (const StringName &E : names) {2210// Filter out undesired values.2211if (!p_filter.is_subsequence_ofn(String(E))) {2212continue;2213}22142215// Skip duplicate values.2216if (unique_names.has(E)) {2217continue;2218}2219unique_names.append(E);22202221Ref<Texture2D> item_icon;2222if (E == "") {2223item_icon = get_editor_theme_icon(SNAME("NodeDisabled"));2224} else {2225item_icon = EditorNode::get_singleton()->get_class_icon(E, "NodeDisabled");2226}22272228add_type_options->add_item(E, item_icon);2229}2230}22312232void ThemeTypeDialog::_add_type_filter_cbk(const String &p_value) {2233_update_add_type_options(p_value);2234}22352236void ThemeTypeDialog::_add_type_options_cbk(int p_index) {2237add_type_filter->set_text(add_type_options->get_item_text(p_index));2238add_type_filter->set_caret_column(add_type_filter->get_text().length());2239}22402241void ThemeTypeDialog::_add_type_dialog_entered(const String &p_value) {2242_add_type_selected(Theme::validate_type_name(p_value));2243}22442245void ThemeTypeDialog::_add_type_dialog_activated(int p_index) {2246_add_type_selected(add_type_options->get_item_text(p_index));2247}22482249void ThemeTypeDialog::_add_type_selected(const String &p_type_name) {2250pre_submitted_value = p_type_name;2251if (p_type_name.is_empty()) {2252add_type_confirmation->popup_centered();2253return;2254}22552256_add_type_confirmed();2257}22582259void ThemeTypeDialog::_add_type_confirmed() {2260emit_signal(SNAME("type_selected"), pre_submitted_value);2261hide();2262}22632264void ThemeTypeDialog::_notification(int p_what) {2265switch (p_what) {2266case NOTIFICATION_POSTINITIALIZE: {2267connect("about_to_popup", callable_mp(this, &ThemeTypeDialog::_dialog_about_to_show));2268} break;22692270case NOTIFICATION_THEME_CHANGED: {2271_update_add_type_options();2272} break;22732274case NOTIFICATION_VISIBILITY_CHANGED: {2275if (is_visible()) {2276add_type_filter->grab_focus();2277}2278} break;2279}2280}22812282void ThemeTypeDialog::_bind_methods() {2283ADD_SIGNAL(MethodInfo("type_selected", PropertyInfo(Variant::STRING, "type_name")));2284}22852286void ThemeTypeDialog::set_edited_theme(const Ref<Theme> &p_theme) {2287edited_theme = p_theme;2288}22892290void ThemeTypeDialog::set_include_own_types(bool p_enable) {2291include_own_types = p_enable;2292}22932294ThemeTypeDialog::ThemeTypeDialog() {2295set_hide_on_ok(false);22962297VBoxContainer *add_type_vb = memnew(VBoxContainer);2298add_child(add_type_vb);22992300Label *add_type_filter_label = memnew(Label);2301add_type_filter_label->set_text(TTR("Filter the list of types or create a new custom type:"));2302add_type_vb->add_child(add_type_filter_label);23032304add_type_filter = memnew(FilterLineEdit);2305add_type_vb->add_child(add_type_filter);2306add_type_filter->connect(SceneStringName(text_changed), callable_mp(this, &ThemeTypeDialog::_add_type_filter_cbk));2307add_type_filter->connect(SceneStringName(text_submitted), callable_mp(this, &ThemeTypeDialog::_add_type_dialog_entered));23082309Label *add_type_options_label = memnew(Label);2310add_type_options_label->set_text(TTR("Available Node-based types:"));2311add_type_vb->add_child(add_type_options_label);23122313MarginContainer *mc = memnew(MarginContainer);2314mc->set_v_size_flags(Control::SIZE_EXPAND_FILL);2315mc->set_theme_type_variation("NoBorderHorizontalWindow");2316add_type_vb->add_child(mc);23172318add_type_options = memnew(ItemList);2319add_type_filter->set_forward_control(add_type_options);2320add_type_options->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED);2321add_type_options->set_scroll_hint_mode(ItemList::SCROLL_HINT_MODE_BOTH);2322mc->add_child(add_type_options);2323add_type_options->connect(SceneStringName(item_selected), callable_mp(this, &ThemeTypeDialog::_add_type_options_cbk));2324add_type_options->connect("item_activated", callable_mp(this, &ThemeTypeDialog::_add_type_dialog_activated));23252326add_type_confirmation = memnew(ConfirmationDialog);2327add_type_confirmation->set_title(TTR("Type name is empty!"));2328add_type_confirmation->set_text(TTR("Are you sure you want to create an empty type?"));2329add_type_confirmation->connect(SceneStringName(confirmed), callable_mp(this, &ThemeTypeDialog::_add_type_confirmed));2330add_child(add_type_confirmation);2331}23322333///////////////////////23342335Control *ThemeItemLabel::make_custom_tooltip(const String &p_text) const {2336return EditorHelpBitTooltip::make_tooltip(const_cast<ThemeItemLabel *>(this), p_text);2337}23382339VBoxContainer *ThemeTypeEditor::_create_item_list(Theme::DataType p_data_type) {2340VBoxContainer *items_tab = memnew(VBoxContainer);2341items_tab->set_custom_minimum_size(Size2(0, 160) * EDSCALE);2342data_type_tabs->add_child(items_tab);2343data_type_tabs->set_tab_title(data_type_tabs->get_tab_count() - 1, "");23442345ScrollContainer *items_sc = memnew(ScrollContainer);2346items_sc->set_v_size_flags(SIZE_EXPAND_FILL);2347items_sc->set_horizontal_scroll_mode(ScrollContainer::SCROLL_MODE_DISABLED);2348items_sc->set_theme_type_variation("ScrollContainerSecondary");2349items_tab->add_child(items_sc);2350VBoxContainer *items_list = memnew(VBoxContainer);2351items_list->set_h_size_flags(SIZE_EXPAND_FILL);2352items_sc->add_child(items_list);23532354HBoxContainer *item_add_hb = memnew(HBoxContainer);2355items_tab->add_child(item_add_hb);2356LineEdit *item_add_edit = memnew(LineEdit);2357item_add_edit->set_h_size_flags(SIZE_EXPAND_FILL);2358item_add_hb->add_child(item_add_edit);2359item_add_edit->connect(SceneStringName(text_submitted), callable_mp(this, &ThemeTypeEditor::_item_add_lineedit_cbk).bind(p_data_type, item_add_edit));2360Button *item_add_button = memnew(Button);2361item_add_button->set_text(TTR("Add"));2362item_add_button->set_disabled(true);2363item_add_hb->add_child(item_add_button);2364item_add_button->connect(SceneStringName(pressed), callable_mp(this, &ThemeTypeEditor::_item_add_cbk).bind(p_data_type, item_add_edit));2365item_add_edit->set_meta("button", item_add_button);2366item_add_edit->connect(SceneStringName(text_changed), callable_mp(this, &ThemeTypeEditor::_update_add_button).bind(item_add_edit));23672368return items_list;2369}23702371void ThemeTypeEditor::_update_type_list() {2372ERR_FAIL_COND(edited_theme.is_null());23732374if (updating) {2375return;2376}2377updating = true;23782379Control *focused = get_viewport()->gui_get_focus_owner();2380if (focused) {2381if (focusables.has(focused)) {2382// If focus is currently on one of the internal property editors, don't update.2383updating = false;2384return;2385}23862387Node *focus_parent = focused->get_parent();2388while (focus_parent) {2389Control *c = Object::cast_to<Control>(focus_parent);2390if (c && focusables.has(c)) {2391// If focus is currently on one of the internal property editors, don't update.2392updating = false;2393return;2394}23952396focus_parent = focus_parent->get_parent();2397}2398}23992400List<StringName> theme_types;2401edited_theme->get_type_list(&theme_types);2402theme_types.sort_custom<StringName::AlphCompare>();24032404theme_type_list->clear();24052406if (theme_types.is_empty()) {2407theme_type_list->set_disabled(true);2408theme_type_list->add_item(TTRC("None"));2409theme_type_list->set_item_auto_translate_mode(-1, AUTO_TRANSLATE_MODE_ALWAYS);24102411edited_type = "";2412_update_type_items();2413} else {2414theme_type_list->set_disabled(false);24152416bool item_reselected = false;2417int e_idx = 0;2418for (const StringName &E : theme_types) {2419Ref<Texture2D> item_icon;2420if (E == "") {2421item_icon = get_editor_theme_icon(SNAME("NodeDisabled"));2422} else {2423item_icon = EditorNode::get_singleton()->get_class_icon(E, "NodeDisabled");2424}2425theme_type_list->add_icon_item(item_icon, E);24262427if (E == edited_type) {2428theme_type_list->select(e_idx);2429item_reselected = true;2430}2431e_idx++;2432}24332434if (item_reselected) {2435_update_type_items();2436} else {2437theme_type_list->select(0);2438_list_type_selected(0);2439}2440}24412442rename_type_button->set_disabled(theme_types.is_empty());2443remove_type_button->set_disabled(theme_types.is_empty());24442445updating = false;2446}24472448void ThemeTypeEditor::_update_type_list_debounced() {2449update_debounce_timer->start();2450}24512452HashMap<StringName, bool> ThemeTypeEditor::_get_type_items(String p_type_name, Theme::DataType p_type, bool p_include_default) {2453HashMap<StringName, bool> items;2454List<StringName> names;24552456if (p_include_default) {2457names.clear();2458String default_type;24592460{2461const StringName variation_base = edited_theme->get_type_variation_base(p_type_name);2462if (variation_base != StringName()) {2463default_type = variation_base;2464}2465}24662467if (default_type.is_empty()) {2468// If variation base was not found in the edited theme, look in the default theme.2469const StringName variation_base = ThemeDB::get_singleton()->get_default_theme()->get_type_variation_base(p_type_name);2470if (variation_base != StringName()) {2471default_type = variation_base;2472}2473}24742475if (default_type.is_empty()) {2476default_type = p_type_name;2477}24782479List<ThemeDB::ThemeItemBind> theme_binds;2480ThemeDB::get_singleton()->get_class_items(default_type, &theme_binds, true, p_type);2481for (const ThemeDB::ThemeItemBind &E : theme_binds) {2482names.push_back(E.item_name);2483}24842485names.sort_custom<StringName::AlphCompare>();2486for (const StringName &E : names) {2487items[E] = false;2488}2489}24902491{2492names.clear();2493edited_theme->get_theme_item_list(p_type, p_type_name, &names);2494names.sort_custom<StringName::AlphCompare>();2495for (const StringName &E : names) {2496items[E] = true;2497}2498}24992500List<StringName> keys;2501for (const KeyValue<StringName, bool> &E : items) {2502keys.push_back(E.key);2503}2504keys.sort_custom<StringName::AlphCompare>();25052506HashMap<StringName, bool> ordered_items;2507for (const StringName &E : keys) {2508ordered_items[E] = items[E];2509}25102511return ordered_items;2512}25132514HBoxContainer *ThemeTypeEditor::_create_property_control(Theme::DataType p_data_type, String p_item_name, bool p_editable) {2515HBoxContainer *item_control = memnew(HBoxContainer);25162517HBoxContainer *item_name_container = memnew(HBoxContainer);2518item_name_container->set_h_size_flags(SIZE_EXPAND_FILL);2519item_name_container->set_stretch_ratio(2.0);2520item_control->add_child(item_name_container);25212522Label *item_name = memnew(ThemeItemLabel);2523item_name->set_h_size_flags(SIZE_EXPAND_FILL);2524item_name->set_clip_text(true);2525item_name->set_text(p_item_name);2526// `|` separators used in `EditorHelpBit`.2527item_name->set_tooltip_text("theme_item|" + edited_type + "|" + p_item_name);2528item_name->set_mouse_filter(Control::MOUSE_FILTER_STOP);2529item_name_container->add_child(item_name);25302531if (p_editable) {2532LineEdit *item_name_edit = memnew(LineEdit);2533item_name_edit->set_h_size_flags(SIZE_EXPAND_FILL);2534item_name_edit->set_text(p_item_name);2535item_name_container->add_child(item_name_edit);2536item_name_edit->connect(SceneStringName(text_submitted), callable_mp(this, &ThemeTypeEditor::_item_rename_entered).bind(p_data_type, p_item_name, item_name_container));2537item_name_edit->hide();25382539Button *item_rename_button = memnew(Button);2540item_rename_button->set_button_icon(get_editor_theme_icon(SNAME("Edit")));2541item_rename_button->set_tooltip_text(TTR("Rename Item"));2542item_rename_button->set_flat(true);2543item_name_container->add_child(item_rename_button);2544item_rename_button->connect(SceneStringName(pressed), callable_mp(this, &ThemeTypeEditor::_item_rename_cbk).bind(p_data_type, p_item_name, item_name_container));25452546Button *item_remove_button = memnew(Button);2547item_remove_button->set_button_icon(get_editor_theme_icon(SNAME("Remove")));2548item_remove_button->set_tooltip_text(TTR("Remove Item"));2549item_remove_button->set_flat(true);2550item_name_container->add_child(item_remove_button);2551item_remove_button->connect(SceneStringName(pressed), callable_mp(this, &ThemeTypeEditor::_item_remove_cbk).bind(p_data_type, p_item_name));25522553Button *item_rename_confirm_button = memnew(Button);2554item_rename_confirm_button->set_button_icon(get_editor_theme_icon(SNAME("ImportCheck")));2555item_rename_confirm_button->set_tooltip_text(TTR("Confirm Item Rename"));2556item_rename_confirm_button->set_flat(true);2557item_name_container->add_child(item_rename_confirm_button);2558item_rename_confirm_button->connect(SceneStringName(pressed), callable_mp(this, &ThemeTypeEditor::_item_rename_confirmed).bind(p_data_type, p_item_name, item_name_container));2559item_rename_confirm_button->hide();25602561Button *item_rename_cancel_button = memnew(Button);2562item_rename_cancel_button->set_button_icon(get_editor_theme_icon(SNAME("ImportFail")));2563item_rename_cancel_button->set_tooltip_text(TTR("Cancel Item Rename"));2564item_rename_cancel_button->set_flat(true);2565item_name_container->add_child(item_rename_cancel_button);2566item_rename_cancel_button->connect(SceneStringName(pressed), callable_mp(this, &ThemeTypeEditor::_item_rename_canceled).bind(p_data_type, p_item_name, item_name_container));2567item_rename_cancel_button->hide();2568} else {2569item_name->add_theme_color_override(SceneStringName(font_color), get_theme_color(SNAME("font_disabled_color"), EditorStringName(Editor)));25702571Button *item_override_button = memnew(Button);2572item_override_button->set_button_icon(get_editor_theme_icon(SNAME("Add")));2573item_override_button->set_tooltip_text(TTR("Override Item"));2574item_override_button->set_flat(true);2575item_name_container->add_child(item_override_button);2576item_override_button->connect(SceneStringName(pressed), callable_mp(this, &ThemeTypeEditor::_item_override_cbk).bind(p_data_type, p_item_name));2577}25782579return item_control;2580}25812582void ThemeTypeEditor::_add_focusable(Control *p_control) {2583focusables.append(p_control);2584}25852586void ThemeTypeEditor::_update_type_items() {2587bool show_default = show_default_items_button->is_pressed();25882589focusables.clear();25902591// Colors.2592{2593for (int i = color_items_list->get_child_count() - 1; i >= 0; i--) {2594Node *node = color_items_list->get_child(i);2595node->queue_free();2596color_items_list->remove_child(node);2597}25982599HashMap<StringName, bool> color_items = _get_type_items(edited_type, Theme::DATA_TYPE_COLOR, show_default);2600for (const KeyValue<StringName, bool> &E : color_items) {2601HBoxContainer *item_control = _create_property_control(Theme::DATA_TYPE_COLOR, E.key, E.value);2602ColorPickerButton *item_editor = memnew(ColorPickerButton);2603item_editor->set_h_size_flags(SIZE_EXPAND_FILL);2604item_control->add_child(item_editor);26052606if (E.value) {2607item_editor->set_pick_color(edited_theme->get_color(E.key, edited_type));2608item_editor->connect("color_changed", callable_mp(this, &ThemeTypeEditor::_color_item_changed).bind(E.key));2609item_editor->get_popup()->connect("about_to_popup", callable_mp(EditorNode::get_singleton(), &EditorNode::setup_color_picker).bind(item_editor->get_picker()));2610} else {2611item_editor->set_pick_color(ThemeDB::get_singleton()->get_default_theme()->get_color(E.key, edited_type));2612item_editor->set_disabled(true);2613}26142615_add_focusable(item_editor);2616color_items_list->add_child(item_control);2617}2618}26192620// Constants.2621{2622for (int i = constant_items_list->get_child_count() - 1; i >= 0; i--) {2623Node *node = constant_items_list->get_child(i);2624node->queue_free();2625constant_items_list->remove_child(node);2626}26272628HashMap<StringName, bool> constant_items = _get_type_items(edited_type, Theme::DATA_TYPE_CONSTANT, show_default);2629for (const KeyValue<StringName, bool> &E : constant_items) {2630HBoxContainer *item_control = _create_property_control(Theme::DATA_TYPE_CONSTANT, E.key, E.value);2631EditorSpinSlider *item_editor = memnew(EditorSpinSlider);2632item_editor->set_h_size_flags(SIZE_EXPAND_FILL);2633item_editor->set_min(-100000);2634item_editor->set_max(100000);2635item_editor->set_editing_integer(true);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_read_only(true);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);2704EditorSpinSlider *item_editor = memnew(EditorSpinSlider);2705item_editor->set_h_size_flags(SIZE_EXPAND_FILL);2706item_editor->set_min(-100000);2707item_editor->set_max(100000);2708item_editor->set_editing_integer(true);2709item_editor->set_step(1);2710item_editor->set_allow_lesser(true);2711item_editor->set_allow_greater(true);2712item_control->add_child(item_editor);27132714if (E.value) {2715item_editor->set_value(edited_theme->get_font_size(E.key, edited_type));2716item_editor->connect(SceneStringName(value_changed), callable_mp(this, &ThemeTypeEditor::_font_size_item_changed).bind(E.key));2717} else {2718item_editor->set_value(ThemeDB::get_singleton()->get_default_theme()->get_font_size(E.key, edited_type));2719item_editor->set_read_only(true);2720}27212722_add_focusable(item_editor);2723font_size_items_list->add_child(item_control);2724}2725}27262727// Icons.2728{2729for (int i = icon_items_list->get_child_count() - 1; i >= 0; i--) {2730Node *node = icon_items_list->get_child(i);2731node->queue_free();2732icon_items_list->remove_child(node);2733}27342735HashMap<StringName, bool> icon_items = _get_type_items(edited_type, Theme::DATA_TYPE_ICON, show_default);2736for (const KeyValue<StringName, bool> &E : icon_items) {2737HBoxContainer *item_control = _create_property_control(Theme::DATA_TYPE_ICON, E.key, E.value);2738EditorResourcePicker *item_editor = memnew(EditorResourcePicker);2739item_editor->set_h_size_flags(SIZE_EXPAND_FILL);2740item_editor->set_base_type("Texture2D");2741item_editor->set_resource_owner(*edited_theme);2742item_control->add_child(item_editor);27432744if (E.value) {2745if (edited_theme->has_icon(E.key, edited_type)) {2746item_editor->set_edited_resource(edited_theme->get_icon(E.key, edited_type));2747} else {2748item_editor->set_edited_resource(Ref<Resource>());2749}2750item_editor->connect("resource_selected", callable_mp(this, &ThemeTypeEditor::_edit_resource_item));2751item_editor->connect("resource_changed", callable_mp(this, &ThemeTypeEditor::_icon_item_changed).bind(E.key));2752} else {2753if (ThemeDB::get_singleton()->get_default_theme()->has_icon(E.key, edited_type)) {2754item_editor->set_edited_resource(ThemeDB::get_singleton()->get_default_theme()->get_icon(E.key, edited_type));2755} else {2756item_editor->set_edited_resource(Ref<Resource>());2757}2758item_editor->set_editable(false);2759}27602761_add_focusable(item_editor);2762icon_items_list->add_child(item_control);2763}2764}27652766// Styleboxes.2767{2768for (int i = stylebox_items_list->get_child_count() - 1; i >= 0; i--) {2769Node *node = stylebox_items_list->get_child(i);2770node->queue_free();2771stylebox_items_list->remove_child(node);2772}27732774if (leading_stylebox.pinned) {2775HBoxContainer *item_control = _create_property_control(Theme::DATA_TYPE_STYLEBOX, leading_stylebox.item_name, true);2776EditorResourcePicker *item_editor = memnew(EditorResourcePicker);2777item_editor->set_h_size_flags(SIZE_EXPAND_FILL);2778item_editor->set_stretch_ratio(1.5);2779item_editor->set_base_type("StyleBox");2780item_editor->set_resource_owner(*edited_theme);27812782Button *pin_leader_button = memnew(Button);2783pin_leader_button->set_flat(true);2784pin_leader_button->set_toggle_mode(true);2785pin_leader_button->set_pressed(true);2786pin_leader_button->set_button_icon(get_editor_theme_icon(SNAME("Pin")));2787pin_leader_button->set_tooltip_text(TTR("Unpin this StyleBox as a main style."));2788item_control->add_child(pin_leader_button);2789pin_leader_button->connect(SceneStringName(pressed), callable_mp(this, &ThemeTypeEditor::_on_unpin_leader_button_pressed));27902791item_control->add_child(item_editor);27922793if (edited_theme->has_stylebox(leading_stylebox.item_name, edited_type)) {2794item_editor->set_edited_resource(leading_stylebox.stylebox);2795} else {2796item_editor->set_edited_resource(Ref<Resource>());2797}2798item_editor->connect("resource_selected", callable_mp(this, &ThemeTypeEditor::_edit_resource_item));2799item_editor->connect("resource_changed", callable_mp(this, &ThemeTypeEditor::_stylebox_item_changed).bind(leading_stylebox.item_name));28002801stylebox_items_list->add_child(item_control);2802stylebox_items_list->add_child(memnew(HSeparator));2803}28042805HashMap<StringName, bool> stylebox_items = _get_type_items(edited_type, Theme::DATA_TYPE_STYLEBOX, show_default);2806for (const KeyValue<StringName, bool> &E : stylebox_items) {2807if (leading_stylebox.pinned && leading_stylebox.item_name == E.key) {2808continue;2809}28102811HBoxContainer *item_control = _create_property_control(Theme::DATA_TYPE_STYLEBOX, E.key, E.value);2812EditorResourcePicker *item_editor = memnew(EditorResourcePicker);2813item_editor->set_h_size_flags(SIZE_EXPAND_FILL);2814item_editor->set_stretch_ratio(1.5);2815item_editor->set_base_type("StyleBox");2816item_editor->set_resource_owner(*edited_theme);28172818if (E.value) {2819if (edited_theme->has_stylebox(E.key, edited_type)) {2820item_editor->set_edited_resource(edited_theme->get_stylebox(E.key, edited_type));2821} else {2822item_editor->set_edited_resource(Ref<Resource>());2823}2824item_editor->connect("resource_selected", callable_mp(this, &ThemeTypeEditor::_edit_resource_item));2825item_editor->connect("resource_changed", callable_mp(this, &ThemeTypeEditor::_stylebox_item_changed).bind(E.key));28262827Button *pin_leader_button = memnew(Button);2828pin_leader_button->set_flat(true);2829pin_leader_button->set_toggle_mode(true);2830pin_leader_button->set_button_icon(get_editor_theme_icon(SNAME("Pin")));2831pin_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."));2832pin_leader_button->set_accessibility_name(TTRC("Pin this StyleBox as a main style."));2833item_control->add_child(pin_leader_button);2834pin_leader_button->connect(SceneStringName(pressed), callable_mp(this, &ThemeTypeEditor::_on_pin_leader_button_pressed).bind(item_editor, E.key));2835} else {2836if (ThemeDB::get_singleton()->get_default_theme()->has_stylebox(E.key, edited_type)) {2837item_editor->set_edited_resource(ThemeDB::get_singleton()->get_default_theme()->get_stylebox(E.key, edited_type));2838} else {2839item_editor->set_edited_resource(Ref<Resource>());2840}2841item_editor->set_editable(false);2842}28432844item_control->add_child(item_editor);2845_add_focusable(item_editor);2846stylebox_items_list->add_child(item_control);2847}2848}28492850// Various type settings.2851if (edited_type.is_empty() || ClassDB::class_exists(edited_type)) {2852type_variation_edit->set_editable(false);2853type_variation_edit->set_text("");2854type_variation_button->hide();2855type_variation_locked->set_visible(!edited_type.is_empty());2856} else {2857type_variation_edit->set_editable(true);2858type_variation_edit->set_text(edited_theme->get_type_variation_base(edited_type));2859_add_focusable(type_variation_edit);2860type_variation_button->show();2861type_variation_locked->hide();2862}2863}28642865void ThemeTypeEditor::_list_type_selected(int p_index) {2866edited_type = theme_type_list->get_item_text(p_index);2867_update_type_items();2868}28692870void ThemeTypeEditor::_add_type_button_cbk() {2871add_type_mode = ADD_THEME_TYPE;2872add_type_dialog->set_title(TTR("Add Item Type"));2873add_type_dialog->set_ok_button_text(TTR("Add Type"));2874add_type_dialog->set_include_own_types(false);2875add_type_dialog->popup_centered(Size2(560, 420) * EDSCALE);2876}28772878void ThemeTypeEditor::_rename_type_button_cbk() {2879theme_type_rename_line_edit->set_text(edited_type);2880theme_type_rename_dialog->reset_size();2881theme_type_rename_dialog->popup_centered();2882theme_type_rename_line_edit->grab_focus();2883}28842885void ThemeTypeEditor::_theme_type_rename_dialog_confirmed() {2886const String &new_type_name = Theme::validate_type_name(theme_type_rename_line_edit->get_text());2887if (edited_type == new_type_name) {2888return;2889}28902891List<StringName> theme_types;2892edited_theme->get_type_list(&theme_types);2893if (theme_types.find(new_type_name) != nullptr) {2894return;2895}28962897EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();2898ur->create_action(TTR("Rename Theme Type"));28992900_rename_theme_type(ur, *edited_theme, edited_type, new_type_name);29012902ur->add_do_method(this, "select_type", new_type_name);2903ur->add_undo_method(this, "select_type", edited_type);29042905ur->commit_action();2906}29072908void ThemeTypeEditor::_remove_type_button_cbk() {2909Ref<Theme> old_snapshot = edited_theme->duplicate();29102911EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();2912ur->create_action(TTR("Remove Theme Type"));29132914ur->add_do_method(*edited_theme, "remove_type", edited_type);2915// If the type was empty, it cannot be restored with merge, but thankfully we can fake it.2916ur->add_undo_method(*edited_theme, "add_type", edited_type);2917ur->add_undo_method(*edited_theme, "merge_with", old_snapshot);29182919ur->commit_action();2920}29212922void ThemeTypeEditor::_add_default_type_items() {2923List<StringName> names;2924String default_type = edited_type;2925if (edited_theme->get_type_variation_base(edited_type) != StringName()) {2926default_type = edited_theme->get_type_variation_base(edited_type);2927}29282929Ref<Theme> old_snapshot = edited_theme->duplicate();2930Ref<Theme> new_snapshot = edited_theme->duplicate();29312932updating = true;29332934{2935names.clear();2936ThemeDB::get_singleton()->get_default_theme()->get_icon_list(default_type, &names);2937for (const StringName &E : names) {2938if (!new_snapshot->has_icon(E, edited_type)) {2939new_snapshot->set_icon(E, edited_type, ThemeDB::get_singleton()->get_default_theme()->get_icon(E, edited_type));2940}2941}2942}2943{2944names.clear();2945ThemeDB::get_singleton()->get_default_theme()->get_stylebox_list(default_type, &names);2946for (const StringName &E : names) {2947if (!new_snapshot->has_stylebox(E, edited_type)) {2948new_snapshot->set_stylebox(E, edited_type, ThemeDB::get_singleton()->get_default_theme()->get_stylebox(E, edited_type));2949}2950}2951}2952{2953names.clear();2954ThemeDB::get_singleton()->get_default_theme()->get_font_list(default_type, &names);2955for (const StringName &E : names) {2956if (!new_snapshot->has_font(E, edited_type)) {2957new_snapshot->set_font(E, edited_type, ThemeDB::get_singleton()->get_default_theme()->get_font(E, edited_type));2958}2959}2960}2961{2962names.clear();2963ThemeDB::get_singleton()->get_default_theme()->get_font_size_list(default_type, &names);2964for (const StringName &E : names) {2965if (!new_snapshot->has_font_size(E, edited_type)) {2966new_snapshot->set_font_size(E, edited_type, ThemeDB::get_singleton()->get_default_theme()->get_font_size(E, edited_type));2967}2968}2969}2970{2971names.clear();2972ThemeDB::get_singleton()->get_default_theme()->get_color_list(default_type, &names);2973for (const StringName &E : names) {2974if (!new_snapshot->has_color(E, edited_type)) {2975new_snapshot->set_color(E, edited_type, ThemeDB::get_singleton()->get_default_theme()->get_color(E, edited_type));2976}2977}2978}2979{2980names.clear();2981ThemeDB::get_singleton()->get_default_theme()->get_constant_list(default_type, &names);2982for (const StringName &E : names) {2983if (!new_snapshot->has_constant(E, edited_type)) {2984new_snapshot->set_constant(E, edited_type, ThemeDB::get_singleton()->get_default_theme()->get_constant(E, edited_type));2985}2986}2987}29882989updating = false;29902991EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();2992ur->create_action(TTR("Override All Default Theme Items"));29932994ur->add_do_method(*edited_theme, "merge_with", new_snapshot);2995ur->add_undo_method(*edited_theme, "clear");2996ur->add_undo_method(*edited_theme, "merge_with", old_snapshot);29972998ur->add_do_method(this, "_update_type_items");2999ur->add_undo_method(this, "_update_type_items");30003001ur->commit_action();3002}30033004void ThemeTypeEditor::_update_add_button(const String &p_text, LineEdit *p_for_edit) {3005Button *button = Object::cast_to<Button>(p_for_edit->get_meta("button"));3006button->set_disabled(p_text.strip_edges().is_empty());3007}30083009void ThemeTypeEditor::_item_add_cbk(int p_data_type, Control *p_control) {3010LineEdit *le = Object::cast_to<LineEdit>(p_control);3011if (le->get_text().strip_edges().is_empty()) {3012return;3013}30143015const String item_name = le->get_text().strip_edges().validate_ascii_identifier();30163017EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();3018ur->create_action(TTR("Add Theme Item"));30193020switch (p_data_type) {3021case Theme::DATA_TYPE_COLOR: {3022ur->add_do_method(*edited_theme, "set_color", item_name, edited_type, Color());3023ur->add_undo_method(*edited_theme, "clear_color", item_name, edited_type);3024} break;3025case Theme::DATA_TYPE_CONSTANT: {3026ur->add_do_method(*edited_theme, "set_constant", item_name, edited_type, 0);3027ur->add_undo_method(*edited_theme, "clear_constant", item_name, edited_type);3028} break;3029case Theme::DATA_TYPE_FONT: {3030ur->add_do_method(*edited_theme, "set_font", item_name, edited_type, Ref<Font>());3031ur->add_undo_method(*edited_theme, "clear_font", item_name, edited_type);3032} break;3033case Theme::DATA_TYPE_FONT_SIZE: {3034ur->add_do_method(*edited_theme, "set_font_size", item_name, edited_type, -1);3035ur->add_undo_method(*edited_theme, "clear_font_size", item_name, edited_type);3036} break;3037case Theme::DATA_TYPE_ICON: {3038ur->add_do_method(*edited_theme, "set_icon", item_name, edited_type, Ref<Texture2D>());3039ur->add_undo_method(*edited_theme, "clear_icon", item_name, edited_type);3040} break;3041case Theme::DATA_TYPE_STYLEBOX: {3042Ref<StyleBox> sb;3043ur->add_do_method(*edited_theme, "set_stylebox", item_name, edited_type, sb);3044ur->add_undo_method(*edited_theme, "clear_stylebox", item_name, edited_type);30453046if (is_stylebox_pinned(sb)) {3047ur->add_undo_method(this, "_unpin_leading_stylebox");3048}3049} break;3050}30513052ur->commit_action();30533054le->set_text("");3055_update_add_button("", le);3056}30573058void ThemeTypeEditor::_item_add_lineedit_cbk(String p_value, int p_data_type, Control *p_control) {3059_item_add_cbk(p_data_type, p_control);3060}30613062void ThemeTypeEditor::_item_override_cbk(int p_data_type, String p_item_name) {3063// Avoid errors if the action is triggered multiple times.3064if (edited_theme->has_theme_item_nocheck((Theme::DataType)p_data_type, p_item_name, edited_type)) {3065return;3066}30673068EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();3069ur->create_action(TTR("Override Theme Item"));30703071switch (p_data_type) {3072case Theme::DATA_TYPE_COLOR: {3073ur->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));3074ur->add_undo_method(*edited_theme, "clear_color", p_item_name, edited_type);3075} break;3076case Theme::DATA_TYPE_CONSTANT: {3077ur->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));3078ur->add_undo_method(*edited_theme, "clear_constant", p_item_name, edited_type);3079} break;3080case Theme::DATA_TYPE_FONT: {3081ur->add_do_method(*edited_theme, "set_font", p_item_name, edited_type, Ref<Font>());3082ur->add_undo_method(*edited_theme, "clear_font", p_item_name, edited_type);3083} break;3084case Theme::DATA_TYPE_FONT_SIZE: {3085ur->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));3086ur->add_undo_method(*edited_theme, "clear_font_size", p_item_name, edited_type);3087} break;3088case Theme::DATA_TYPE_ICON: {3089ur->add_do_method(*edited_theme, "set_icon", p_item_name, edited_type, Ref<Texture2D>());3090ur->add_undo_method(*edited_theme, "clear_icon", p_item_name, edited_type);3091} break;3092case Theme::DATA_TYPE_STYLEBOX: {3093Ref<StyleBox> sb;3094ur->add_do_method(*edited_theme, "set_stylebox", p_item_name, edited_type, sb);3095ur->add_undo_method(*edited_theme, "clear_stylebox", p_item_name, edited_type);30963097if (is_stylebox_pinned(sb)) {3098ur->add_undo_method(this, "_unpin_leading_stylebox");3099}3100} break;3101}31023103ur->commit_action();3104}31053106void ThemeTypeEditor::_item_remove_cbk(int p_data_type, String p_item_name) {3107// Avoid errors if the action is triggered multiple times.3108if (!edited_theme->has_theme_item_nocheck((Theme::DataType)p_data_type, p_item_name, edited_type)) {3109return;3110}31113112EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();3113ur->create_action(TTR("Remove Theme Item"));31143115switch (p_data_type) {3116case Theme::DATA_TYPE_COLOR: {3117ur->add_do_method(*edited_theme, "clear_color", p_item_name, edited_type);3118ur->add_undo_method(*edited_theme, "set_color", p_item_name, edited_type, edited_theme->get_color(p_item_name, edited_type));3119} break;3120case Theme::DATA_TYPE_CONSTANT: {3121ur->add_do_method(*edited_theme, "clear_constant", p_item_name, edited_type);3122ur->add_undo_method(*edited_theme, "set_constant", p_item_name, edited_type, edited_theme->get_constant(p_item_name, edited_type));3123} break;3124case Theme::DATA_TYPE_FONT: {3125ur->add_do_method(*edited_theme, "clear_font", p_item_name, edited_type);3126if (edited_theme->has_font(p_item_name, edited_type)) {3127ur->add_undo_method(*edited_theme, "set_font", p_item_name, edited_type, edited_theme->get_font(p_item_name, edited_type));3128} else {3129ur->add_undo_method(*edited_theme, "set_font", p_item_name, edited_type, Ref<Font>());3130}3131} break;3132case Theme::DATA_TYPE_FONT_SIZE: {3133ur->add_do_method(*edited_theme, "clear_font_size", p_item_name, edited_type);3134ur->add_undo_method(*edited_theme, "set_font_size", p_item_name, edited_type, edited_theme->get_font_size(p_item_name, edited_type));3135} break;3136case Theme::DATA_TYPE_ICON: {3137ur->add_do_method(*edited_theme, "clear_icon", p_item_name, edited_type);3138if (edited_theme->has_icon(p_item_name, edited_type)) {3139ur->add_undo_method(*edited_theme, "set_icon", p_item_name, edited_type, edited_theme->get_icon(p_item_name, edited_type));3140} else {3141ur->add_undo_method(*edited_theme, "set_icon", p_item_name, edited_type, Ref<Texture2D>());3142}3143} break;3144case Theme::DATA_TYPE_STYLEBOX: {3145Ref<StyleBox> sb = edited_theme->get_stylebox(p_item_name, edited_type);3146ur->add_do_method(*edited_theme, "clear_stylebox", p_item_name, edited_type);3147if (edited_theme->has_stylebox(p_item_name, edited_type)) {3148ur->add_undo_method(*edited_theme, "set_stylebox", p_item_name, edited_type, sb);3149} else {3150ur->add_undo_method(*edited_theme, "set_stylebox", p_item_name, edited_type, Ref<StyleBox>());3151}31523153if (is_stylebox_pinned(sb)) {3154ur->add_do_method(this, "_unpin_leading_stylebox");3155ur->add_undo_method(this, "_pin_leading_stylebox", p_item_name, sb);3156}3157} break;3158}31593160ur->commit_action();3161}31623163void ThemeTypeEditor::_item_rename_cbk(int p_data_type, String p_item_name, Control *p_control) {3164// Label3165Object::cast_to<Label>(p_control->get_child(0))->hide();3166// Label buttons3167Object::cast_to<Button>(p_control->get_child(2))->hide();3168Object::cast_to<Button>(p_control->get_child(3))->hide();31693170// LineEdit3171Object::cast_to<LineEdit>(p_control->get_child(1))->set_text(p_item_name);3172Object::cast_to<LineEdit>(p_control->get_child(1))->show();3173// LineEdit buttons3174Object::cast_to<Button>(p_control->get_child(4))->show();3175Object::cast_to<Button>(p_control->get_child(5))->show();3176}31773178void ThemeTypeEditor::_item_rename_confirmed(int p_data_type, String p_item_name, Control *p_control) {3179LineEdit *le = Object::cast_to<LineEdit>(p_control->get_child(1));3180if (le->get_text().strip_edges().is_empty()) {3181return;3182}31833184const String new_name = le->get_text().strip_edges().validate_ascii_identifier();3185if (new_name == p_item_name) {3186_item_rename_canceled(p_data_type, p_item_name, p_control);3187return;3188}31893190EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();3191ur->create_action(TTR("Rename Theme Item"));31923193switch (p_data_type) {3194case Theme::DATA_TYPE_COLOR: {3195ur->add_do_method(*edited_theme, "rename_color", p_item_name, new_name, edited_type);3196ur->add_undo_method(*edited_theme, "rename_color", new_name, p_item_name, edited_type);3197} break;3198case Theme::DATA_TYPE_CONSTANT: {3199ur->add_do_method(*edited_theme, "rename_constant", p_item_name, new_name, edited_type);3200ur->add_undo_method(*edited_theme, "rename_constant", new_name, p_item_name, edited_type);3201} break;3202case Theme::DATA_TYPE_FONT: {3203ur->add_do_method(*edited_theme, "rename_font", p_item_name, new_name, edited_type);3204ur->add_undo_method(*edited_theme, "rename_font", new_name, p_item_name, edited_type);3205} break;3206case Theme::DATA_TYPE_FONT_SIZE: {3207ur->add_do_method(*edited_theme, "rename_font_size", p_item_name, new_name, edited_type);3208ur->add_undo_method(*edited_theme, "rename_font_size", new_name, p_item_name, edited_type);3209} break;3210case Theme::DATA_TYPE_ICON: {3211ur->add_do_method(*edited_theme, "rename_icon", p_item_name, new_name, edited_type);3212ur->add_undo_method(*edited_theme, "rename_icon", new_name, p_item_name, edited_type);3213} break;3214case Theme::DATA_TYPE_STYLEBOX: {3215ur->add_do_method(*edited_theme, "rename_stylebox", p_item_name, new_name, edited_type);3216ur->add_undo_method(*edited_theme, "rename_stylebox", new_name, p_item_name, edited_type);32173218if (leading_stylebox.pinned && leading_stylebox.item_name == p_item_name) {3219leading_stylebox.item_name = new_name;3220}3221} break;3222}32233224ur->commit_action();3225}32263227void ThemeTypeEditor::_item_rename_entered(String p_value, int p_data_type, String p_item_name, Control *p_control) {3228_item_rename_confirmed(p_data_type, p_item_name, p_control);3229}32303231void ThemeTypeEditor::_item_rename_canceled(int p_data_type, String p_item_name, Control *p_control) {3232// LineEdit3233Object::cast_to<LineEdit>(p_control->get_child(1))->hide();3234// LineEdit buttons3235Object::cast_to<Button>(p_control->get_child(4))->hide();3236Object::cast_to<Button>(p_control->get_child(5))->hide();32373238// Label3239Object::cast_to<Label>(p_control->get_child(0))->show();3240// Label buttons3241Object::cast_to<Button>(p_control->get_child(2))->show();3242Object::cast_to<Button>(p_control->get_child(3))->show();3243}32443245void ThemeTypeEditor::_color_item_changed(Color p_value, String p_item_name) {3246EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();3247ur->create_action(TTR("Set Color Item in Theme"), UndoRedo::MERGE_ENDS);3248ur->add_do_method(*edited_theme, "set_color", p_item_name, edited_type, p_value);3249ur->add_undo_method(*edited_theme, "set_color", p_item_name, edited_type, edited_theme->get_color(p_item_name, edited_type));3250ur->commit_action();3251}32523253void ThemeTypeEditor::_constant_item_changed(float p_value, String p_item_name) {3254EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();3255ur->create_action(TTR("Set Constant Item in Theme"));3256ur->add_do_method(*edited_theme, "set_constant", p_item_name, edited_type, p_value);3257ur->add_undo_method(*edited_theme, "set_constant", p_item_name, edited_type, edited_theme->get_constant(p_item_name, edited_type));3258ur->commit_action();3259}32603261void ThemeTypeEditor::_font_size_item_changed(float p_value, String p_item_name) {3262EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();3263ur->create_action(TTR("Set Font Size Item in Theme"));3264ur->add_do_method(*edited_theme, "set_font_size", p_item_name, edited_type, p_value);3265ur->add_undo_method(*edited_theme, "set_font_size", p_item_name, edited_type, edited_theme->get_font_size(p_item_name, edited_type));3266ur->commit_action();3267}32683269void ThemeTypeEditor::_edit_resource_item(Ref<Resource> p_resource, bool p_edit) {3270EditorNode::get_singleton()->edit_resource(p_resource);3271}32723273void ThemeTypeEditor::_font_item_changed(Ref<Font> p_value, String p_item_name) {3274EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();3275ur->create_action(TTR("Set Font Item in Theme"));32763277ur->add_do_method(*edited_theme, "set_font", p_item_name, edited_type, p_value.is_valid() ? p_value : Ref<Font>());3278if (edited_theme->has_font(p_item_name, edited_type)) {3279ur->add_undo_method(*edited_theme, "set_font", p_item_name, edited_type, edited_theme->get_font(p_item_name, edited_type));3280} else {3281ur->add_undo_method(*edited_theme, "set_font", p_item_name, edited_type, Ref<Font>());3282}32833284ur->add_do_method(this, CoreStringName(call_deferred), "_update_type_items");3285ur->add_undo_method(this, CoreStringName(call_deferred), "_update_type_items");32863287ur->commit_action();3288}32893290void ThemeTypeEditor::_icon_item_changed(Ref<Texture2D> p_value, String p_item_name) {3291EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();3292ur->create_action(TTR("Set Icon Item in Theme"));32933294ur->add_do_method(*edited_theme, "set_icon", p_item_name, edited_type, p_value.is_valid() ? p_value : Ref<Texture2D>());3295if (edited_theme->has_icon(p_item_name, edited_type)) {3296ur->add_undo_method(*edited_theme, "set_icon", p_item_name, edited_type, edited_theme->get_icon(p_item_name, edited_type));3297} else {3298ur->add_undo_method(*edited_theme, "set_icon", p_item_name, edited_type, Ref<Texture2D>());3299}33003301ur->add_do_method(this, CoreStringName(call_deferred), "_update_type_items");3302ur->add_undo_method(this, CoreStringName(call_deferred), "_update_type_items");33033304ur->commit_action();3305}33063307void ThemeTypeEditor::_stylebox_item_changed(Ref<StyleBox> p_value, String p_item_name) {3308EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();3309ur->create_action(TTR("Set Stylebox Item in Theme"));33103311ur->add_do_method(*edited_theme, "set_stylebox", p_item_name, edited_type, p_value.is_valid() ? p_value : Ref<StyleBox>());3312if (edited_theme->has_stylebox(p_item_name, edited_type)) {3313ur->add_undo_method(*edited_theme, "set_stylebox", p_item_name, edited_type, edited_theme->get_stylebox(p_item_name, edited_type));3314} else {3315ur->add_undo_method(*edited_theme, "set_stylebox", p_item_name, edited_type, Ref<StyleBox>());3316}33173318ur->add_do_method(this, "_change_pinned_stylebox");3319ur->add_undo_method(this, "_change_pinned_stylebox");33203321ur->add_do_method(this, CoreStringName(call_deferred), "_update_type_items");3322ur->add_undo_method(this, CoreStringName(call_deferred), "_update_type_items");33233324ur->commit_action();3325}33263327void ThemeTypeEditor::_change_pinned_stylebox() {3328if (leading_stylebox.pinned) {3329if (leading_stylebox.stylebox.is_valid()) {3330leading_stylebox.stylebox->disconnect_changed(callable_mp(this, &ThemeTypeEditor::_update_stylebox_from_leading));3331}33323333Ref<StyleBox> new_stylebox = edited_theme->get_stylebox(leading_stylebox.item_name, edited_type);3334leading_stylebox.stylebox = new_stylebox;3335leading_stylebox.ref_stylebox = (new_stylebox.is_valid() ? new_stylebox->duplicate() : Ref<Resource>());33363337if (leading_stylebox.stylebox.is_valid()) {3338new_stylebox->connect_changed(callable_mp(this, &ThemeTypeEditor::_update_stylebox_from_leading));3339}3340} else if (leading_stylebox.stylebox.is_valid()) {3341leading_stylebox.stylebox->disconnect_changed(callable_mp(this, &ThemeTypeEditor::_update_stylebox_from_leading));3342}3343}33443345void ThemeTypeEditor::_on_pin_leader_button_pressed(Control *p_editor, String p_item_name) {3346Ref<StyleBox> stylebox;3347if (Object::cast_to<EditorResourcePicker>(p_editor)) {3348stylebox = Object::cast_to<EditorResourcePicker>(p_editor)->get_edited_resource();3349}33503351EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();3352ur->create_action(TTR("Pin Stylebox"));3353ur->add_do_method(this, "_pin_leading_stylebox", p_item_name, stylebox);33543355if (leading_stylebox.pinned) {3356ur->add_undo_method(this, "_pin_leading_stylebox", leading_stylebox.item_name, leading_stylebox.stylebox);3357} else {3358ur->add_undo_method(this, "_unpin_leading_stylebox");3359}33603361ur->commit_action();3362}33633364void ThemeTypeEditor::_pin_leading_stylebox(String p_item_name, Ref<StyleBox> p_stylebox) {3365if (leading_stylebox.stylebox.is_valid()) {3366leading_stylebox.stylebox->disconnect_changed(callable_mp(this, &ThemeTypeEditor::_update_stylebox_from_leading));3367}33683369LeadingStylebox leader;3370leader.pinned = true;3371leader.item_name = p_item_name;3372leader.stylebox = p_stylebox;3373leader.ref_stylebox = (p_stylebox.is_valid() ? p_stylebox->duplicate() : Ref<Resource>());33743375leading_stylebox = leader;3376if (p_stylebox.is_valid()) {3377p_stylebox->connect_changed(callable_mp(this, &ThemeTypeEditor::_update_stylebox_from_leading));3378}33793380_update_type_items();3381}33823383void ThemeTypeEditor::_on_unpin_leader_button_pressed() {3384EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();3385ur->create_action(TTR("Unpin Stylebox"));3386ur->add_do_method(this, "_unpin_leading_stylebox");3387ur->add_undo_method(this, "_pin_leading_stylebox", leading_stylebox.item_name, leading_stylebox.stylebox);3388ur->commit_action();3389}33903391void ThemeTypeEditor::_unpin_leading_stylebox() {3392if (leading_stylebox.stylebox.is_valid()) {3393leading_stylebox.stylebox->disconnect_changed(callable_mp(this, &ThemeTypeEditor::_update_stylebox_from_leading));3394}33953396LeadingStylebox leader;3397leader.pinned = false;3398leading_stylebox = leader;33993400_update_type_items();3401}34023403void ThemeTypeEditor::_update_stylebox_from_leading() {3404if (!leading_stylebox.pinned || leading_stylebox.stylebox.is_null()) {3405return;3406}3407ERR_FAIL_COND_MSG(edited_theme.is_null(), "Leading stylebox does not have an edited theme to update");34083409// Prevent changes from immediately being reported while the operation is still ongoing.3410edited_theme->_freeze_change_propagation();34113412List<StringName> names;3413edited_theme->get_stylebox_list(edited_type, &names);3414List<Ref<StyleBox>> styleboxes;3415for (const StringName &E : names) {3416Ref<StyleBox> sb = edited_theme->get_stylebox(E, edited_type);34173418// Avoid itself, stylebox can be shared between items.3419if (sb == leading_stylebox.stylebox) {3420continue;3421}34223423if (sb->get_class() == leading_stylebox.stylebox->get_class()) {3424styleboxes.push_back(sb);3425}3426}34273428List<PropertyInfo> props;3429leading_stylebox.stylebox->get_property_list(&props);3430for (const PropertyInfo &E : props) {3431if (!(E.usage & PROPERTY_USAGE_STORAGE)) {3432continue;3433}34343435Variant value = leading_stylebox.stylebox->get(E.name);3436Variant ref_value = leading_stylebox.ref_stylebox->get(E.name);3437if (value == ref_value) {3438continue;3439}34403441for (const Ref<StyleBox> &F : styleboxes) {3442Ref<StyleBox> sb = F;3443sb->set(E.name, value);3444}3445}34463447leading_stylebox.ref_stylebox = leading_stylebox.stylebox->duplicate();34483449// Allow changes to be reported now that the operation is finished.3450edited_theme->_unfreeze_and_propagate_changes();3451}34523453void ThemeTypeEditor::_type_variation_changed(const String p_value) {3454EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();3455ur->create_action(TTR("Set Theme Type Variation"));34563457if (p_value.is_empty()) {3458ur->add_do_method(*edited_theme, "clear_type_variation", edited_type);3459} else {3460ur->add_do_method(*edited_theme, "set_type_variation", edited_type, StringName(p_value));3461}34623463if (edited_theme->get_type_variation_base(edited_type) == "") {3464ur->add_undo_method(*edited_theme, "clear_type_variation", edited_type);3465} else {3466ur->add_undo_method(*edited_theme, "set_type_variation", edited_type, edited_theme->get_type_variation_base(edited_type));3467}34683469ur->commit_action();3470}34713472void ThemeTypeEditor::_add_type_variation_cbk() {3473add_type_mode = ADD_VARIATION_BASE;3474add_type_dialog->set_title(TTR("Set Variation Base Type"));3475add_type_dialog->set_ok_button_text(TTR("Set Base Type"));3476add_type_dialog->set_include_own_types(true);3477add_type_dialog->popup_centered(Size2(560, 420) * EDSCALE);3478}34793480void ThemeTypeEditor::_add_type_dialog_selected(const String p_type_name) {3481if (add_type_mode == ADD_THEME_TYPE) {3482select_type(p_type_name);3483} else if (add_type_mode == ADD_VARIATION_BASE) {3484_type_variation_changed(p_type_name);3485}3486}34873488void ThemeTypeEditor::_notification(int p_what) {3489switch (p_what) {3490case NOTIFICATION_THEME_CHANGED: {3491add_type_button->set_button_icon(get_editor_theme_icon(SNAME("Add")));3492rename_type_button->set_button_icon(get_editor_theme_icon(SNAME("Rename")));3493remove_type_button->set_button_icon(get_editor_theme_icon(SNAME("Remove")));34943495const String theme_style = EDITOR_GET("interface/theme/style");3496data_type_tabs->set_theme_type_variation(theme_style == "Classic" ? "TabContainerOdd" : "TabContainerInner");34973498data_type_tabs->set_tab_icon(0, get_editor_theme_icon(SNAME("Color")));3499data_type_tabs->set_tab_icon(1, get_editor_theme_icon(SNAME("MemberConstant")));3500data_type_tabs->set_tab_icon(2, get_editor_theme_icon(SNAME("FontItem")));3501data_type_tabs->set_tab_icon(3, get_editor_theme_icon(SNAME("FontSize")));3502data_type_tabs->set_tab_icon(4, get_editor_theme_icon(SNAME("ImageTexture")));3503data_type_tabs->set_tab_icon(5, get_editor_theme_icon(SNAME("StyleBoxFlat")));3504data_type_tabs->set_tab_icon(6, get_editor_theme_icon(SNAME("Tools")));35053506type_variation_button->set_button_icon(get_editor_theme_icon(SNAME("Add")));3507} break;3508}3509}35103511void ThemeTypeEditor::_bind_methods() {3512ClassDB::bind_method(D_METHOD("_update_type_items"), &ThemeTypeEditor::_update_type_items);3513ClassDB::bind_method(D_METHOD("_pin_leading_stylebox"), &ThemeTypeEditor::_pin_leading_stylebox);3514ClassDB::bind_method(D_METHOD("_unpin_leading_stylebox"), &ThemeTypeEditor::_unpin_leading_stylebox);3515ClassDB::bind_method(D_METHOD("_change_pinned_stylebox"), &ThemeTypeEditor::_change_pinned_stylebox);3516ClassDB::bind_method(D_METHOD("select_type", "type_name"), &ThemeTypeEditor::select_type);3517}35183519void ThemeTypeEditor::set_edited_theme(const Ref<Theme> &p_theme) {3520if (edited_theme.is_valid()) {3521edited_theme->disconnect_changed(callable_mp(this, &ThemeTypeEditor::_update_type_list_debounced));3522}35233524edited_theme = p_theme;3525if (edited_theme.is_valid()) {3526edited_theme->connect_changed(callable_mp(this, &ThemeTypeEditor::_update_type_list_debounced));3527_update_type_list();3528}35293530add_type_dialog->set_edited_theme(edited_theme);3531}35323533void ThemeTypeEditor::select_type(String p_type_name) {3534edited_type = p_type_name;3535bool type_exists = false;35363537for (int i = 0; i < theme_type_list->get_item_count(); i++) {3538String type_name = theme_type_list->get_item_text(i);3539if (type_name == edited_type) {3540theme_type_list->select(i);3541type_exists = true;3542break;3543}3544}35453546if (type_exists) {3547_update_type_items();3548} else {3549edited_theme->add_icon_type(edited_type);3550edited_theme->add_stylebox_type(edited_type);3551edited_theme->add_font_type(edited_type);3552edited_theme->add_font_size_type(edited_type);3553edited_theme->add_color_type(edited_type);3554edited_theme->add_constant_type(edited_type);35553556_update_type_list();3557}3558}35593560bool ThemeTypeEditor::is_stylebox_pinned(Ref<StyleBox> p_stylebox) {3561return leading_stylebox.pinned && leading_stylebox.stylebox == p_stylebox;3562}35633564ThemeTypeEditor::ThemeTypeEditor() {3565VBoxContainer *main_vb = memnew(VBoxContainer);3566add_child(main_vb);35673568HBoxContainer *type_list_hb = memnew(HBoxContainer);3569main_vb->add_child(type_list_hb);35703571Label *type_list_label = memnew(Label);3572type_list_label->set_text(TTR("Type:"));3573type_list_hb->add_child(type_list_label);35743575theme_type_list = memnew(OptionButton);3576theme_type_list->set_h_size_flags(SIZE_EXPAND_FILL);3577theme_type_list->set_text_overrun_behavior(TextServer::OVERRUN_TRIM_ELLIPSIS);3578theme_type_list->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED);3579theme_type_list->set_accessibility_name(TTRC("Type"));3580type_list_hb->add_child(theme_type_list);3581theme_type_list->connect(SceneStringName(item_selected), callable_mp(this, &ThemeTypeEditor::_list_type_selected));35823583add_type_button = memnew(Button);3584add_type_button->set_tooltip_text(TTR("Add a type from a list of available types or create a new one."));3585type_list_hb->add_child(add_type_button);3586add_type_button->connect(SceneStringName(pressed), callable_mp(this, &ThemeTypeEditor::_add_type_button_cbk));35873588rename_type_button = memnew(Button);3589rename_type_button->set_disabled(true);3590rename_type_button->set_tooltip_text(TTRC("Rename current type."));3591type_list_hb->add_child(rename_type_button);3592rename_type_button->connect(SceneStringName(pressed), callable_mp(this, &ThemeTypeEditor::_rename_type_button_cbk));35933594theme_type_rename_dialog = memnew(ConfirmationDialog);3595theme_type_rename_dialog->set_title(TTRC("Rename Theme Type"));3596theme_type_rename_dialog->set_min_size(Size2(256, 64) * EDSCALE);3597add_child(theme_type_rename_dialog);3598theme_type_rename_dialog->connect(SceneStringName(confirmed), callable_mp(this, &ThemeTypeEditor::_theme_type_rename_dialog_confirmed));35993600theme_type_rename_line_edit = memnew(LineEdit);3601theme_type_rename_line_edit->set_select_all_on_focus(true);3602theme_type_rename_dialog->add_child(theme_type_rename_line_edit);3603theme_type_rename_dialog->register_text_enter(theme_type_rename_line_edit);36043605remove_type_button = memnew(Button);3606remove_type_button->set_disabled(true);3607remove_type_button->set_tooltip_text(TTRC("Remove current type."));3608type_list_hb->add_child(remove_type_button);3609remove_type_button->connect(SceneStringName(pressed), callable_mp(this, &ThemeTypeEditor::_remove_type_button_cbk));36103611HBoxContainer *type_controls = memnew(HBoxContainer);3612main_vb->add_child(type_controls);36133614show_default_items_button = memnew(CheckButton);3615show_default_items_button->set_h_size_flags(SIZE_EXPAND_FILL);3616show_default_items_button->set_text(TTR("Show Default"));3617show_default_items_button->set_text_overrun_behavior(TextServer::OVERRUN_TRIM_CHAR);3618show_default_items_button->set_tooltip_text(TTR("Show default type items alongside items that have been overridden."));3619show_default_items_button->set_pressed(true);3620type_controls->add_child(show_default_items_button);3621show_default_items_button->connect(SceneStringName(pressed), callable_mp(this, &ThemeTypeEditor::_update_type_items));36223623Button *add_default_items_button = memnew(Button);3624add_default_items_button->set_h_size_flags(SIZE_EXPAND_FILL);3625add_default_items_button->set_text(TTR("Override All"));3626add_default_items_button->set_tooltip_text(TTR("Override all default type items."));3627type_controls->add_child(add_default_items_button);3628add_default_items_button->connect(SceneStringName(pressed), callable_mp(this, &ThemeTypeEditor::_add_default_type_items));36293630data_type_tabs = memnew(TabContainer);3631data_type_tabs->set_tab_alignment(TabBar::ALIGNMENT_CENTER);3632main_vb->add_child(data_type_tabs);3633data_type_tabs->set_v_size_flags(SIZE_EXPAND_FILL);3634data_type_tabs->set_use_hidden_tabs_for_min_size(true);36353636color_items_list = _create_item_list(Theme::DATA_TYPE_COLOR);3637constant_items_list = _create_item_list(Theme::DATA_TYPE_CONSTANT);3638font_items_list = _create_item_list(Theme::DATA_TYPE_FONT);3639font_size_items_list = _create_item_list(Theme::DATA_TYPE_FONT_SIZE);3640icon_items_list = _create_item_list(Theme::DATA_TYPE_ICON);3641stylebox_items_list = _create_item_list(Theme::DATA_TYPE_STYLEBOX);36423643VBoxContainer *type_settings_tab = memnew(VBoxContainer);3644type_settings_tab->set_custom_minimum_size(Size2(0, 160) * EDSCALE);3645data_type_tabs->add_child(type_settings_tab);3646data_type_tabs->set_tab_title(data_type_tabs->get_tab_count() - 1, "");36473648ScrollContainer *type_settings_sc = memnew(ScrollContainer);3649type_settings_sc->set_v_size_flags(SIZE_EXPAND_FILL);3650type_settings_sc->set_horizontal_scroll_mode(ScrollContainer::SCROLL_MODE_DISABLED);3651type_settings_tab->add_child(type_settings_sc);3652VBoxContainer *type_settings_list = memnew(VBoxContainer);3653type_settings_list->set_h_size_flags(SIZE_EXPAND_FILL);3654type_settings_sc->add_child(type_settings_list);36553656VBoxContainer *type_variation_vb = memnew(VBoxContainer);3657type_settings_list->add_child(type_variation_vb);36583659HBoxContainer *type_variation_hb = memnew(HBoxContainer);3660type_variation_vb->add_child(type_variation_hb);3661Label *type_variation_label = memnew(Label);3662type_variation_hb->add_child(type_variation_label);3663type_variation_label->set_text(TTR("Base Type"));3664type_variation_label->set_h_size_flags(Control::SIZE_EXPAND_FILL);3665type_variation_edit = memnew(LineEdit);3666type_variation_hb->add_child(type_variation_edit);3667type_variation_edit->set_h_size_flags(Control::SIZE_EXPAND_FILL);3668type_variation_edit->connect(SceneStringName(text_changed), callable_mp(this, &ThemeTypeEditor::_type_variation_changed));3669type_variation_edit->connect(SceneStringName(focus_exited), callable_mp(this, &ThemeTypeEditor::_update_type_items));3670type_variation_edit->set_accessibility_name(TTRC("Base Type"));3671type_variation_button = memnew(Button);3672type_variation_hb->add_child(type_variation_button);3673type_variation_button->set_tooltip_text(TTR("Select the variation base type from a list of available types."));3674type_variation_button->connect(SceneStringName(pressed), callable_mp(this, &ThemeTypeEditor::_add_type_variation_cbk));36753676type_variation_locked = memnew(Label);3677type_variation_vb->add_child(type_variation_locked);3678type_variation_locked->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_CENTER);3679type_variation_locked->set_autowrap_mode(TextServer::AUTOWRAP_WORD);3680type_variation_locked->set_text(TTR("A type associated with a built-in class cannot be marked as a variation of another type."));3681type_variation_locked->hide();36823683add_type_dialog = memnew(ThemeTypeDialog);3684add_child(add_type_dialog);3685add_type_dialog->connect("type_selected", callable_mp(this, &ThemeTypeEditor::_add_type_dialog_selected));36863687update_debounce_timer = memnew(Timer);3688update_debounce_timer->set_one_shot(true);3689update_debounce_timer->set_wait_time(0.5);3690update_debounce_timer->connect("timeout", callable_mp(this, &ThemeTypeEditor::_update_type_list));3691add_child(update_debounce_timer);3692}36933694///////////////////////36953696void ThemeEditor::edit(const Ref<Theme> &p_theme) {3697if (theme == p_theme) {3698return;3699}37003701theme = p_theme;3702theme_type_editor->set_edited_theme(p_theme);3703theme_edit_dialog->set_edited_theme(p_theme);37043705for (int i = 0; i < preview_tabs_content->get_child_count(); i++) {3706ThemeEditorPreview *preview_tab = Object::cast_to<ThemeEditorPreview>(preview_tabs_content->get_child(i));3707if (!preview_tab) {3708continue;3709}37103711preview_tab->set_preview_theme(p_theme);3712}37133714if (theme.is_valid()) {3715_update_theme_name(theme->get_path().get_file());3716}3717}37183719Ref<Theme> ThemeEditor::get_edited_theme() {3720return theme;3721}37223723void ThemeEditor::_theme_save_button_cbk(bool p_save_as) {3724ERR_FAIL_COND_MSG(theme.is_null(), "Invalid state of the Theme Editor; the Theme resource is missing.");37253726if (p_save_as) {3727EditorNode::get_singleton()->save_resource_as(theme);3728} else {3729EditorNode::get_singleton()->save_resource(theme);3730}3731}37323733void ThemeEditor::_theme_edit_button_cbk() {3734theme_edit_dialog->popup_centered_clamped(Size2(850, 700) * EDSCALE, 0.8);3735}37363737void ThemeEditor::_theme_close_button_cbk() {3738close();3739_dock_closed_cbk();3740}37413742void ThemeEditor::_dock_closed_cbk() {3743if (theme.is_valid() && InspectorDock::get_inspector_singleton()->get_edited_object() == theme.ptr()) {3744EditorNode::get_singleton()->push_item(nullptr);3745}3746theme = Ref<Theme>();3747}37483749void ThemeEditor::_scene_closed(const String &p_path) {3750if (theme.is_valid() && theme->is_built_in() && theme->get_path().get_slice("::", 0) == p_path) {3751theme = Ref<Theme>();3752EditorNode::get_singleton()->hide_unused_editors(plugin);3753}3754}37553756void ThemeEditor::_resource_saved(const Ref<Resource> &p_resource) {3757if (theme.is_valid() && theme == p_resource) {3758_update_theme_name(theme->get_path().get_file());3759}3760}37613762void ThemeEditor::_files_moved(const String &p_old_path, const String &p_new_path) {3763// Theme's path may not have been updated to new path yet - need to check both old and new.3764if (theme.is_valid() && (theme->get_path() == p_old_path || theme->get_path() == p_new_path)) {3765_update_theme_name(p_new_path.get_file());3766}3767}37683769void ThemeEditor::_update_theme_name(const String &p_name) {3770theme_name->set_text(p_name);3771theme_name->set_tooltip_text(p_name);37723773int label_min_width = theme_name->get_minimum_size().x + theme_name->get_character_bounds(0).size.x;3774theme_name->set_custom_minimum_size(Size2(label_min_width, 0));3775}37763777void ThemeEditor::_add_preview_button_cbk() {3778preview_scene_dialog->popup_file_dialog();3779}37803781void ThemeEditor::_preview_scene_dialog_cbk(const String &p_path) {3782SceneThemeEditorPreview *preview_tab = memnew(SceneThemeEditorPreview);3783if (!preview_tab->set_preview_scene(p_path)) {3784memdelete(preview_tab);3785return;3786}37873788_add_preview_tab(preview_tab, p_path.get_file(), get_editor_theme_icon(SNAME("PackedScene")));3789preview_tab->connect("scene_invalidated", callable_mp(this, &ThemeEditor::_remove_preview_tab_invalid).bind(preview_tab));3790preview_tab->connect("scene_reloaded", callable_mp(this, &ThemeEditor::_update_preview_tab).bind(preview_tab));3791}37923793void ThemeEditor::_add_preview_tab(ThemeEditorPreview *p_preview_tab, const String &p_preview_name, const Ref<Texture2D> &p_icon) {3794p_preview_tab->set_preview_theme(theme);37953796preview_tabs->add_tab(p_preview_name, p_icon);3797preview_tabs_content->add_child(p_preview_tab);3798preview_tabs->set_tab_button_icon(preview_tabs->get_tab_count() - 1, EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("close"), SNAME("TabBar")));3799p_preview_tab->connect("control_picked", callable_mp(this, &ThemeEditor::_preview_control_picked));38003801preview_tabs->set_current_tab(preview_tabs->get_tab_count() - 1);3802_preview_tabs_resized();3803}38043805void ThemeEditor::_change_preview_tab(int p_tab) {3806ERR_FAIL_INDEX_MSG(p_tab, preview_tabs_content->get_child_count(), "Attempting to open a preview tab that doesn't exist.");38073808for (int i = 0; i < preview_tabs_content->get_child_count(); i++) {3809Control *c = Object::cast_to<Control>(preview_tabs_content->get_child(i));3810if (!c) {3811continue;3812}38133814c->set_visible(i == p_tab);3815}3816}38173818void ThemeEditor::_remove_preview_tab(int p_tab) {3819ERR_FAIL_INDEX_MSG(p_tab, preview_tabs_content->get_child_count(), "Attempting to remove a preview tab that doesn't exist.");38203821ThemeEditorPreview *preview_tab = Object::cast_to<ThemeEditorPreview>(preview_tabs_content->get_child(p_tab));3822ERR_FAIL_COND_MSG(Object::cast_to<DefaultThemeEditorPreview>(preview_tab), "Attemptying to remove the default preview tab.");38233824if (preview_tab) {3825preview_tab->disconnect("control_picked", callable_mp(this, &ThemeEditor::_preview_control_picked));3826if (preview_tab->is_connected("scene_invalidated", callable_mp(this, &ThemeEditor::_remove_preview_tab_invalid))) {3827preview_tab->disconnect("scene_invalidated", callable_mp(this, &ThemeEditor::_remove_preview_tab_invalid));3828}3829if (preview_tab->is_connected("scene_reloaded", callable_mp(this, &ThemeEditor::_update_preview_tab))) {3830preview_tab->disconnect("scene_reloaded", callable_mp(this, &ThemeEditor::_update_preview_tab));3831}38323833preview_tabs_content->remove_child(preview_tab);3834preview_tab->queue_free();38353836preview_tabs->remove_tab(p_tab);3837_change_preview_tab(preview_tabs->get_current_tab());3838_preview_tabs_resized();3839}3840}38413842void ThemeEditor::_remove_preview_tab_invalid(Node *p_tab_control) {3843int tab_index = p_tab_control->get_index();3844_remove_preview_tab(tab_index);3845}38463847void ThemeEditor::_update_preview_tab(Node *p_tab_control) {3848if (!Object::cast_to<SceneThemeEditorPreview>(p_tab_control)) {3849return;3850}38513852int tab_index = p_tab_control->get_index();3853SceneThemeEditorPreview *scene_preview = Object::cast_to<SceneThemeEditorPreview>(p_tab_control);3854preview_tabs->set_tab_title(tab_index, scene_preview->get_preview_scene_path().get_file());38553856_preview_tabs_resized();3857}38583859void ThemeEditor::_preview_control_picked(String p_class_name) {3860theme_type_editor->select_type(p_class_name);3861}38623863bool ThemeEditor::can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) {3864const Dictionary d = p_data;3865if (!d.has("type")) {3866return false;3867}38683869if (String(d["type"]) == "files") {3870const Vector<String> files = d["files"];38713872if (files.size() != 1) {3873return false;3874}38753876const String ftype = EditorFileSystem::get_singleton()->get_file_type(files[0]);3877return ftype == "PackedScene";3878}3879return false;3880}38813882void ThemeEditor::drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) {3883Dictionary d = p_data;3884Vector<String> files = d["files"];3885const String &path = files[0];38863887SceneThemeEditorPreview *preview_tab = memnew(SceneThemeEditorPreview);3888if (!preview_tab->set_preview_scene(path)) {3889memdelete(preview_tab);3890return;3891}38923893Ref<Texture2D> icon = get_editor_theme_icon(SNAME("PackedScene"));38943895preview_tab->set_preview_theme(theme);38963897preview_tabs->add_tab(path.get_file(), icon);3898preview_tabs_content->add_child(preview_tab);3899preview_tabs->set_tab_button_icon(preview_tabs->get_tab_count() - 1, EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("close"), SNAME("TabBar")));3900preview_tab->connect("control_picked", callable_mp(this, &ThemeEditor::_preview_control_picked));39013902preview_tabs->set_current_tab(preview_tabs->get_tab_count() - 1);3903preview_tab->connect("scene_invalidated", callable_mp(this, &ThemeEditor::_remove_preview_tab_invalid).bind(preview_tab));3904preview_tab->connect("scene_reloaded", callable_mp(this, &ThemeEditor::_update_preview_tab).bind(preview_tab));3905}39063907void ThemeEditor::_preview_tabs_resized() {3908const Size2 add_button_size = Size2(add_preview_button->get_size().x, preview_tabs->get_size().y);3909if (preview_tabs->get_offset_buttons_visible()) {3910// Move the add button to a fixed position.3911if (add_preview_button->get_parent() == preview_tabs) {3912add_preview_button->reparent(add_preview_button_ph);3913add_preview_button->set_rect(Rect2(Point2(), add_button_size));3914}3915} else {3916// Move the add button to be after the last tab.3917if (add_preview_button->get_parent() == add_preview_button_ph) {3918add_preview_button->reparent(preview_tabs);3919}39203921Rect2 last_tab = preview_tabs->get_tab_rect(preview_tabs->get_tab_count() - 1);3922int hsep = preview_tabs->get_theme_constant(SNAME("h_separation"));3923if (preview_tabs->is_layout_rtl()) {3924add_preview_button->set_rect(Rect2(Point2(last_tab.position.x - add_button_size.x - hsep, last_tab.position.y), add_button_size));3925} else {3926add_preview_button->set_rect(Rect2(Point2(last_tab.position.x + last_tab.size.width + hsep, last_tab.position.y), add_button_size));3927}3928}3929}39303931void ThemeEditor::_notification(int p_what) {3932switch (p_what) {3933case NOTIFICATION_READY: {3934connect("closed", callable_mp(this, &ThemeEditor::_dock_closed_cbk));3935EditorNode::get_singleton()->connect("scene_closed", callable_mp(this, &ThemeEditor::_scene_closed));3936EditorNode::get_singleton()->connect("resource_saved", callable_mp(this, &ThemeEditor::_resource_saved));3937FileSystemDock::get_singleton()->connect("files_moved", callable_mp(this, &ThemeEditor::_files_moved));3938} break;39393940case NOTIFICATION_THEME_CHANGED: {3941theme_edit_button->set_button_icon(get_editor_theme_icon(SNAME("Tools")));3942theme_close_button->set_button_icon(get_editor_theme_icon(SNAME("Close")));39433944if (EDITOR_GET("interface/theme/style") == "Classic") {3945preview_tabs->add_theme_style_override("tab_selected", get_theme_stylebox(SNAME("ThemeEditorPreviewFG"), EditorStringName(EditorStyles)));3946preview_tabs->add_theme_style_override("tab_unselected", get_theme_stylebox(SNAME("ThemeEditorPreviewBG"), EditorStringName(EditorStyles)));3947preview_tabs_content->add_theme_style_override(SceneStringName(panel), get_theme_stylebox(SceneStringName(panel), SNAME("TabContainerOdd")));3948}39493950add_preview_button->set_button_icon(get_editor_theme_icon(SNAME("Add")));3951add_preview_button_ph->set_custom_minimum_size(add_preview_button->get_minimum_size());39523953int label_min_width = theme_name->get_minimum_size().x + theme_name->get_character_bounds(0).size.x;3954theme_name->set_custom_minimum_size(Size2(label_min_width, 0));3955} break;39563957case NOTIFICATION_LAYOUT_DIRECTION_CHANGED:3958case NOTIFICATION_TRANSLATION_CHANGED: {3959_preview_tabs_resized();3960} break;3961}3962}39633964void ThemeEditor::save_layout_to_config(Ref<ConfigFile> &p_layout, const String &p_section) const {3965const int split_offset = Math::round(main_hs->get_split_offset() / EDSCALE);3966p_layout->set_value(p_section, "split_offset", split_offset);3967}39683969void ThemeEditor::load_layout_from_config(const Ref<ConfigFile> &p_layout, const String &p_section) {3970if (p_layout->has_section_key(p_section, "split_offset")) {3971const int split_offset = p_layout->get_value(p_section, "split_offset");3972main_hs->set_split_offset(split_offset * EDSCALE);3973}3974}39753976ThemeEditor::ThemeEditor() {3977set_name(TTRC("Theme"));3978set_icon_name("ThemeDock");3979set_dock_shortcut(ED_SHORTCUT_AND_COMMAND("bottom_panels/toggle_theme_bottom_panel", TTRC("Toggle Theme Dock")));3980set_default_slot(EditorDock::DOCK_SLOT_BOTTOM);3981set_available_layouts(EditorDock::DOCK_LAYOUT_HORIZONTAL | EditorDock::DOCK_LAYOUT_FLOATING);3982set_global(false);3983set_transient(true);3984set_closable(true);3985set_custom_minimum_size(Size2(0, 200 * EDSCALE));39863987VBoxContainer *content_vb = memnew(VBoxContainer);3988add_child(content_vb);39893990HBoxContainer *top_menu = memnew(HBoxContainer);3991content_vb->add_child(top_menu);39923993Label *theme_label = memnew(Label);3994theme_label->set_text(TTRC("Theme:"));3995top_menu->add_child(theme_label);39963997theme_name = memnew(Label);3998theme_name->set_text_overrun_behavior(TextServer::OVERRUN_TRIM_ELLIPSIS);3999theme_name->set_theme_type_variation("HeaderSmall");4000theme_name->set_h_size_flags(Control::SIZE_EXPAND_FILL);4001theme_name->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED);4002theme_name->set_mouse_filter(Control::MOUSE_FILTER_PASS);4003top_menu->add_child(theme_name);40044005theme_edit_button = memnew(Button);4006theme_edit_button->set_text(TTRC("Manage Items..."));4007theme_edit_button->set_tooltip_text(TTRC("Add, remove, organize, and import Theme items."));4008theme_edit_button->set_flat(true);4009theme_edit_button->connect(SceneStringName(pressed), callable_mp(this, &ThemeEditor::_theme_edit_button_cbk));4010top_menu->add_child(theme_edit_button);40114012top_menu->add_child(memnew(VSeparator));40134014Button *theme_save_button = memnew(Button);4015theme_save_button->set_text(TTR("Save"));4016theme_save_button->set_flat(true);4017theme_save_button->connect(SceneStringName(pressed), callable_mp(this, &ThemeEditor::_theme_save_button_cbk).bind(false));4018top_menu->add_child(theme_save_button);40194020Button *theme_save_as_button = memnew(Button);4021theme_save_as_button->set_text(TTR("Save As..."));4022theme_save_as_button->set_flat(true);4023theme_save_as_button->connect(SceneStringName(pressed), callable_mp(this, &ThemeEditor::_theme_save_button_cbk).bind(true));4024top_menu->add_child(theme_save_as_button);40254026top_menu->add_child(memnew(VSeparator));40274028theme_close_button = memnew(Button);4029theme_close_button->set_tooltip_text(TTRC("Close"));4030theme_close_button->set_flat(true);4031theme_close_button->connect(SceneStringName(pressed), callable_mp(this, &ThemeEditor::_theme_close_button_cbk));4032top_menu->add_child(theme_close_button);40334034theme_type_editor = memnew(ThemeTypeEditor);40354036theme_edit_dialog = memnew(ThemeItemEditorDialog(theme_type_editor));4037theme_edit_dialog->hide();4038top_menu->add_child(theme_edit_dialog);40394040main_hs = memnew(HSplitContainer);4041main_hs->set_v_size_flags(SIZE_EXPAND_FILL);4042content_vb->add_child(main_hs);40434044main_hs->set_split_offset(520 * EDSCALE);40454046VBoxContainer *preview_tabs_vb = memnew(VBoxContainer);4047preview_tabs_vb->set_h_size_flags(SIZE_EXPAND_FILL);4048preview_tabs_vb->add_theme_constant_override("separation", 2 * EDSCALE);4049main_hs->add_child(preview_tabs_vb);40504051PanelContainer *tabs_panel = memnew(PanelContainer);4052tabs_panel->set_h_size_flags(SIZE_EXPAND_FILL);4053tabs_panel->set_theme_type_variation("PanelContainerTabbarInner");4054preview_tabs_vb->add_child(tabs_panel);40554056HBoxContainer *preview_tabbar_hb = memnew(HBoxContainer);4057tabs_panel->add_child(preview_tabbar_hb);40584059preview_tabs_content = memnew(PanelContainer);4060preview_tabs_content->set_v_size_flags(SIZE_EXPAND_FILL);4061preview_tabs_content->set_draw_behind_parent(true);4062preview_tabs_vb->add_child(preview_tabs_content);40634064preview_tabs = memnew(TabBar);4065preview_tabs->set_h_size_flags(SIZE_EXPAND_FILL);4066preview_tabs->set_theme_type_variation("TabContainerInner");4067preview_tabbar_hb->add_child(preview_tabs);4068preview_tabs->connect("tab_changed", callable_mp(this, &ThemeEditor::_change_preview_tab));4069preview_tabs->connect("tab_button_pressed", callable_mp(this, &ThemeEditor::_remove_preview_tab));4070preview_tabs->connect(SceneStringName(resized), callable_mp(this, &ThemeEditor::_preview_tabs_resized), CONNECT_DEFERRED);40714072add_preview_button = memnew(Button);4073add_preview_button->set_tooltip_text(TTRC("Add Preview"));4074add_preview_button->set_flat(true);4075preview_tabs->add_child(add_preview_button);4076add_preview_button->connect(SceneStringName(pressed), callable_mp(this, &ThemeEditor::_add_preview_button_cbk));40774078add_preview_button_ph = memnew(Control);4079add_preview_button_ph->set_mouse_filter(Control::MOUSE_FILTER_IGNORE);4080add_preview_button_ph->set_custom_minimum_size(add_preview_button->get_minimum_size());4081preview_tabbar_hb->add_child(add_preview_button_ph);40824083DefaultThemeEditorPreview *default_preview_tab = memnew(DefaultThemeEditorPreview);4084preview_tabs_content->add_child(default_preview_tab);4085default_preview_tab->connect("control_picked", callable_mp(this, &ThemeEditor::_preview_control_picked));4086preview_tabs->add_tab(TTR("Default Preview"));40874088preview_scene_dialog = memnew(EditorFileDialog);4089preview_scene_dialog->set_file_mode(EditorFileDialog::FILE_MODE_OPEN_FILE);4090preview_scene_dialog->set_title(TTR("Select UI Scene:"));4091List<String> ext;4092ResourceLoader::get_recognized_extensions_for_type("PackedScene", &ext);4093for (const String &E : ext) {4094preview_scene_dialog->add_filter("*." + E, TTR("Scene"));4095}4096main_hs->add_child(preview_scene_dialog);4097preview_scene_dialog->connect("file_selected", callable_mp(this, &ThemeEditor::_preview_scene_dialog_cbk));40984099main_hs->add_child(theme_type_editor);4100theme_type_editor->set_custom_minimum_size(Size2(280, 0) * EDSCALE);41014102SET_DRAG_FORWARDING_CD(top_menu, ThemeEditor);4103SET_DRAG_FORWARDING_CD(preview_tabs, ThemeEditor);4104}41054106///////////////////////41074108void ThemeEditorPlugin::edit(Object *p_object) {4109theme_editor->edit(Ref<Theme>(p_object));4110}41114112bool ThemeEditorPlugin::handles(Object *p_object) const {4113return Object::cast_to<Theme>(p_object) != nullptr;4114}41154116void ThemeEditorPlugin::make_visible(bool p_visible) {4117if (p_visible) {4118theme_editor->make_visible();4119} else {4120theme_editor->close();4121}4122}41234124bool ThemeEditorPlugin::can_auto_hide() const {4125return theme_editor->theme.is_null();4126}41274128ThemeEditorPlugin::ThemeEditorPlugin() {4129theme_editor = memnew(ThemeEditor);4130theme_editor->plugin = this;4131EditorDockManager::get_singleton()->add_dock(theme_editor);4132theme_editor->close();4133}413441354136