diff --git a/doc/classes/ColorPalette.xml b/doc/classes/ColorPalette.xml
new file mode 100644
index 000000000000..045d01370b09
--- /dev/null
+++ b/doc/classes/ColorPalette.xml
@@ -0,0 +1,16 @@
+
+
+
+ A resource class for managing a palette of colors, which can be loaded and saved using [ColorPicker].
+
+
+ The [ColorPalette] resource is designed to store and manage a collection of colors. This resource is useful in scenarios where a predefined set of colors is required, such as for creating themes, designing user interfaces, or managing game assets. The built-in [ColorPicker] control can also make use of [ColorPalette] without additional code.
+
+
+
+
+
+ A [PackedColorArray] containing the colors in the palette.
+
+
+
diff --git a/doc/classes/ColorPicker.xml b/doc/classes/ColorPicker.xml
index cf26f917e13e..a11284a8449f 100644
--- a/doc/classes/ColorPicker.xml
+++ b/doc/classes/ColorPicker.xml
@@ -177,6 +177,9 @@
The icon for color preset drop down menu when folded.
+
+ The icon for color preset option menu.
+
The indicator used to signalize that the color value is outside the 0-1 range.
diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp
index d88fb134f162..188f882e9d5b 100644
--- a/editor/editor_node.cpp
+++ b/editor/editor_node.cpp
@@ -3422,6 +3422,11 @@ void EditorNode::_update_file_menu_closed() {
file_menu->set_item_disabled(file_menu->get_item_index(FILE_OPEN_PREV), false);
}
+void EditorNode::_palette_quick_open_dialog() {
+ quick_open_color_palette->popup_dialog({ "ColorPalette" }, palette_file_selected_callback);
+ quick_open_color_palette->set_title(TTR("Quick Open Color Palette..."));
+}
+
void EditorNode::replace_resources_in_object(Object *p_object, const Vector[> &p_source_resources, const Vector][> &p_target_resource) {
List pi;
p_object->get_property_list(&pi);
@@ -3881,6 +3886,10 @@ void EditorNode::setup_color_picker(ColorPicker *p_picker) {
p_picker->set_color_mode((ColorPicker::ColorModeType)default_color_mode);
p_picker->set_picker_shape((ColorPicker::PickerShapeType)picker_shape);
+
+ p_picker->set_quick_open_callback(callable_mp(this, &EditorNode::_palette_quick_open_dialog));
+ p_picker->set_palette_saved_callback(callable_mp(EditorFileSystem::get_singleton(), &EditorFileSystem::update_file));
+ palette_file_selected_callback = callable_mp(p_picker, &ColorPicker::_quick_open_palette_file_selected);
}
bool EditorNode::is_scene_open(const String &p_path) {
@@ -7827,6 +7836,9 @@ EditorNode::EditorNode() {
quick_open_dialog = memnew(EditorQuickOpenDialog);
gui_base->add_child(quick_open_dialog);
+ quick_open_color_palette = memnew(EditorQuickOpenDialog);
+ gui_base->add_child(quick_open_color_palette);
+
_update_recent_scenes();
set_process_shortcut_input(true);
diff --git a/editor/editor_node.h b/editor/editor_node.h
index 696caf857c86..9f56f07503aa 100644
--- a/editor/editor_node.h
+++ b/editor/editor_node.h
@@ -264,6 +264,7 @@ class EditorNode : public Node {
EditorPluginList *editor_plugins_force_input_forwarding = nullptr;
EditorPluginList *editor_plugins_force_over = nullptr;
EditorPluginList *editor_plugins_over = nullptr;
+ EditorQuickOpenDialog *quick_open_color_palette = nullptr;
EditorResourcePreview *resource_preview = nullptr;
EditorSelection *editor_selection = nullptr;
EditorSettingsDialog *editor_settings_dialog = nullptr;
@@ -413,6 +414,7 @@ class EditorNode : public Node {
Timer *editor_layout_save_delay_timer = nullptr;
Timer *scan_changes_timer = nullptr;
Button *distraction_free = nullptr;
+ Callable palette_file_selected_callback;
EditorBottomPanel *bottom_panel = nullptr;
@@ -534,6 +536,7 @@ class EditorNode : public Node {
void _export_as_menu_option(int p_idx);
void _update_file_menu_opened();
void _update_file_menu_closed();
+ void _palette_quick_open_dialog();
void _remove_plugin_from_enabled(const String &p_name);
void _plugin_over_edit(EditorPlugin *p_plugin, Object *p_object);
diff --git a/scene/gui/color_picker.cpp b/scene/gui/color_picker.cpp
index fe4c91cb5696..a53b9dec692c 100644
--- a/scene/gui/color_picker.cpp
+++ b/scene/gui/color_picker.cpp
@@ -34,7 +34,9 @@
#include "core/io/image.h"
#include "core/math/color.h"
#include "scene/gui/color_mode.h"
+#include "scene/gui/file_dialog.h"
#include "scene/gui/margin_container.h"
+#include "scene/resources/color_palette.h"
#include "scene/resources/image_texture.h"
#include "scene/resources/style_box_flat.h"
#include "scene/resources/style_box_texture.h"
@@ -84,6 +86,7 @@ void ColorPicker::_notification(int p_what) {
_update_drop_down_arrow(btn_preset->is_pressed(), btn_preset);
_update_drop_down_arrow(btn_recent_preset->is_pressed(), btn_recent_preset);
btn_add_preset->set_icon(theme_cache.add_preset);
+ menu_btn->set_icon(theme_cache.menu_option);
btn_pick->set_custom_minimum_size(Size2(28 * theme_cache.base_scale, 0));
btn_shape->set_custom_minimum_size(Size2(28 * theme_cache.base_scale, 0));
@@ -499,6 +502,15 @@ void ColorPicker::set_editor_settings(Object *p_editor_settings) {
_update_presets();
_update_recent_presets();
}
+
+void ColorPicker::set_quick_open_callback(const Callable &p_file_selected) {
+ quick_open_callback = p_file_selected;
+}
+
+void ColorPicker::set_palette_saved_callback(const Callable &p_palette_saved) {
+ palette_saved_callback = p_palette_saved;
+}
+
#endif
HSlider *ColorPicker::get_slider(int p_idx) {
@@ -679,16 +691,33 @@ void ColorPicker::_update_presets() {
#ifdef TOOLS_ENABLED
if (editor_settings) {
- // Rebuild swatch color buttons, keeping the add-preset button in the first position.
- for (int i = 1; i < preset_container->get_child_count(); i++) {
- preset_container->get_child(i)->queue_free();
- }
- for (const Color &preset : preset_cache) {
- _add_preset_button(preset_size, preset);
+ String cached_name = editor_settings->call(SNAME("get_project_metadata"), "color_picker", "palette_name", String());
+ bool palette_edited = editor_settings->call(SNAME("get_project_metadata"), "color_picker", "palette_edited", false);
+ if (!cached_name.is_empty()) {
+ palette_name->set_text(cached_name);
+ if (btn_preset->is_pressed() && !presets.is_empty()) {
+ palette_name->show();
+ }
+
+ if (palette_edited) {
+ palette_name->set_text(vformat("%s*", palette_name->get_text().replace("*", "")));
+ palette_name->set_tooltip_text(ETR("The changes to this palette have not been saved to a file."));
+ }
}
- _notification(NOTIFICATION_VISIBILITY_CHANGED);
}
#endif
+
+ // Rebuild swatch color buttons, keeping the add-preset button in the first position.
+ for (int i = 1; i < preset_container->get_child_count(); i++) {
+ preset_container->get_child(i)->queue_free();
+ }
+
+ presets = preset_cache;
+ for (const Color &preset : preset_cache) {
+ _add_preset_button(preset_size, preset);
+ }
+
+ _notification(NOTIFICATION_VISIBILITY_CHANGED);
}
void ColorPicker::_update_recent_presets() {
@@ -797,6 +826,99 @@ void ColorPicker::_add_recent_preset_button(int p_size, const Color &p_color) {
btn_preset_new->connect(SceneStringName(toggled), callable_mp(this, &ColorPicker::_recent_preset_pressed).bind(btn_preset_new));
}
+void ColorPicker::_load_palette() {
+ List extensions;
+ ResourceLoader::get_recognized_extensions_for_type("ColorPalette", &extensions);
+
+ file_dialog->set_title(RTR("Load Color Palette"));
+ file_dialog->clear_filters();
+ for (const String &K : extensions) {
+ file_dialog->add_filter("*." + K);
+ }
+
+ file_dialog->set_file_mode(FileDialog::FILE_MODE_OPEN_FILE);
+ file_dialog->set_current_file("");
+ file_dialog->popup_centered_ratio();
+}
+
+void ColorPicker::_save_palette() {
+ List extensions;
+ ResourceLoader::get_recognized_extensions_for_type("ColorPalette", &extensions);
+
+ file_dialog->set_title(RTR("Save Color Palette"));
+ file_dialog->clear_filters();
+ for (const String &K : extensions) {
+ file_dialog->add_filter("*." + K);
+ }
+
+ file_dialog->set_file_mode(FileDialog::FILE_MODE_SAVE_FILE);
+ file_dialog->set_current_file("new_palette.tres");
+ file_dialog->popup_centered_ratio();
+}
+
+void ColorPicker::_quick_open_palette_file_selected(const String &p_path) {
+ if (!file_dialog) {
+ file_dialog = memnew(FileDialog);
+ add_child(file_dialog, false, INTERNAL_MODE_FRONT);
+ file_dialog->force_parent_owned();
+ file_dialog->connect("file_selected", callable_mp(this, &ColorPicker::_palette_file_selected));
+ file_dialog->set_access(FileDialog::ACCESS_FILESYSTEM);
+ file_dialog->set_current_dir(Engine::get_singleton()->is_editor_hint() ? "res://" : "user://");
+ }
+ file_dialog->set_file_mode(FileDialog::FILE_MODE_OPEN_FILE);
+ _palette_file_selected(p_path);
+}
+
+void ColorPicker::_palette_file_selected(const String &p_path) {
+ switch (file_dialog->get_file_mode()) {
+ case FileDialog::FileMode::FILE_MODE_OPEN_FILE: {
+ Ref palette = ResourceLoader::load(p_path, "", ResourceFormatLoader::CACHE_MODE_IGNORE);
+ ERR_FAIL_COND_MSG(palette.is_null(), vformat("Cannot open color palette file for reading at: %s", p_path));
+ preset_cache.clear();
+ presets.clear();
+
+ PackedColorArray saved_presets = palette->get_colors();
+ for (const Color &saved_preset : saved_presets) {
+ preset_cache.push_back(saved_preset);
+ presets.push_back(saved_preset);
+ }
+
+#ifdef TOOLS_ENABLED
+ if (editor_settings) {
+ const StringName set_project_metadata = SNAME("set_project_metadata");
+ editor_settings->call(set_project_metadata, "color_picker", "presets", saved_presets);
+ editor_settings->call(set_project_metadata, "color_picker", "palette_edited", false);
+ }
+#endif
+ } break;
+ case FileDialog::FileMode::FILE_MODE_SAVE_FILE: {
+ ColorPalette *palette = memnew(ColorPalette);
+ palette->set_colors(get_presets());
+ Error error = ResourceSaver::save(palette, p_path);
+ ERR_FAIL_COND_MSG(error != Error::OK, vformat("Cannot open color palette file for writing at: %s", p_path));
+#ifdef TOOLS_ENABLED
+ if (palette_saved_callback.is_valid()) {
+ palette_saved_callback.call_deferred(p_path);
+ }
+#endif // TOOLS_ENABLED
+ } break;
+ default:
+ break;
+ }
+
+ palette_name->set_text(p_path.get_file().get_basename());
+ palette_name->set_tooltip_text("");
+ palette_name->show();
+ btn_preset->set_pressed(true);
+#ifdef TOOLS_ENABLED
+ if (editor_settings) {
+ editor_settings->call(SNAME("set_project_metadata"), "color_picker", "palette_name", palette_name->get_text());
+ editor_settings->call(SNAME("set_project_metadata"), "color_picker", "palette_edited", false);
+ }
+#endif
+ _update_presets();
+}
+
void ColorPicker::_show_hide_preset(const bool &p_is_btn_pressed, Button *p_btn_preset, Container *p_preset_container) {
if (p_is_btn_pressed) {
p_preset_container->show();
@@ -804,6 +926,11 @@ void ColorPicker::_show_hide_preset(const bool &p_is_btn_pressed, Button *p_btn_
p_preset_container->hide();
}
_update_drop_down_arrow(p_is_btn_pressed, p_btn_preset);
+
+ palette_name->hide();
+ if (btn_preset->is_pressed() && !palette_name->get_text().is_empty()) {
+ palette_name->show();
+ }
}
void ColorPicker::_update_drop_down_arrow(const bool &p_is_btn_pressed, Button *p_btn_preset) {
@@ -880,10 +1007,17 @@ void ColorPicker::add_preset(const Color &p_color) {
_add_preset_button(_get_preset_size(), p_color);
}
+ if (!palette_name->get_text().is_empty()) {
+ palette_name->set_text(vformat("%s*", palette_name->get_text().trim_suffix("*")));
+ palette_name->set_tooltip_text(ETR("The changes to this palette have not been saved to a file."));
+ }
+
#ifdef TOOLS_ENABLED
if (editor_settings) {
PackedColorArray arr_to_save = get_presets();
- editor_settings->call(SNAME("set_project_metadata"), "color_picker", "presets", arr_to_save);
+ const StringName set_project_metadata = SNAME("set_project_metadata");
+ editor_settings->call(set_project_metadata, "color_picker", "presets", arr_to_save);
+ editor_settings->call(set_project_metadata, "color_picker", "palette_edited", true);
}
#endif
}
@@ -924,10 +1058,20 @@ void ColorPicker::erase_preset(const Color &p_color) {
}
}
+ palette_name->set_text(vformat("%s*", palette_name->get_text().replace("*", "")));
+ palette_name->set_tooltip_text(ETR("The changes to this palette have not been saved to a file."));
+ if (presets.is_empty()) {
+ palette_name->set_text("");
+ palette_name->hide();
+ }
+
#ifdef TOOLS_ENABLED
if (editor_settings) {
PackedColorArray arr_to_save = get_presets();
- editor_settings->call(SNAME("set_project_metadata"), "color_picker", "presets", arr_to_save);
+ const StringName set_project_metadata = SNAME("set_project_metadata");
+ editor_settings->call(set_project_metadata, "color_picker", "presets", arr_to_save);
+ editor_settings->call(set_project_metadata, "color_picker", "palette_edited", true);
+ editor_settings->call(set_project_metadata, "color_picker", "palette_name", palette_name->get_text());
}
#endif
}
@@ -1554,6 +1698,97 @@ void ColorPicker::_pick_finished() {
picker_window->hide();
}
+void ColorPicker::_update_menu_items() {
+ if (!options_menu) {
+ options_menu = memnew(PopupMenu);
+ add_child(options_menu, false, INTERNAL_MODE_FRONT);
+ options_menu->force_parent_owned();
+ options_menu->connect("id_pressed", callable_mp(this, &ColorPicker::_options_menu_cbk));
+ }
+
+ options_menu->clear();
+ options_menu->reset_size();
+
+ if (!presets.is_empty()) {
+ options_menu->add_icon_item(get_theme_icon(SNAME("save"), SNAME("FileDialog")), RTR("Save"), static_cast(MenuOption::MENU_SAVE));
+ options_menu->set_item_tooltip(-1, ETR("Save the current color palette to reuse later."));
+ }
+ options_menu->add_icon_item(get_theme_icon(SNAME("load"), SNAME("FileDialog")), RTR("Load"), static_cast(MenuOption::MENU_LOAD));
+ options_menu->set_item_tooltip(-1, ETR("Load existing color palette."));
+
+ if (Engine::get_singleton()->is_editor_hint()) {
+ options_menu->add_icon_item(get_theme_icon(SNAME("load"), SNAME("FileDialog")), RTR("Quick Load"), static_cast(MenuOption::MENU_QUICKLOAD));
+ options_menu->set_item_tooltip(-1, ETR("Load existing color palette."));
+ }
+
+ if (!presets.is_empty()) {
+ options_menu->add_icon_item(get_theme_icon(SNAME("clear"), SNAME("FileDialog")), RTR("Clear"), static_cast(MenuOption::MENU_CLEAR));
+ options_menu->set_item_tooltip(-1, ETR("Clear the currently loaded color palettes in the picker."));
+ }
+}
+
+void ColorPicker::_update_menu() {
+ _update_menu_items();
+ Rect2 gt = menu_btn->get_screen_rect();
+ menu_btn->reset_size();
+ int min_size = menu_btn->get_minimum_size().width;
+ Vector2 popup_pos = gt.get_end() - Vector2(min_size, 0);
+ options_menu->set_position(popup_pos);
+ options_menu->popup();
+}
+
+void ColorPicker::_options_menu_cbk(int p_which) {
+ if (!file_dialog) {
+ file_dialog = memnew(FileDialog);
+ add_child(file_dialog, false, INTERNAL_MODE_FRONT);
+ file_dialog->force_parent_owned();
+ file_dialog->connect("file_selected", callable_mp(this, &ColorPicker::_palette_file_selected));
+ file_dialog->set_access(FileDialog::ACCESS_FILESYSTEM);
+ file_dialog->set_current_dir(Engine::get_singleton()->is_editor_hint() ? "res://" : "user://");
+ }
+
+ MenuOption option = static_cast(p_which);
+ switch (option) {
+ case MenuOption::MENU_SAVE:
+ _save_palette();
+ break;
+ case MenuOption::MENU_LOAD:
+ _load_palette();
+ break;
+
+#ifdef TOOLS_ENABLED
+ case MenuOption::MENU_QUICKLOAD:
+ if (quick_open_callback.is_valid()) {
+ file_dialog->set_file_mode(FileDialog::FILE_MODE_OPEN_FILE);
+ quick_open_callback.call_deferred();
+ }
+ break;
+#endif // TOOLS_ENABLED
+ case MenuOption::MENU_CLEAR: {
+ PackedColorArray colors = get_presets();
+ for (Color c : colors) {
+ erase_preset(c);
+ }
+
+ palette_name->set_text("");
+ palette_name->set_tooltip_text("");
+ btn_preset->set_pressed(false);
+
+#ifdef TOOLS_ENABLED
+ if (editor_settings) {
+ editor_settings->call(SNAME("set_project_metadata"), "color_picker", "palette_name", palette_name->get_text());
+ editor_settings->call(SNAME("set_project_metadata"), "color_picker", "palette_edited", false);
+ }
+#endif // TOOLS_ENABLED
+
+ }
+
+ break;
+ default:
+ break;
+ }
+}
+
void ColorPicker::_pick_button_pressed_legacy() {
if (!is_inside_tree()) {
return;
@@ -1811,6 +2046,7 @@ void ColorPicker::_bind_methods() {
BIND_THEME_ITEM(Theme::DATA_TYPE_CONSTANT, ColorPicker, center_slider_grabbers);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_ICON, ColorPicker, menu_option);
BIND_THEME_ITEM(Theme::DATA_TYPE_ICON, ColorPicker, screen_picker);
BIND_THEME_ITEM(Theme::DATA_TYPE_ICON, ColorPicker, expanded_arrow);
BIND_THEME_ITEM(Theme::DATA_TYPE_ICON, ColorPicker, folded_arrow);
@@ -2008,13 +2244,34 @@ ColorPicker::ColorPicker() {
preset_group.instantiate();
- btn_preset = memnew(Button(ETR("Swatches")));
+ HBoxContainer *palette_box = memnew(HBoxContainer);
+ palette_box->set_h_size_flags(SIZE_EXPAND_FILL);
+ real_vbox->add_child(palette_box);
+
+ btn_preset = memnew(Button);
+ btn_preset->set_text("Swatches");
btn_preset->set_flat(true);
btn_preset->set_toggle_mode(true);
btn_preset->set_focus_mode(FOCUS_NONE);
btn_preset->set_text_alignment(HORIZONTAL_ALIGNMENT_LEFT);
- btn_preset->connect(SceneStringName(toggled), callable_mp(this, &ColorPicker::_show_hide_preset).bind(btn_preset, preset_container));
- real_vbox->add_child(btn_preset);
+ btn_preset->connect("toggled", callable_mp(this, &ColorPicker::_show_hide_preset).bind(btn_preset, preset_container));
+ palette_box->add_child(btn_preset);
+
+ HBoxContainer *padding_box = memnew(HBoxContainer);
+ padding_box->set_h_size_flags(SIZE_EXPAND_FILL);
+ palette_box->add_child(padding_box);
+
+ menu_btn = memnew(Button);
+ menu_btn->set_flat(true);
+ menu_btn->set_tooltip_text(ETR("Show all options available."));
+ menu_btn->set_focus_mode(FOCUS_NONE);
+ menu_btn->connect(SceneStringName(pressed), callable_mp(this, &ColorPicker::_update_menu));
+ palette_box->add_child(menu_btn);
+
+ palette_name = memnew(Label);
+ palette_name->hide();
+ palette_name->set_mouse_filter(MOUSE_FILTER_PASS);
+ real_vbox->add_child(palette_name);
real_vbox->add_child(preset_container);
diff --git a/scene/gui/color_picker.h b/scene/gui/color_picker.h
index ad028584b11b..99d6999a5280 100644
--- a/scene/gui/color_picker.h
+++ b/scene/gui/color_picker.h
@@ -53,6 +53,7 @@ class ColorModeRGB;
class ColorModeHSV;
class ColorModeRAW;
class ColorModeOKHSL;
+class FileDialog;
class ColorPresetButton : public BaseButton {
GDCLASS(ColorPresetButton, BaseButton);
@@ -110,6 +111,13 @@ class ColorPicker : public VBoxContainer {
static const int SLIDER_COUNT = 4;
private:
+ enum class MenuOption {
+ MENU_SAVE,
+ MENU_LOAD,
+ MENU_QUICKLOAD,
+ MENU_CLEAR,
+ };
+
static Ref wheel_shader;
static Ref circle_shader;
static Ref circle_ok_color_shader;
@@ -134,6 +142,9 @@ class ColorPicker : public VBoxContainer {
Label *picker_preview_label = nullptr;
Ref picker_preview_style_box;
Color picker_color;
+ FileDialog *file_dialog = nullptr;
+ Button *menu_btn = nullptr;
+ PopupMenu *options_menu = nullptr;
MarginContainer *internal_margin = nullptr;
Control *uv_edit = nullptr;
@@ -149,6 +160,7 @@ class ColorPicker : public VBoxContainer {
HBoxContainer *recent_preset_hbc = nullptr;
Button *btn_add_preset = nullptr;
Button *btn_pick = nullptr;
+ Label *palette_name = nullptr;
Button *btn_preset = nullptr;
Button *btn_recent_preset = nullptr;
PopupMenu *shape_popup = nullptr;
@@ -164,6 +176,10 @@ class ColorPicker : public VBoxContainer {
ColorPresetButton *selected_recent_preset = nullptr;
Ref preset_group;
Ref recent_preset_group;
+#ifdef TOOLS_ENABLED
+ Callable quick_open_callback;
+ Callable palette_saved_callback;
+#endif // TOOLS_ENABLED
OptionButton *mode_option_button = nullptr;
@@ -226,6 +242,7 @@ class ColorPicker : public VBoxContainer {
bool center_slider_grabbers = true;
+ Ref menu_option;
Ref screen_picker;
Ref expanded_arrow;
Ref folded_arrow;
@@ -279,6 +296,10 @@ class ColorPicker : public VBoxContainer {
void _html_focus_exit();
void _pick_button_pressed();
void _pick_finished();
+ void _update_menu_items();
+ void _update_menu();
+ void _options_menu_cbk(int p_which);
+
// Legacy color picking.
void _pick_button_pressed_legacy();
void _picker_texture_input(const Ref &p_event);
@@ -286,6 +307,8 @@ class ColorPicker : public VBoxContainer {
inline int _get_preset_size();
void _add_preset_button(int p_size, const Color &p_color);
void _add_recent_preset_button(int p_size, const Color &p_color);
+ void _save_palette();
+ void _load_palette();
void _show_hide_preset(const bool &p_is_btn_pressed, Button *p_btn_preset, Container *p_preset_container);
void _update_drop_down_arrow(const bool &p_is_btn_pressed, Button *p_btn_preset);
@@ -305,6 +328,8 @@ class ColorPicker : public VBoxContainer {
public:
#ifdef TOOLS_ENABLED
void set_editor_settings(Object *p_editor_settings);
+ void set_quick_open_callback(const Callable &p_file_selected);
+ void set_palette_saved_callback(const Callable &p_palette_saved);
#endif
HSlider *get_slider(int idx);
Vector get_active_slider_values();
@@ -322,6 +347,8 @@ class ColorPicker : public VBoxContainer {
Color get_pick_color() const;
void set_old_color(const Color &p_color);
Color get_old_color() const;
+ void _quick_open_palette_file_selected(const String &p_path);
+ void _palette_file_selected(const String &p_path);
void set_display_old_color(bool p_enabled);
bool is_displaying_old_color() const;
diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp
index 6b1ce2b4ca7f..73d2ea3ab443 100644
--- a/scene/register_scene_types.cpp
+++ b/scene/register_scene_types.cpp
@@ -113,6 +113,7 @@
#include "scene/resources/bone_map.h"
#include "scene/resources/camera_attributes.h"
#include "scene/resources/camera_texture.h"
+#include "scene/resources/color_palette.h"
#include "scene/resources/compositor.h"
#include "scene/resources/compressed_texture.h"
#include "scene/resources/curve_texture.h"
@@ -961,6 +962,7 @@ void register_scene_types() {
GDREGISTER_CLASS(FontFile);
GDREGISTER_CLASS(FontVariation);
GDREGISTER_CLASS(SystemFont);
+ GDREGISTER_CLASS(ColorPalette);
GDREGISTER_CLASS(Curve);
diff --git a/scene/resources/color_palette.cpp b/scene/resources/color_palette.cpp
new file mode 100644
index 000000000000..7c1faeadfb99
--- /dev/null
+++ b/scene/resources/color_palette.cpp
@@ -0,0 +1,46 @@
+/**************************************************************************/
+/* color_palette.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 "color_palette.h"
+
+void ColorPalette::set_colors(const PackedColorArray &p_colors) {
+ colors = p_colors;
+}
+
+PackedColorArray ColorPalette::get_colors() const {
+ return colors;
+}
+
+void ColorPalette::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_colors", "colors"), &ColorPalette::set_colors);
+ ClassDB::bind_method(D_METHOD("get_colors"), &ColorPalette::get_colors);
+
+ ADD_PROPERTY(PropertyInfo(Variant::PACKED_COLOR_ARRAY, "colors"), "set_colors", "get_colors");
+}
diff --git a/scene/resources/color_palette.h b/scene/resources/color_palette.h
new file mode 100644
index 000000000000..13c5e4bfe500
--- /dev/null
+++ b/scene/resources/color_palette.h
@@ -0,0 +1,50 @@
+/**************************************************************************/
+/* color_palette.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. */
+/**************************************************************************/
+
+#ifndef COLOR_PALETTE_H
+#define COLOR_PALETTE_H
+
+#include "core/io/resource.h"
+
+class ColorPalette : public Resource {
+ GDCLASS(ColorPalette, Resource)
+
+private:
+ PackedColorArray colors;
+
+protected:
+ static void _bind_methods();
+
+public:
+ void set_colors(const PackedColorArray &p_colors);
+ PackedColorArray get_colors() const;
+};
+
+#endif // COLOR_PALETTE_H
diff --git a/scene/theme/default_theme.cpp b/scene/theme/default_theme.cpp
index caf44ac392f6..4c7efabe0615 100644
--- a/scene/theme/default_theme.cpp
+++ b/scene/theme/default_theme.cpp
@@ -684,6 +684,9 @@ void fill_default_theme(Ref &theme, const Ref &default_font, const
// File Dialog
+ theme->set_icon("load", "FileDialog", icons["load"]);
+ theme->set_icon("save", "FileDialog", icons["save"]);
+ theme->set_icon("clear", "FileDialog", icons["clear"]);
theme->set_icon("parent_folder", "FileDialog", icons["folder_up"]);
theme->set_icon("back_folder", "FileDialog", icons["arrow_left"]);
theme->set_icon("forward_folder", "FileDialog", icons["arrow_right"]);
@@ -1020,6 +1023,7 @@ void fill_default_theme(Ref &theme, const Ref &default_font, const
theme->set_constant("label_width", "ColorPicker", Math::round(10 * scale));
theme->set_constant("center_slider_grabbers", "ColorPicker", 1);
+ theme->set_icon("menu_option", "ColorPicker", icons["tabs_menu_hl"]);
theme->set_icon("folded_arrow", "ColorPicker", icons["arrow_right"]);
theme->set_icon("expanded_arrow", "ColorPicker", icons["arrow_down"]);
theme->set_icon("screen_picker", "ColorPicker", icons["color_picker_pipette"]);
diff --git a/scene/theme/icons/clear.svg b/scene/theme/icons/clear.svg
new file mode 100644
index 000000000000..d809d62e4670
--- /dev/null
+++ b/scene/theme/icons/clear.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/scene/theme/icons/load.svg b/scene/theme/icons/load.svg
new file mode 100644
index 000000000000..6f738a8a7e8d
--- /dev/null
+++ b/scene/theme/icons/load.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/scene/theme/icons/save.svg b/scene/theme/icons/save.svg
new file mode 100644
index 000000000000..ab8ffff89c7c
--- /dev/null
+++ b/scene/theme/icons/save.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
]