From 19226d77ed5ac06904e728b29f0a718ee599219b Mon Sep 17 00:00:00 2001 From: Haoyu Qiu Date: Wed, 28 May 2025 09:18:32 +0800 Subject: [PATCH] Improve Variant type menus in the editor --- editor/add_metadata_dialog.cpp | 21 +-- editor/add_metadata_dialog.h | 4 +- editor/connections_dialog.cpp | 21 +-- editor/connections_dialog.h | 5 +- editor/editor_properties.cpp | 40 ++--- editor/editor_properties.h | 5 +- editor/editor_properties_array_dict.cpp | 31 +--- editor/editor_properties_array_dict.h | 5 +- editor/gui/editor_variant_type_selectors.cpp | 179 +++++++++++++++++++ editor/gui/editor_variant_type_selectors.h | 67 +++++++ editor/project_settings_editor.cpp | 16 +- editor/project_settings_editor.h | 3 +- 12 files changed, 297 insertions(+), 100 deletions(-) create mode 100644 editor/gui/editor_variant_type_selectors.cpp create mode 100644 editor/gui/editor_variant_type_selectors.h diff --git a/editor/add_metadata_dialog.cpp b/editor/add_metadata_dialog.cpp index c1e6d80fcc..2950059d40 100644 --- a/editor/add_metadata_dialog.cpp +++ b/editor/add_metadata_dialog.cpp @@ -31,9 +31,9 @@ #include "add_metadata_dialog.h" #include "editor/gui/editor_validation_panel.h" +#include "editor/gui/editor_variant_type_selectors.h" #include "editor/themes/editor_scale.h" #include "scene/gui/line_edit.h" -#include "scene/gui/option_button.h" AddMetadataDialog::AddMetadataDialog() { VBoxContainer *vbc = memnew(VBoxContainer); @@ -49,7 +49,7 @@ AddMetadataDialog::AddMetadataDialog() { hbc->add_child(add_meta_name); hbc->add_child(memnew(Label(TTR("Type:")))); - add_meta_type = memnew(OptionButton); + add_meta_type = memnew(EditorVariantTypeOptionButton); add_meta_type->set_accessibility_name(TTRC("Type:")); hbc->add_child(add_meta_type); @@ -76,19 +76,8 @@ void AddMetadataDialog::_complete_init(const StringName &p_title) { set_title(vformat(TTR("Add Metadata Property for \"%s\""), p_title)); - // Skip if we already completed the initialization. - if (add_meta_type->get_item_count()) { - return; - } - - // Theme icons can be retrieved only the Window has been initialized. - for (int i = 0; i < Variant::VARIANT_MAX; i++) { - if (i == Variant::NIL || i == Variant::RID || i == Variant::CALLABLE || i == Variant::SIGNAL) { - continue; //not editable by inspector. - } - String type = i == Variant::OBJECT ? String("Resource") : Variant::get_type_name(Variant::Type(i)); - - add_meta_type->add_icon_item(get_editor_theme_icon(type), type, i); + if (add_meta_type->get_item_count() == 0) { + add_meta_type->populate({ Variant::NIL }, { { Variant::OBJECT, "Resource" } }); } } @@ -106,7 +95,7 @@ StringName AddMetadataDialog::get_meta_name() { Variant AddMetadataDialog::get_meta_defval() { Variant defval; Callable::CallError ce; - Variant::construct(Variant::Type(add_meta_type->get_selected_id()), defval, nullptr, 0, ce); + Variant::construct(add_meta_type->get_selected_type(), defval, nullptr, 0, ce); return defval; } diff --git a/editor/add_metadata_dialog.h b/editor/add_metadata_dialog.h index a30fbcf0ff..9c100f812d 100644 --- a/editor/add_metadata_dialog.h +++ b/editor/add_metadata_dialog.h @@ -33,8 +33,8 @@ #include "scene/gui/dialogs.h" class EditorValidationPanel; +class EditorVariantTypeOptionButton; class LineEdit; -class OptionButton; class AddMetadataDialog : public ConfirmationDialog { GDCLASS(AddMetadataDialog, ConfirmationDialog); @@ -53,6 +53,6 @@ private: void _complete_init(const StringName &p_label); LineEdit *add_meta_name = nullptr; - OptionButton *add_meta_type = nullptr; + EditorVariantTypeOptionButton *add_meta_type = nullptr; EditorValidationPanel *validation_panel = nullptr; }; diff --git a/editor/connections_dialog.cpp b/editor/connections_dialog.cpp index c8ccde374c..f17eac9da9 100644 --- a/editor/connections_dialog.cpp +++ b/editor/connections_dialog.cpp @@ -39,6 +39,7 @@ #include "editor/editor_settings.h" #include "editor/editor_string_names.h" #include "editor/editor_undo_redo_manager.h" +#include "editor/gui/editor_variant_type_selectors.h" #include "editor/gui/scene_tree_editor.h" #include "editor/node_dock.h" #include "editor/plugins/script_editor_plugin.h" @@ -46,11 +47,11 @@ #include "editor/themes/editor_scale.h" #include "scene/gui/button.h" #include "scene/gui/check_box.h" +#include "scene/gui/check_button.h" #include "scene/gui/flow_container.h" #include "scene/gui/label.h" #include "scene/gui/line_edit.h" #include "scene/gui/margin_container.h" -#include "scene/gui/option_button.h" #include "scene/gui/popup_menu.h" #include "scene/gui/spin_box.h" @@ -209,7 +210,7 @@ void ConnectDialog::_method_selected() { * Adds a new parameter bind to connection. */ void ConnectDialog::_add_bind() { - Variant::Type type = (Variant::Type)type_list->get_item_id(type_list->get_selected()); + Variant::Type type = type_list->get_selected_type(); Variant value; Callable::CallError err; @@ -493,11 +494,6 @@ void ConnectDialog::_notification(int p_what) { [[fallthrough]]; } case NOTIFICATION_THEME_CHANGED: { - for (int i = 0; i < type_list->get_item_count(); i++) { - String type_name = Variant::get_type_name((Variant::Type)type_list->get_item_id(i)); - type_list->set_item_icon(i, get_editor_theme_icon(type_name)); - } - method_search->set_right_icon(get_editor_theme_icon("Search")); open_method_tree->set_button_icon(get_editor_theme_icon("Edit")); } break; @@ -839,18 +835,11 @@ ConnectDialog::ConnectDialog() { HBoxContainer *add_bind_hb = memnew(HBoxContainer); - type_list = memnew(OptionButton); + type_list = memnew(EditorVariantTypeOptionButton); type_list->set_accessibility_name(TTRC("Type")); type_list->set_h_size_flags(Control::SIZE_EXPAND_FILL); + type_list->populate({ Variant::NIL, Variant::OBJECT }); add_bind_hb->add_child(type_list); - for (int i = 0; i < Variant::VARIANT_MAX; i++) { - if (i == Variant::NIL || i == Variant::OBJECT || i == Variant::CALLABLE || i == Variant::SIGNAL || i == Variant::RID) { - // These types can't be constructed or serialized properly, so skip them. - continue; - } - - type_list->add_item(Variant::get_type_name(Variant::Type(i)), i); - } bind_controls.push_back(type_list); Button *add_bind = memnew(Button); diff --git a/editor/connections_dialog.h b/editor/connections_dialog.h index 042e6fe049..ae129b2520 100644 --- a/editor/connections_dialog.h +++ b/editor/connections_dialog.h @@ -30,14 +30,15 @@ #pragma once -#include "scene/gui/check_button.h" #include "scene/gui/dialogs.h" #include "scene/gui/tree.h" class Button; class CheckBox; +class CheckButton; class ConnectDialogBinds; class EditorInspector; +class EditorVariantTypeOptionButton; class Label; class LineEdit; class OptionButton; @@ -133,7 +134,7 @@ private: SpinBox *unbind_count = nullptr; EditorInspector *bind_editor = nullptr; - OptionButton *type_list = nullptr; + EditorVariantTypeOptionButton *type_list = nullptr; CheckBox *deferred = nullptr; CheckBox *one_shot = nullptr; CheckBox *append_source = nullptr; diff --git a/editor/editor_properties.cpp b/editor/editor_properties.cpp index 17fe007364..27a831a50b 100644 --- a/editor/editor_properties.cpp +++ b/editor/editor_properties.cpp @@ -41,6 +41,7 @@ #include "editor/editor_string_names.h" #include "editor/gui/editor_file_dialog.h" #include "editor/gui/editor_spin_slider.h" +#include "editor/gui/editor_variant_type_selectors.h" #include "editor/gui/scene_tree_editor.h" #include "editor/inspector_dock.h" #include "editor/plugins/script_editor_plugin.h" @@ -80,8 +81,20 @@ void EditorPropertyVariant::_change_type(int p_to_type) { emit_changed(get_edited_property(), zero); } +void EditorPropertyVariant::_popup_edit_menu() { + if (change_type == nullptr) { + change_type = memnew(EditorVariantTypePopupMenu(false)); + change_type->connect(SceneStringName(id_pressed), callable_mp(this, &EditorPropertyVariant::_change_type)); + content->add_child(change_type); + } + + Rect2 rect = edit_button->get_screen_rect(); + change_type->set_position(rect.get_end() - Vector2(change_type->get_contents_minimum_size().x, 0)); + change_type->popup(); +} + void EditorPropertyVariant::_set_read_only(bool p_read_only) { - change_type->set_disabled(p_read_only); + edit_button->set_disabled(p_read_only); if (sub_property) { sub_property->set_read_only(p_read_only); } @@ -89,12 +102,7 @@ void EditorPropertyVariant::_set_read_only(bool p_read_only) { void EditorPropertyVariant::_notification(int p_what) { if (p_what == NOTIFICATION_THEME_CHANGED) { - change_type->set_button_icon(get_editor_theme_icon("Edit")); - - PopupMenu *popup = change_type->get_popup(); - for (int i = 0; i < popup->get_item_count(); i++) { - popup->set_item_icon(i, get_editor_theme_icon(Variant::get_type_name(Variant::Type(popup->get_item_id(i))))); - } + edit_button->set_button_icon(get_editor_theme_icon(SNAME("Edit"))); } } @@ -139,19 +147,11 @@ EditorPropertyVariant::EditorPropertyVariant() { content = memnew(HBoxContainer); add_child(content); - change_type = memnew(MenuButton); - change_type->set_flat(false); - - PopupMenu *popup = change_type->get_popup(); - for (int i = 0; i < Variant::VARIANT_MAX; i++) { - if (i == Variant::CALLABLE || i == Variant::SIGNAL || i == Variant::RID) { - // These types can't be constructed or serialized properly, so skip them. - continue; - } - popup->add_item(Variant::get_type_name(Variant::Type(i)), i); - } - popup->connect(SceneStringName(id_pressed), callable_mp(this, &EditorPropertyVariant::_change_type)); - content->add_child(change_type); + edit_button = memnew(Button); + edit_button->set_flat(true); + edit_button->set_accessibility_name(TTRC("Edit")); + edit_button->connect(SceneStringName(pressed), callable_mp(this, &EditorPropertyVariant::_popup_edit_menu)); + content->add_child(edit_button); } ///////////////////// TEXT ///////////////////////// diff --git a/editor/editor_properties.h b/editor/editor_properties.h index 9011071a2d..08adb99e3b 100644 --- a/editor/editor_properties.h +++ b/editor/editor_properties.h @@ -39,6 +39,7 @@ class EditorFileDialog; class EditorLocaleDialog; class EditorResourcePicker; class EditorSpinSlider; +class EditorVariantTypePopupMenu; class MenuButton; class PropertySelector; class SceneTreeDialog; @@ -59,12 +60,14 @@ class EditorPropertyVariant : public EditorProperty { HBoxContainer *content = nullptr; EditorProperty *sub_property = nullptr; - MenuButton *change_type = nullptr; + Button *edit_button = nullptr; + EditorVariantTypePopupMenu *change_type = nullptr; Variant::Type current_type = Variant::VARIANT_MAX; Variant::Type new_type = Variant::VARIANT_MAX; void _change_type(int p_to_type); + void _popup_edit_menu(); protected: virtual void _set_read_only(bool p_read_only) override; diff --git a/editor/editor_properties_array_dict.cpp b/editor/editor_properties_array_dict.cpp index d6bcb5d0f8..9cdee104df 100644 --- a/editor/editor_properties_array_dict.cpp +++ b/editor/editor_properties_array_dict.cpp @@ -39,6 +39,7 @@ #include "editor/editor_settings.h" #include "editor/editor_string_names.h" #include "editor/gui/editor_spin_slider.h" +#include "editor/gui/editor_variant_type_selectors.h" #include "editor/inspector_dock.h" #include "editor/themes/editor_scale.h" #include "scene/gui/button.h" @@ -750,19 +751,6 @@ Node *EditorPropertyArray::get_base_node() { void EditorPropertyArray::_notification(int p_what) { switch (p_what) { case NOTIFICATION_THEME_CHANGED: { - change_type->clear(); - change_type->add_icon_item(get_editor_theme_icon(SNAME("Remove")), TTR("Remove Item"), Variant::VARIANT_MAX); - change_type->add_separator(); - for (int i = 0; i < Variant::VARIANT_MAX; i++) { - if (i == Variant::CALLABLE || i == Variant::SIGNAL || i == Variant::RID) { - // These types can't be constructed or serialized properly, so skip them. - continue; - } - - String type = Variant::get_type_name(Variant::Type(i)); - change_type->add_icon_item(get_editor_theme_icon(type), type, i); - } - if (button_add_item) { button_add_item->set_button_icon(get_editor_theme_icon(SNAME("Add"))); } @@ -977,7 +965,7 @@ EditorPropertyArray::EditorPropertyArray() { add_child(edit); add_focusable(edit); - change_type = memnew(PopupMenu); + change_type = memnew(EditorVariantTypePopupMenu(true)); add_child(change_type); change_type->connect(SceneStringName(id_pressed), callable_mp(this, &EditorPropertyArray::_change_type_menu)); changing_type_index = -1; @@ -1465,19 +1453,6 @@ void EditorPropertyDictionary::_object_id_selected(const StringName &p_property, void EditorPropertyDictionary::_notification(int p_what) { switch (p_what) { case NOTIFICATION_THEME_CHANGED: { - change_type->clear(); - change_type->add_icon_item(get_editor_theme_icon(SNAME("Remove")), TTR("Remove Item"), Variant::VARIANT_MAX); - change_type->add_separator(); - for (int i = 0; i < Variant::VARIANT_MAX; i++) { - if (i == Variant::CALLABLE || i == Variant::SIGNAL || i == Variant::RID) { - // These types can't be constructed or serialized properly, so skip them. - continue; - } - - String type = Variant::get_type_name(Variant::Type(i)); - change_type->add_icon_item(get_editor_theme_icon(type), type, i); - } - if (button_add_item) { button_add_item->set_button_icon(get_editor_theme_icon(SNAME("Add"))); add_panel->add_theme_style_override(SceneStringName(panel), get_theme_stylebox(SNAME("DictionaryAddItem"))); @@ -1532,7 +1507,7 @@ EditorPropertyDictionary::EditorPropertyDictionary() { container = nullptr; button_add_item = nullptr; paginator = nullptr; - change_type = memnew(PopupMenu); + change_type = memnew(EditorVariantTypePopupMenu(true)); add_child(change_type); change_type->connect(SceneStringName(id_pressed), callable_mp(this, &EditorPropertyDictionary::_change_type_menu)); changing_type_index = EditorPropertyDictionaryObject::NOT_CHANGING_TYPE; diff --git a/editor/editor_properties_array_dict.h b/editor/editor_properties_array_dict.h index e826395d8e..3e716eee6d 100644 --- a/editor/editor_properties_array_dict.h +++ b/editor/editor_properties_array_dict.h @@ -35,6 +35,7 @@ class Button; class EditorSpinSlider; +class EditorVariantTypePopupMenu; class MarginContainer; class EditorPropertyArrayObject : public RefCounted { @@ -108,7 +109,7 @@ class EditorPropertyArray : public EditorProperty { } }; - PopupMenu *change_type = nullptr; + EditorVariantTypePopupMenu *change_type = nullptr; bool preview_value = false; int page_length = 20; @@ -221,7 +222,7 @@ class EditorPropertyDictionary : public EditorProperty { } }; - PopupMenu *change_type = nullptr; + EditorVariantTypePopupMenu *change_type = nullptr; bool updating = false; bool preview_value = false; diff --git a/editor/gui/editor_variant_type_selectors.cpp b/editor/gui/editor_variant_type_selectors.cpp new file mode 100644 index 0000000000..31325a7eec --- /dev/null +++ b/editor/gui/editor_variant_type_selectors.cpp @@ -0,0 +1,179 @@ +/**************************************************************************/ +/* editor_variant_type_selectors.cpp */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/**************************************************************************/ + +#include "editor_variant_type_selectors.h" + +struct CompareVariantTypeNames { + bool operator()(const String &p_lhs, const String &p_rhs) const { + // Variant type names should not be empty, but just in case. + DEV_ASSERT(!p_lhs.is_empty() && !p_rhs.is_empty()); + + // Variant type names are ascii strings. + const bool lhs_lower = is_ascii_lower_case(p_lhs[0]); + const bool rhs_lower = is_ascii_lower_case(p_rhs[0]); + if (lhs_lower != rhs_lower) { + // Lowercase types like `int` and `float` come first. + return lhs_lower > rhs_lower; + } + + return p_lhs < p_rhs; + } +}; + +// EditorVariantTypeOptionButton + +void EditorVariantTypeOptionButton::_update_menu_icons() { + for (int i = 0; i < get_item_count(); i++) { + const Variant::Type type = Variant::Type(get_item_id(i)); + const String &type_name = Variant::get_type_name(type); + set_item_icon(i, get_editor_theme_icon(type_name)); + } +} + +void EditorVariantTypeOptionButton::_notification(int p_what) { + switch (p_what) { + case NOTIFICATION_POSTINITIALIZE: { + set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED); + } break; + + case NOTIFICATION_THEME_CHANGED: { + _update_menu_icons(); + } break; + } +} + +Variant::Type EditorVariantTypeOptionButton::get_selected_type() const { + int selected = get_selected(); + if (selected == -1) { + return Variant::NIL; + } + return Variant::Type(get_item_id(selected)); +} + +void EditorVariantTypeOptionButton::populate(const LocalVector &p_disabled_types, const HashMap &p_renames) { + LocalVector names; + HashMap name_to_type; + names.reserve(Variant::VARIANT_MAX); + name_to_type.reserve(Variant::VARIANT_MAX); + + for (int i = 0; i < Variant::VARIANT_MAX; i++) { + const Variant::Type type = Variant::Type(i); + + if (p_disabled_types.has(type) || type == Variant::RID || type == Variant::CALLABLE || type == Variant::SIGNAL) { + continue; + } + + const String &type_name = Variant::get_type_name(type); + const String &display_name = p_renames.has(type) ? p_renames[type] : type_name; + names.push_back(display_name); + name_to_type[display_name] = type; + } + + names.sort_custom(); + + for (const String &name : names) { + add_item(name, name_to_type[name]); + } + + _update_menu_icons(); +} + +// EditorVariantTypeArrayItemMenu + +void EditorVariantTypePopupMenu::_populate() { + if (remove_item) { + add_item(TTRC("Remove Item"), Variant::VARIANT_MAX); + set_item_auto_translate_mode(-1, AUTO_TRANSLATE_MODE_ALWAYS); + add_separator(); + } + + LocalVector names; + names.reserve(Variant::VARIANT_MAX); + + for (int i = 0; i < Variant::VARIANT_MAX; i++) { + const Variant::Type type = Variant::Type(i); + + if (type == Variant::RID || type == Variant::CALLABLE || type == Variant::SIGNAL) { + continue; + } + + names.push_back(Variant::get_type_name(type)); + } + + names.sort_custom(); + + for (const String &name : names) { + add_item(name, Variant::get_type_by_name(name)); + } +} + +void EditorVariantTypePopupMenu::_update_menu_icons() { + if (remove_item) { + set_item_icon(get_item_index(Variant::VARIANT_MAX), get_editor_theme_icon(SNAME("Remove"))); + } + + for (int i = 0; i < get_item_count(); i++) { + int id = get_item_id(i); + + // Skip the Remove Item option and the separator without hardcoding the index. + if (id < 0 || id >= Variant::VARIANT_MAX) { + continue; + } + + const Variant::Type type = Variant::Type(id); + const String &type_name = Variant::get_type_name(type); + set_item_icon(i, get_editor_theme_icon(type_name)); + } +} + +void EditorVariantTypePopupMenu::_notification(int p_what) { + switch (p_what) { + case NOTIFICATION_POSTINITIALIZE: { + set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED); + _populate(); + } break; + + case NOTIFICATION_THEME_CHANGED: { + icons_dirty = true; + } break; + } +} + +void EditorVariantTypePopupMenu::popup(const Rect2i &p_bounds) { + if (icons_dirty) { + _update_menu_icons(); + icons_dirty = false; + } + PopupMenu::popup(p_bounds); +} + +EditorVariantTypePopupMenu::EditorVariantTypePopupMenu(bool p_remove_item) { + remove_item = p_remove_item; +} diff --git a/editor/gui/editor_variant_type_selectors.h b/editor/gui/editor_variant_type_selectors.h new file mode 100644 index 0000000000..9f42dbed07 --- /dev/null +++ b/editor/gui/editor_variant_type_selectors.h @@ -0,0 +1,67 @@ +/**************************************************************************/ +/* editor_variant_type_selectors.h */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/**************************************************************************/ + +#pragma once + +#include "core/variant/variant.h" +#include "scene/gui/option_button.h" +#include "scene/gui/popup_menu.h" + +class EditorVariantTypeOptionButton : public OptionButton { + GDCLASS(EditorVariantTypeOptionButton, OptionButton); + + void _update_menu_icons(); + +protected: + void _notification(int p_what); + +public: + Variant::Type get_selected_type() const; + + void populate(const LocalVector &p_disabled_types, const HashMap &p_renames = {}); +}; + +class EditorVariantTypePopupMenu : public PopupMenu { + GDCLASS(EditorVariantTypePopupMenu, PopupMenu); + + bool remove_item = false; + bool icons_dirty = true; + + void _populate(); + void _update_menu_icons(); + +protected: + void _notification(int p_what); + +public: + virtual void popup(const Rect2i &p_bounds = Rect2i()) override; + + EditorVariantTypePopupMenu(bool p_remove_item); +}; diff --git a/editor/project_settings_editor.cpp b/editor/project_settings_editor.cpp index 1b96c602af..7bb6a72182 100644 --- a/editor/project_settings_editor.cpp +++ b/editor/project_settings_editor.cpp @@ -38,6 +38,7 @@ #include "editor/editor_string_names.h" #include "editor/editor_undo_redo_manager.h" #include "editor/export/editor_export.h" +#include "editor/gui/editor_variant_type_selectors.h" #include "editor/themes/editor_scale.h" #include "scene/gui/check_button.h" #include "servers/movie_writer/movie_writer.h" @@ -132,7 +133,7 @@ void ProjectSettingsEditor::_add_setting() { // Initialize the property with the default value for the given type. Callable::CallError ce; Variant value; - Variant::construct(Variant::Type(type_box->get_selected_id()), value, nullptr, 0, ce); + Variant::construct(type_box->get_selected_type(), value, nullptr, 0, ce); EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Add Project Setting")); @@ -605,16 +606,6 @@ void ProjectSettingsEditor::_update_theme() { restart_container->add_theme_style_override(SceneStringName(panel), get_theme_stylebox(SceneStringName(panel), SNAME("Tree"))); restart_icon->set_texture(get_editor_theme_icon(SNAME("StatusWarning"))); restart_label->add_theme_color_override(SceneStringName(font_color), get_theme_color(SNAME("warning_color"), EditorStringName(Editor))); - - type_box->clear(); - for (int i = 0; i < Variant::VARIANT_MAX; i++) { - if (i == Variant::NIL || i == Variant::OBJECT || i == Variant::CALLABLE || i == Variant::SIGNAL || i == Variant::RID) { - // These types can't be serialized properly, so skip them. - continue; - } - String type = Variant::get_type_name(Variant::Type(i)); - type_box->add_icon_item(get_editor_theme_icon(type), type, i); - } } void ProjectSettingsEditor::_notification(int p_what) { @@ -699,7 +690,8 @@ ProjectSettingsEditor::ProjectSettingsEditor(EditorData *p_data) { feature_box->connect(SceneStringName(item_selected), callable_mp(this, &ProjectSettingsEditor::_feature_selected)); custom_properties->add_child(feature_box); - type_box = memnew(OptionButton); + type_box = memnew(EditorVariantTypeOptionButton); + type_box->populate({ Variant::NIL, Variant::OBJECT }); type_box->set_custom_minimum_size(Size2(120, 0) * EDSCALE); type_box->set_accessibility_name(TTRC("Type")); custom_properties->add_child(type_box); diff --git a/editor/project_settings_editor.h b/editor/project_settings_editor.h index 9506458ea5..b5ae6c5035 100644 --- a/editor/project_settings_editor.h +++ b/editor/project_settings_editor.h @@ -44,6 +44,7 @@ #include "scene/gui/tab_container.h" #include "scene/gui/texture_rect.h" +class EditorVariantTypeOptionButton; class FileSystemDock; class ProjectSettingsEditor : public AcceptDialog { @@ -76,7 +77,7 @@ class ProjectSettingsEditor : public AcceptDialog { HBoxContainer *custom_properties = nullptr; LineEdit *property_box = nullptr; OptionButton *feature_box = nullptr; - OptionButton *type_box = nullptr; + EditorVariantTypeOptionButton *type_box = nullptr; Button *add_button = nullptr; Button *del_button = nullptr;