2014-02-09 22:10:30 -03:00
/**************************************************************************/
/* color_picker.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. */
/**************************************************************************/
2018-01-05 00:50:27 +01:00
2014-02-09 22:10:30 -03:00
# include "color_picker.h"
2023-02-05 17:35:39 +01:00
# include "core/io/image.h"
2025-05-23 12:45:29 +08:00
# include "core/math/expression.h"
2022-05-29 20:47:37 +05:30
# include "scene/gui/color_mode.h"
2024-11-20 23:26:52 +01:00
# include "scene/gui/color_picker_shape.h"
2024-05-18 10:45:16 +07:00
# include "scene/gui/file_dialog.h"
2024-11-22 01:09:24 +01:00
# include "scene/gui/grid_container.h"
# include "scene/gui/label.h"
# include "scene/gui/line_edit.h"
2025-04-18 00:05:49 +03:00
# include "scene/gui/link_button.h"
2024-02-23 15:51:47 +02:00
# include "scene/gui/margin_container.h"
2024-11-22 01:09:24 +01:00
# include "scene/gui/menu_button.h"
2024-02-27 22:19:47 +02:00
# include "scene/gui/panel.h"
2024-11-22 01:09:24 +01:00
# include "scene/gui/popup_menu.h"
# include "scene/gui/slider.h"
# include "scene/gui/spin_box.h"
# include "scene/gui/texture_rect.h"
2024-02-27 22:19:47 +02:00
# include "scene/resources/atlas_texture.h"
2024-05-18 10:45:16 +07:00
# include "scene/resources/color_palette.h"
2023-07-11 22:29:09 +02:00
# include "scene/resources/image_texture.h"
2023-07-14 22:35:39 +02:00
# include "scene/resources/style_box_flat.h"
# include "scene/resources/style_box_texture.h"
2023-09-08 21:00:10 +02:00
# include "scene/theme/theme_db.h"
2022-04-18 11:29:29 -07:00
# include "thirdparty/misc/ok_color_shader.h"
2025-05-23 12:45:29 +08:00
static inline bool is_color_overbright ( const Color & color ) {
return ( color . r > 1.0 ) | | ( color . g > 1.0 ) | | ( color . b > 1.0 ) ;
}
static inline bool is_color_valid_hex ( const Color & color ) {
return ! is_color_overbright ( color ) & & color . r > = 0 & & color . g > = 0 & & color . b > = 0 ;
}
static inline String color_to_string ( const Color & color , bool show_alpha = true , bool force_value_format = false ) {
if ( ! force_value_format & & ! is_color_overbright ( color ) ) {
return " # " + color . to_html ( show_alpha ) ;
}
String t = " ( " + String : : num ( color . r , 3 ) + " , " + String : : num ( color . g , 3 ) + " , " + String : : num ( color . b , 3 ) ;
if ( show_alpha ) {
t + = " , " + String : : num ( color . a , 3 ) + " ) " ;
} else {
t + = " ) " ;
}
return t ;
}
2014-02-09 22:10:30 -03:00
void ColorPicker : : _notification ( int p_what ) {
switch ( p_what ) {
2025-03-21 16:42:23 +02:00
case NOTIFICATION_ACCESSIBILITY_UPDATE : {
RID ae = get_accessibility_element ( ) ;
ERR_FAIL_COND ( ae . is_null ( ) ) ;
DisplayServer : : get_singleton ( ) - > accessibility_update_set_role ( ae , DisplayServer : : AccessibilityRole : : ROLE_COLOR_PICKER ) ;
DisplayServer : : get_singleton ( ) - > accessibility_update_set_color_value ( ae , color ) ;
} break ;
2015-11-21 02:51:42 -03:00
case NOTIFICATION_ENTER_TREE : {
2016-02-01 21:32:47 -03:00
_update_color ( ) ;
2023-04-03 18:01:11 +02:00
} break ;
2025-04-18 00:05:49 +03:00
# ifdef MACOS_ENABLED
case NOTIFICATION_VISIBILITY_CHANGED : {
if ( is_visible_in_tree ( ) ) {
perm_hb - > set_visible ( ! OS : : get_singleton ( ) - > get_granted_permissions ( ) . has ( " macos.permission.RECORD_SCREEN " ) ) ;
}
} break ;
# endif
2024-07-29 23:44:01 +02:00
case NOTIFICATION_READY : {
2025-01-14 15:15:34 +02:00
if ( DisplayServer : : get_singleton ( ) - > has_feature ( DisplayServer : : FEATURE_NATIVE_COLOR_PICKER ) ) {
btn_pick - > set_tooltip_text ( ETR ( " Pick a color from the screen. " ) ) ;
btn_pick - > connect ( SceneStringName ( pressed ) , callable_mp ( this , & ColorPicker : : _pick_button_pressed_native ) ) ;
} else if ( DisplayServer : : get_singleton ( ) - > has_feature ( DisplayServer : : FEATURE_SCREEN_CAPTURE ) & & ! get_tree ( ) - > get_root ( ) - > is_embedding_subwindows ( ) ) {
2025-03-21 16:42:23 +02:00
// FIXME: The embedding check is needed to fix a bug in single-window mode (GH-93718).
2024-07-29 23:44:01 +02:00
btn_pick - > set_tooltip_text ( ETR ( " Pick a color from the screen. " ) ) ;
btn_pick - > connect ( SceneStringName ( pressed ) , callable_mp ( this , & ColorPicker : : _pick_button_pressed ) ) ;
} else {
// On unsupported platforms, use a legacy method for color picking.
btn_pick - > set_tooltip_text ( ETR ( " Pick a color from the application window. " ) ) ;
btn_pick - > connect ( SceneStringName ( pressed ) , callable_mp ( this , & ColorPicker : : _pick_button_pressed_legacy ) ) ;
}
} break ;
2021-10-02 23:07:42 +03:00
case NOTIFICATION_THEME_CHANGED : {
2024-10-09 15:21:47 -07:00
btn_pick - > set_button_icon ( theme_cache . screen_picker ) ;
2022-06-30 17:04:32 +05:30
_update_drop_down_arrow ( btn_preset - > is_pressed ( ) , btn_preset ) ;
_update_drop_down_arrow ( btn_recent_preset - > is_pressed ( ) , btn_recent_preset ) ;
2024-10-09 15:21:47 -07:00
btn_add_preset - > set_button_icon ( theme_cache . add_preset ) ;
2024-05-18 10:45:16 +07:00
menu_btn - > set_button_icon ( theme_cache . menu_option ) ;
2025-04-29 10:42:28 +08:00
btn_mode - > set_button_icon ( theme_cache . menu_option ) ;
2021-10-02 23:07:42 +03:00
2023-04-03 18:01:11 +02:00
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 ) ) ;
btn_mode - > set_custom_minimum_size ( Size2 ( 28 * theme_cache . base_scale , 0 ) ) ;
2022-06-30 17:04:32 +05:30
2024-11-20 23:26:52 +01:00
{
int i = 0 ;
for ( ColorPickerShape * shape : shapes ) {
if ( shape - > is_initialized ) {
shape - > update_theme ( ) ;
2025-09-05 18:04:26 +02:00
for ( Control * c : shape - > controls ) {
c - > queue_redraw ( ) ;
}
2024-11-20 23:26:52 +01:00
}
shape_popup - > set_item_icon ( i , shape - > get_icon ( ) ) ;
i + + ;
}
}
2021-10-02 23:07:42 +03:00
2024-11-20 23:26:52 +01:00
if ( current_shape ! = SHAPE_NONE ) {
2025-06-07 22:30:40 +08:00
btn_shape - > set_button_icon ( shape_popup - > get_item_icon ( get_current_shape_index ( ) ) ) ;
2024-11-20 23:26:52 +01:00
}
2021-10-02 23:07:42 +03:00
2025-06-07 22:30:40 +08:00
for ( int i = 0 ; i < MODE_SLIDER_COUNT ; i + + ) {
2023-04-03 18:01:11 +02:00
labels [ i ] - > set_custom_minimum_size ( Size2 ( theme_cache . label_width , 0 ) ) ;
2022-11-23 14:56:10 +01:00
sliders [ i ] - > add_theme_constant_override ( SNAME ( " center_grabber " ) , theme_cache . center_slider_grabbers ) ;
2020-05-14 16:41:43 +02:00
}
2023-04-03 18:01:11 +02:00
alpha_label - > set_custom_minimum_size ( Size2 ( theme_cache . label_width , 0 ) ) ;
2023-12-11 16:17:45 +01:00
alpha_slider - > add_theme_constant_override ( SNAME ( " center_grabber " ) , theme_cache . center_slider_grabbers ) ;
2025-05-23 12:45:29 +08:00
intensity_label - > set_custom_minimum_size ( Size2 ( theme_cache . label_width , 0 ) ) ;
2023-04-03 18:01:11 +02:00
for ( int i = 0 ; i < MODE_BUTTON_COUNT ; i + + ) {
2023-10-19 18:05:19 +02:00
mode_btns [ i ] - > begin_bulk_theme_override ( ) ;
2024-05-14 09:40:21 +02:00
mode_btns [ i ] - > add_theme_style_override ( SceneStringName ( pressed ) , theme_cache . mode_button_pressed ) ;
2024-05-13 16:56:03 +02:00
mode_btns [ i ] - > add_theme_style_override ( CoreStringName ( normal ) , theme_cache . mode_button_normal ) ;
2024-12-05 11:24:52 +03:00
mode_btns [ i ] - > add_theme_style_override ( SceneStringName ( hover ) , theme_cache . mode_button_hover ) ;
2023-10-19 18:05:19 +02:00
mode_btns [ i ] - > end_bulk_theme_override ( ) ;
2023-04-03 18:01:11 +02:00
}
2023-10-19 18:05:19 +02:00
internal_margin - > begin_bulk_theme_override ( ) ;
2023-06-20 12:47:52 +02:00
internal_margin - > add_theme_constant_override ( SNAME ( " margin_bottom " ) , theme_cache . content_margin ) ;
internal_margin - > add_theme_constant_override ( SNAME ( " margin_left " ) , theme_cache . content_margin ) ;
internal_margin - > add_theme_constant_override ( SNAME ( " margin_right " ) , theme_cache . content_margin ) ;
internal_margin - > add_theme_constant_override ( SNAME ( " margin_top " ) , theme_cache . content_margin ) ;
2023-10-19 18:05:19 +02:00
internal_margin - > end_bulk_theme_override ( ) ;
2023-06-20 12:47:52 +02:00
2023-04-03 18:01:11 +02:00
_reset_sliders_theme ( ) ;
2021-10-02 23:07:42 +03:00
2025-05-23 12:45:29 +08:00
hex_label - > set_custom_minimum_size ( Size2 ( 38 * theme_cache . base_scale , 0 ) ) ;
// Adjust for the width of the "script" icon.
text_type - > set_custom_minimum_size ( Size2 ( 28 * theme_cache . base_scale , 0 ) ) ;
2021-10-02 23:07:42 +03:00
_update_presets ( ) ;
2022-06-30 17:04:32 +05:30
_update_recent_presets ( ) ;
2021-10-02 23:07:42 +03:00
_update_controls ( ) ;
2017-07-04 05:52:45 +07:00
} break ;
2021-10-02 23:07:42 +03:00
2020-03-04 13:36:09 -03:00
case NOTIFICATION_WM_CLOSE_REQUEST : {
2023-02-05 17:35:39 +01:00
if ( picker_window ! = nullptr & & picker_window - > is_visible ( ) ) {
picker_window - > hide ( ) ;
2020-05-14 16:41:43 +02:00
}
2017-06-18 17:16:54 -03:00
} break ;
2023-03-15 23:30:42 +01:00
2024-11-07 13:27:11 +01:00
case NOTIFICATION_FOCUS_ENTER :
case NOTIFICATION_FOCUS_EXIT : {
2024-11-20 23:26:52 +01:00
if ( current_shape ! = SHAPE_NONE ) {
2025-06-07 22:30:40 +08:00
shapes [ get_current_shape_index ( ) ] - > cursor_editing = false ;
2024-11-20 23:26:52 +01:00
}
2024-11-07 13:27:11 +01:00
} break ;
2023-03-15 23:30:42 +01:00
case NOTIFICATION_INTERNAL_PROCESS : {
if ( ! is_picking_color ) {
2024-11-07 13:27:11 +01:00
Input * input = Input : : get_singleton ( ) ;
if ( input - > is_action_just_released ( " ui_left " ) | |
input - > is_action_just_released ( " ui_right " ) | |
input - > is_action_just_released ( " ui_up " ) | |
input - > is_action_just_released ( " ui_down " ) ) {
gamepad_event_delay_ms = DEFAULT_GAMEPAD_EVENT_DELAY_MS ;
2024-11-20 23:26:52 +01:00
if ( current_shape = = SHAPE_NONE ) {
2025-06-07 22:30:40 +08:00
shapes [ get_current_shape_index ( ) ] - > echo_multiplier = 1 ;
2024-11-20 23:26:52 +01:00
}
2024-11-07 13:27:11 +01:00
accept_event ( ) ;
set_process_internal ( false ) ;
return ;
}
2024-11-20 23:26:52 +01:00
if ( current_shape = = SHAPE_NONE ) {
return ;
}
2024-11-07 13:27:11 +01:00
gamepad_event_delay_ms - = get_process_delta_time ( ) ;
if ( gamepad_event_delay_ms < = 0 ) {
gamepad_event_delay_ms = GAMEPAD_EVENT_REPEAT_RATE_MS + gamepad_event_delay_ms ;
// Treat any input from joypad axis as -1, 0, or 1, as the value is added to Vector2i and would be lost.
Vector2 color_change_vector = Vector2 (
input - > is_action_pressed ( " ui_right " ) - input - > is_action_pressed ( " ui_left " ) ,
input - > is_action_pressed ( " ui_down " ) - input - > is_action_pressed ( " ui_up " ) ) ;
2024-11-20 23:26:52 +01:00
2025-06-07 22:30:40 +08:00
shapes [ get_current_shape_index ( ) ] - > update_cursor ( color_change_vector , true ) ;
2024-11-20 23:26:52 +01:00
accept_event ( ) ;
2024-11-07 13:27:11 +01:00
}
2023-03-15 23:30:42 +01:00
return ;
}
2024-02-27 22:19:47 +02:00
DisplayServer * ds = DisplayServer : : get_singleton ( ) ;
Vector2 ofs = ds - > mouse_get_position ( ) ;
2025-01-08 10:32:25 +02:00
Color c = DisplayServer : : get_singleton ( ) - > screen_get_pixel ( ofs ) ;
2024-02-27 22:19:47 +02:00
picker_preview_style_box_color - > set_bg_color ( c ) ;
picker_preview_style_box - > set_bg_color ( c . get_luminance ( ) < 0.5 ? Color ( 1.0f , 1.0f , 1.0f ) : Color ( 0.0f , 0.0f , 0.0f ) ) ;
2025-01-08 10:32:25 +02:00
if ( ds - > has_feature ( DisplayServer : : FEATURE_SCREEN_EXCLUDE_FROM_CAPTURE ) ) {
Ref < Image > zoom_preview_img = ds - > screen_get_image_rect ( Rect2i ( ofs . x - 8 , ofs . y - 8 , 17 , 17 ) ) ;
picker_window - > set_position ( ofs - Vector2 ( 28 , 28 ) ) ;
picker_texture_zoom - > set_texture ( ImageTexture : : create_from_image ( zoom_preview_img ) ) ;
} else {
2025-01-14 00:14:40 +02:00
Size2i screen_size = ds - > screen_get_size ( DisplayServer : : SCREEN_WITH_MOUSE_FOCUS ) ;
Vector2i screen_position = ds - > screen_get_position ( DisplayServer : : SCREEN_WITH_MOUSE_FOCUS ) ;
float ofs_decal_x = ( ofs . x < screen_position . x + screen_size . width - 51 ) ? 8 : - 36 ;
float ofs_decal_y = ( ofs . y < screen_position . y + screen_size . height - 51 ) ? 8 : - 36 ;
picker_window - > set_position ( ofs + Vector2 ( ofs_decal_x , ofs_decal_y ) ) ;
2025-01-08 10:32:25 +02:00
}
2024-02-27 22:19:47 +02:00
set_pick_color ( c ) ;
2024-11-07 13:27:11 +01:00
} break ;
2014-02-09 22:10:30 -03:00
}
}
2023-04-03 18:01:11 +02:00
void ColorPicker : : _update_theme_item_cache ( ) {
VBoxContainer : : _update_theme_item_cache ( ) ;
theme_cache . base_scale = get_theme_default_base_scale ( ) ;
}
2021-05-13 15:51:46 +02:00
void ColorPicker : : init_shaders ( ) {
2021-06-17 16:03:09 -06:00
wheel_shader . instantiate ( ) ;
2021-07-19 08:06:51 +02:00
wheel_shader - > set_code ( R " (
2021-08-18 03:09:22 +02:00
// ColorPicker wheel shader.
2021-07-19 08:06:51 +02:00
shader_type canvas_item ;
2025-01-10 09:55:54 +02:00
uniform float wheel_radius = 0.42 ;
2021-07-19 08:06:51 +02:00
void fragment ( ) {
float x = UV . x - 0.5 ;
float y = UV . y - 0.5 ;
float a = atan ( y , x ) ;
x + = 0.001 ;
y + = 0.001 ;
2025-01-10 09:55:54 +02:00
float b = float ( sqrt ( x * x + y * y ) < 0.5 ) * float ( sqrt ( x * x + y * y ) > wheel_radius ) ;
2021-07-19 08:06:51 +02:00
x - = 0.002 ;
2025-01-10 09:55:54 +02:00
float b2 = float ( sqrt ( x * x + y * y ) < 0.5 ) * float ( sqrt ( x * x + y * y ) > wheel_radius ) ;
2021-07-19 08:06:51 +02:00
y - = 0.002 ;
2025-01-10 09:55:54 +02:00
float b3 = float ( sqrt ( x * x + y * y ) < 0.5 ) * float ( sqrt ( x * x + y * y ) > wheel_radius ) ;
2021-07-19 08:06:51 +02:00
x + = 0.002 ;
2025-01-10 09:55:54 +02:00
float b4 = float ( sqrt ( x * x + y * y ) < 0.5 ) * float ( sqrt ( x * x + y * y ) > wheel_radius ) ;
2021-07-19 08:06:51 +02:00
COLOR = vec4 ( clamp ( ( abs ( fract ( ( ( a - TAU ) / TAU ) + vec3 ( 3.0 , 2.0 , 1.0 ) / 3.0 ) * 6.0 - 3.0 ) - 1.0 ) , 0.0 , 1.0 ) , ( b + b2 + b3 + b4 ) / 4.00 ) ;
}
) " );
2021-05-13 15:51:46 +02:00
2021-06-17 16:03:09 -06:00
circle_shader . instantiate ( ) ;
2021-07-19 08:06:51 +02:00
circle_shader - > set_code ( R " (
2021-08-18 03:09:22 +02:00
// ColorPicker circle shader.
2021-07-19 08:06:51 +02:00
shader_type canvas_item ;
uniform float v = 1.0 ;
void fragment ( ) {
float x = UV . x - 0.5 ;
float y = UV . y - 0.5 ;
float a = atan ( y , x ) ;
x + = 0.001 ;
y + = 0.001 ;
float b = float ( sqrt ( x * x + y * y ) < 0.5 ) ;
x - = 0.002 ;
float b2 = float ( sqrt ( x * x + y * y ) < 0.5 ) ;
y - = 0.002 ;
float b3 = float ( sqrt ( x * x + y * y ) < 0.5 ) ;
x + = 0.002 ;
float b4 = float ( sqrt ( x * x + y * y ) < 0.5 ) ;
COLOR = vec4 ( mix ( vec3 ( 1.0 ) , clamp ( abs ( fract ( vec3 ( ( a - TAU ) / TAU ) + vec3 ( 1.0 , 2.0 / 3.0 , 1.0 / 3.0 ) ) * 6.0 - vec3 ( 3.0 ) ) - vec3 ( 1.0 ) , 0.0 , 1.0 ) , ( ( float ( sqrt ( x * x + y * y ) ) * 2.0 ) ) / 1.0 ) * vec3 ( v ) , ( b + b2 + b3 + b4 ) / 4.00 ) ;
} ) " );
2022-04-18 11:29:29 -07:00
circle_ok_color_shader . instantiate ( ) ;
circle_ok_color_shader - > set_code ( OK_COLOR_SHADER + R " (
2025-06-07 22:30:40 +08:00
// ColorPicker ok color hsl circle shader.
2022-04-18 11:29:29 -07:00
2024-11-20 19:34:31 +08:00
uniform float ok_hsl_l = 1.0 ;
2022-04-18 11:29:29 -07:00
void fragment ( ) {
float x = UV . x - 0.5 ;
float y = UV . y - 0.5 ;
2022-08-01 12:39:55 -07:00
float h = atan ( y , x ) / ( 2.0 * M_PI ) ;
float s = sqrt ( x * x + y * y ) * 2.0 ;
2024-11-20 19:34:31 +08:00
vec3 col = okhsl_to_srgb ( vec3 ( h , s , ok_hsl_l ) ) ;
2022-04-18 11:29:29 -07:00
x + = 0.001 ;
y + = 0.001 ;
float b = float ( sqrt ( x * x + y * y ) < 0.5 ) ;
x - = 0.002 ;
float b2 = float ( sqrt ( x * x + y * y ) < 0.5 ) ;
y - = 0.002 ;
float b3 = float ( sqrt ( x * x + y * y ) < 0.5 ) ;
x + = 0.002 ;
float b4 = float ( sqrt ( x * x + y * y ) < 0.5 ) ;
COLOR = vec4 ( col , ( b + b2 + b3 + b4 ) / 4.00 ) ;
} ) " );
2025-06-07 22:30:40 +08:00
rectangle_ok_color_hs_shader . instantiate ( ) ;
rectangle_ok_color_hs_shader - > set_code ( OK_COLOR_SHADER + R " (
// ColorPicker ok color hs rectangle shader.
uniform float ok_hsl_l = 0.0 ;
void fragment ( ) {
float h = UV . x ;
float s = 1.0 - UV . y ;
vec3 col = okhsl_to_srgb ( vec3 ( h , s , ok_hsl_l ) ) ;
COLOR = vec4 ( col , 1.0 ) ;
} ) " );
rectangle_ok_color_hl_shader . instantiate ( ) ;
rectangle_ok_color_hl_shader - > set_code ( OK_COLOR_SHADER + R " (
// ColorPicker ok color hl rectangle shader.
uniform float ok_hsl_s = 0.0 ;
void fragment ( ) {
float h = UV . x ;
float l = 1.0 - UV . y ;
vec3 col = okhsl_to_srgb ( vec3 ( h , ok_hsl_s , l ) ) ;
COLOR = vec4 ( col , 1.0 ) ;
} ) " );
2021-05-13 15:51:46 +02:00
}
void ColorPicker : : finish_shaders ( ) {
wheel_shader . unref ( ) ;
circle_shader . unref ( ) ;
2022-04-18 11:29:29 -07:00
circle_ok_color_shader . unref ( ) ;
2025-06-07 22:30:40 +08:00
rectangle_ok_color_hs_shader . unref ( ) ;
rectangle_ok_color_hl_shader . unref ( ) ;
2021-05-13 15:51:46 +02:00
}
2016-07-01 10:55:35 -03:00
void ColorPicker : : set_focus_on_line_edit ( ) {
2025-09-03 20:39:18 -03:00
callable_mp ( ( Control * ) c_text , & Control : : grab_focus ) . call_deferred ( false ) ;
2016-07-01 10:55:35 -03:00
}
2024-11-07 13:27:11 +01:00
void ColorPicker : : set_focus_on_picker_shape ( ) {
2025-06-07 22:30:40 +08:00
shapes [ get_current_shape_index ( ) ] - > grab_focus ( ) ;
2024-11-07 13:27:11 +01:00
}
2014-02-09 22:10:30 -03:00
void ColorPicker : : _update_controls ( ) {
2022-05-29 20:47:37 +05:30
int mode_sliders_count = modes [ current_mode ] - > get_slider_count ( ) ;
for ( int i = current_slider_count ; i < mode_sliders_count ; i + + ) {
sliders [ i ] - > show ( ) ;
labels [ i ] - > show ( ) ;
values [ i ] - > show ( ) ;
2019-05-03 19:38:45 +02:00
}
2022-05-29 20:47:37 +05:30
for ( int i = mode_sliders_count ; i < current_slider_count ; i + + ) {
sliders [ i ] - > hide ( ) ;
labels [ i ] - > hide ( ) ;
values [ i ] - > hide ( ) ;
2019-05-03 19:38:45 +02:00
}
2022-05-29 20:47:37 +05:30
current_slider_count = mode_sliders_count ;
2019-05-03 19:38:45 +02:00
2022-05-29 20:47:37 +05:30
for ( int i = 0 ; i < current_slider_count ; i + + ) {
labels [ i ] - > set_text ( modes [ current_mode ] - > get_slider_label ( i ) ) ;
2025-03-21 16:42:23 +02:00
sliders [ i ] - > set_accessibility_name ( modes [ current_mode ] - > get_slider_label ( i ) ) ;
values [ i ] - > set_accessibility_name ( modes [ current_mode ] - > get_slider_label ( i ) ) ;
2021-02-17 12:30:56 +07:00
}
2022-05-29 20:47:37 +05:30
alpha_label - > set_text ( " A " ) ;
2025-03-21 16:42:23 +02:00
alpha_slider - > set_accessibility_name ( ETR ( " Alpha " ) ) ;
alpha_value - > set_accessibility_name ( ETR ( " Alpha " ) ) ;
2022-05-29 20:47:37 +05:30
2025-05-23 12:45:29 +08:00
intensity_label - > set_text ( " I " ) ;
intensity_slider - > set_accessibility_name ( ETR ( " Intensity " ) ) ;
intensity_value - > set_accessibility_name ( ETR ( " Intensity " ) ) ;
2021-02-17 12:30:56 +07:00
2025-05-23 12:45:29 +08:00
alpha_value - > set_visible ( edit_alpha ) ;
alpha_slider - > set_visible ( edit_alpha ) ;
alpha_label - > set_visible ( edit_alpha ) ;
intensity_value - > set_visible ( edit_intensity ) ;
intensity_slider - > set_visible ( edit_intensity ) ;
intensity_label - > set_visible ( edit_intensity ) ;
2021-02-23 17:22:46 +07:00
2024-11-20 23:26:52 +01:00
int i = 0 ;
for ( ColorPickerShape * shape : shapes ) {
2025-06-07 22:30:40 +08:00
bool is_active = get_current_shape_index ( ) = = i ;
2024-11-20 23:26:52 +01:00
i + + ;
if ( ! shape - > is_initialized ) {
if ( is_active ) {
// Controls are initialized on demand, because ColorPicker does not need them all at once.
shape - > initialize_controls ( ) ;
} else {
continue ;
2024-11-07 13:27:11 +01:00
}
2024-11-20 23:26:52 +01:00
}
2024-11-07 13:27:11 +01:00
2024-11-20 23:26:52 +01:00
for ( Control * control : shape - > controls ) {
control - > set_visible ( is_active ) ;
2021-02-23 17:22:46 +07:00
}
}
2024-11-20 23:26:52 +01:00
btn_shape - > set_visible ( current_shape ! = SHAPE_NONE ) ;
2014-02-09 22:10:30 -03:00
}
2025-05-23 12:45:29 +08:00
void ColorPicker : : _set_pick_color ( const Color & p_color , bool p_update_sliders , bool p_calc_intensity ) {
2022-06-30 17:04:32 +05:30
if ( text_changed ) {
add_recent_preset ( color ) ;
text_changed = false ;
}
2014-02-09 22:10:30 -03:00
color = p_color ;
2025-05-23 12:45:29 +08:00
if ( p_calc_intensity ) {
_copy_color_to_normalized_and_intensity ( ) ;
2016-02-05 23:35:15 -03:00
}
2025-05-23 12:45:29 +08:00
_copy_normalized_to_hsv_okhsl ( ) ;
2016-02-01 21:32:47 -03:00
2020-05-14 16:41:43 +02:00
if ( ! is_inside_tree ( ) ) {
2016-02-01 21:32:47 -03:00
return ;
2020-05-14 16:41:43 +02:00
}
2016-02-01 21:32:47 -03:00
2019-05-03 19:38:45 +02:00
_update_color ( p_update_sliders ) ;
2014-02-09 22:10:30 -03:00
}
2019-06-19 14:52:54 +02:00
void ColorPicker : : set_pick_color ( const Color & p_color ) {
2025-05-23 12:45:29 +08:00
_set_pick_color ( p_color , true , true ) ; // Because setters can't have more arguments.
2019-06-19 14:52:54 +02:00
}
2020-01-05 18:01:24 +01:00
void ColorPicker : : set_old_color ( const Color & p_color ) {
old_color = p_color ;
}
void ColorPicker : : set_display_old_color ( bool p_enabled ) {
display_old_color = p_enabled ;
}
bool ColorPicker : : is_displaying_old_color ( ) const {
return display_old_color ;
}
2014-02-09 22:10:30 -03:00
void ColorPicker : : set_edit_alpha ( bool p_show ) {
2022-03-16 15:50:48 +08:00
if ( edit_alpha = = p_show ) {
return ;
}
2014-02-09 22:10:30 -03:00
edit_alpha = p_show ;
_update_controls ( ) ;
2016-02-01 21:32:47 -03:00
2020-05-14 16:41:43 +02:00
if ( ! is_inside_tree ( ) ) {
2016-02-01 21:32:47 -03:00
return ;
2020-05-14 16:41:43 +02:00
}
2016-02-01 21:32:47 -03:00
2014-02-09 22:10:30 -03:00
_update_color ( ) ;
2022-08-13 23:21:24 +02:00
sample - > queue_redraw ( ) ;
2014-02-09 22:10:30 -03:00
}
bool ColorPicker : : is_editing_alpha ( ) const {
return edit_alpha ;
}
2025-05-23 12:45:29 +08:00
void ColorPicker : : set_edit_intensity ( bool p_show ) {
if ( edit_intensity = = p_show ) {
return ;
}
if ( p_show ) {
set_pick_color ( color ) ;
} else {
_normalized_apply_intensity_to_color ( ) ;
color_normalized = color ;
intensity = 0 ;
}
edit_intensity = p_show ;
_update_controls ( ) ;
if ( ! is_inside_tree ( ) ) {
return ;
}
_update_color ( ) ;
sample - > queue_redraw ( ) ;
}
bool ColorPicker : : is_editing_intensity ( ) const {
return edit_intensity ;
}
2023-09-19 10:47:46 +02:00
void ColorPicker : : _slider_drag_started ( ) {
currently_dragging = true ;
}
void ColorPicker : : _slider_value_changed ( ) {
2020-05-14 16:41:43 +02:00
if ( updating ) {
2014-02-09 22:10:30 -03:00
return ;
2020-05-14 16:41:43 +02:00
}
2014-02-09 22:10:30 -03:00
2025-05-23 12:45:29 +08:00
intensity = intensity_value - > get_value ( ) ;
color_normalized = modes [ current_mode ] - > get_color ( ) ;
if ( edit_intensity & & is_color_overbright ( color_normalized ) ) {
modes [ current_mode ] - > _greater_value_inputted ( ) ;
color_normalized = modes [ current_mode ] - > get_color ( ) ;
}
_normalized_apply_intensity_to_color ( ) ;
intensity_value - > set_prefix ( intensity < 0 ? " " : " + " ) ;
2023-07-01 14:17:46 -07:00
modes [ current_mode ] - > _value_changed ( ) ;
2023-06-04 18:22:24 -07:00
2025-05-23 12:45:29 +08:00
_set_pick_color ( color , false , false ) ;
2023-09-19 10:47:46 +02:00
if ( ! deferred_mode_enabled | | ! currently_dragging ) {
emit_signal ( SNAME ( " color_changed " ) , color ) ;
}
}
void ColorPicker : : _slider_drag_ended ( ) {
currently_dragging = false ;
if ( deferred_mode_enabled ) {
emit_signal ( SNAME ( " color_changed " ) , color ) ;
}
2014-02-09 22:10:30 -03:00
}
2022-05-29 20:47:37 +05:30
void ColorPicker : : add_mode ( ColorMode * p_mode ) {
modes . push_back ( p_mode ) ;
}
2024-11-20 23:26:52 +01:00
void ColorPicker : : add_shape ( ColorPickerShape * p_shape ) {
shapes . push_back ( p_shape ) ;
}
2022-05-29 20:47:37 +05:30
void ColorPicker : : create_slider ( GridContainer * gc , int idx ) {
2024-04-18 20:26:56 +02:00
Label * lbl = memnew ( Label ) ;
2022-09-29 12:53:28 +03:00
lbl - > set_v_size_flags ( SIZE_SHRINK_CENTER ) ;
2024-04-18 20:26:56 +02:00
lbl - > set_auto_translate_mode ( AUTO_TRANSLATE_MODE_DISABLED ) ;
2022-09-29 12:53:28 +03:00
gc - > add_child ( lbl ) ;
2022-05-29 20:47:37 +05:30
2022-09-29 12:53:28 +03:00
HSlider * slider = memnew ( HSlider ) ;
slider - > set_v_size_flags ( SIZE_SHRINK_CENTER ) ;
2025-04-23 12:46:50 +03:00
slider - > set_focus_mode ( FOCUS_ACCESSIBILITY ) ;
2022-09-29 12:53:28 +03:00
gc - > add_child ( slider ) ;
2022-05-29 20:47:37 +05:30
2022-09-29 12:53:28 +03:00
SpinBox * val = memnew ( SpinBox ) ;
slider - > share ( val ) ;
2022-10-16 20:37:35 +08:00
val - > set_select_all_on_focus ( true ) ;
2022-09-29 12:53:28 +03:00
gc - > add_child ( val ) ;
2022-06-30 17:04:32 +05:30
2022-09-29 12:53:28 +03:00
LineEdit * vle = val - > get_line_edit ( ) ;
2024-05-14 11:42:00 +02:00
vle - > connect ( SceneStringName ( text_changed ) , callable_mp ( this , & ColorPicker : : _text_changed ) ) ;
2024-05-13 16:56:03 +02:00
vle - > connect ( SceneStringName ( gui_input ) , callable_mp ( this , & ColorPicker : : _line_edit_input ) ) ;
2022-06-30 17:04:32 +05:30
vle - > set_horizontal_alignment ( HORIZONTAL_ALIGNMENT_RIGHT ) ;
2024-05-13 16:56:03 +02:00
val - > connect ( SceneStringName ( gui_input ) , callable_mp ( this , & ColorPicker : : _slider_or_spin_input ) ) ;
2022-05-29 20:47:37 +05:30
2022-09-29 12:53:28 +03:00
slider - > set_h_size_flags ( SIZE_EXPAND_FILL ) ;
2022-05-29 20:47:37 +05:30
2023-09-19 10:47:46 +02:00
slider - > connect ( " drag_started " , callable_mp ( this , & ColorPicker : : _slider_drag_started ) ) ;
2024-05-14 11:42:00 +02:00
slider - > connect ( SceneStringName ( value_changed ) , callable_mp ( this , & ColorPicker : : _slider_value_changed ) . unbind ( 1 ) ) ;
2023-09-19 10:47:46 +02:00
slider - > connect ( " drag_ended " , callable_mp ( this , & ColorPicker : : _slider_drag_ended ) . unbind ( 1 ) ) ;
2025-06-07 22:30:40 +08:00
if ( idx < MODE_SLIDER_COUNT ) {
2025-05-23 12:45:29 +08:00
slider - > connect ( SceneStringName ( draw ) , callable_mp ( this , & ColorPicker : : _slider_draw ) . bind ( idx ) ) ;
} else if ( idx = = SLIDER_ALPHA ) {
slider - > connect ( SceneStringName ( draw ) , callable_mp ( this , & ColorPicker : : _alpha_slider_draw ) ) ;
}
2024-05-13 16:56:03 +02:00
slider - > connect ( SceneStringName ( gui_input ) , callable_mp ( this , & ColorPicker : : _slider_or_spin_input ) ) ;
2022-05-29 20:47:37 +05:30
2025-06-07 22:30:40 +08:00
if ( idx < MODE_SLIDER_COUNT ) {
2022-09-29 12:53:28 +03:00
sliders [ idx ] = slider ;
values [ idx ] = val ;
labels [ idx ] = lbl ;
2025-05-23 12:45:29 +08:00
} else if ( idx = = SLIDER_INTENSITY ) {
intensity_slider = slider ;
intensity_value = val ;
intensity_label = lbl ;
} else if ( idx = = SLIDER_ALPHA ) {
2022-09-29 12:53:28 +03:00
alpha_slider = slider ;
alpha_value = val ;
alpha_label = lbl ;
2022-05-29 20:47:37 +05:30
}
}
2022-10-11 14:57:20 +02:00
# ifdef TOOLS_ENABLED
void ColorPicker : : set_editor_settings ( Object * p_editor_settings ) {
if ( editor_settings ) {
return ;
}
editor_settings = p_editor_settings ;
if ( preset_cache . is_empty ( ) ) {
PackedColorArray saved_presets = editor_settings - > call ( SNAME ( " get_project_metadata " ) , " color_picker " , " presets " , PackedColorArray ( ) ) ;
for ( int i = 0 ; i < saved_presets . size ( ) ; i + + ) {
preset_cache . push_back ( saved_presets [ i ] ) ;
}
}
2024-04-15 15:18:34 +02:00
for ( const Color & preset : preset_cache ) {
presets . push_back ( preset ) ;
2022-10-11 14:57:20 +02:00
}
if ( recent_preset_cache . is_empty ( ) ) {
PackedColorArray saved_recent_presets = editor_settings - > call ( SNAME ( " get_project_metadata " ) , " color_picker " , " recent_presets " , PackedColorArray ( ) ) ;
for ( int i = 0 ; i < saved_recent_presets . size ( ) ; i + + ) {
recent_preset_cache . push_back ( saved_recent_presets [ i ] ) ;
}
}
2024-04-15 15:18:34 +02:00
for ( const Color & preset : recent_preset_cache ) {
recent_presets . push_back ( preset ) ;
2022-10-11 14:57:20 +02:00
}
_update_presets ( ) ;
_update_recent_presets ( ) ;
}
2024-05-18 10:45:16 +07:00
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 ;
}
2022-10-11 14:57:20 +02:00
# endif
2022-09-29 12:53:28 +03:00
HSlider * ColorPicker : : get_slider ( int p_idx ) {
2025-06-07 22:30:40 +08:00
ERR_FAIL_INDEX_V ( p_idx , MODE_MAX , nullptr ) ;
return sliders [ p_idx ] ;
2022-05-29 20:47:37 +05:30
}
Vector < float > ColorPicker : : get_active_slider_values ( ) {
2022-09-29 12:53:28 +03:00
Vector < float > cur_values ;
2022-05-29 20:47:37 +05:30
for ( int i = 0 ; i < current_slider_count ; i + + ) {
2022-09-29 12:53:28 +03:00
cur_values . push_back ( sliders [ i ] - > get_value ( ) ) ;
2022-05-29 20:47:37 +05:30
}
2022-09-29 12:53:28 +03:00
cur_values . push_back ( alpha_slider - > get_value ( ) ) ;
return cur_values ;
2022-05-29 20:47:37 +05:30
}
2025-05-23 12:45:29 +08:00
void ColorPicker : : _copy_normalized_to_hsv_okhsl ( ) {
if ( ! okhsl_cached ) {
ok_hsl_h = color_normalized . get_ok_hsl_h ( ) ;
ok_hsl_s = color_normalized . get_ok_hsl_s ( ) ;
ok_hsl_l = color_normalized . get_ok_hsl_l ( ) ;
}
if ( ! hsv_cached ) {
h = color_normalized . get_h ( ) ;
s = color_normalized . get_s ( ) ;
v = color_normalized . get_v ( ) ;
}
hsv_cached = false ;
okhsl_cached = false ;
2022-08-01 22:54:33 +02:00
}
2025-05-23 12:45:29 +08:00
void ColorPicker : : _copy_hsv_okhsl_to_normalized ( ) {
2025-06-07 22:30:40 +08:00
if ( current_shape ! = SHAPE_NONE & & shapes [ get_current_shape_index ( ) ] - > is_ok_hsl ( ) ) {
2025-05-23 12:45:29 +08:00
color_normalized . set_ok_hsl ( ok_hsl_h , ok_hsl_s , ok_hsl_l , color_normalized . a ) ;
2022-08-01 22:54:33 +02:00
} else {
2025-05-23 12:45:29 +08:00
color_normalized . set_hsv ( h , s , v , color_normalized . a ) ;
}
}
Color ColorPicker : : _color_apply_intensity ( const Color & col ) const {
2025-07-29 12:37:45 +03:00
if ( intensity = = 0.0f ) {
return col ;
}
2025-05-23 12:45:29 +08:00
Color linear_color = col . srgb_to_linear ( ) ;
Color result ;
float multiplier = Math : : pow ( 2 , intensity ) ;
for ( int i = 0 ; i < 3 ; i + + ) {
result . components [ i ] = linear_color . components [ i ] * multiplier ;
2022-08-01 22:54:33 +02:00
}
2025-05-23 12:45:29 +08:00
result . a = col . a ;
return result . linear_to_srgb ( ) ;
}
void ColorPicker : : _normalized_apply_intensity_to_color ( ) {
color = _color_apply_intensity ( color_normalized ) ;
}
void ColorPicker : : _copy_color_to_normalized_and_intensity ( ) {
Color linear_color = color . srgb_to_linear ( ) ;
float multiplier = MAX ( 1 , MAX ( MAX ( linear_color . r , linear_color . g ) , linear_color . b ) ) ;
for ( int i = 0 ; i < 3 ; i + + ) {
color_normalized . components [ i ] = linear_color . components [ i ] / multiplier ;
}
color_normalized . a = linear_color . a ;
color_normalized = color_normalized . linear_to_srgb ( ) ;
intensity = Math : : log2 ( multiplier ) ;
2022-08-01 22:54:33 +02:00
}
2022-06-30 17:04:32 +05:30
void ColorPicker : : _select_from_preset_container ( const Color & p_color ) {
if ( preset_group - > get_pressed_button ( ) ) {
preset_group - > get_pressed_button ( ) - > set_pressed ( false ) ;
}
for ( int i = 1 ; i < preset_container - > get_child_count ( ) ; i + + ) {
ColorPresetButton * current_btn = Object : : cast_to < ColorPresetButton > ( preset_container - > get_child ( i ) ) ;
if ( current_btn & & p_color = = current_btn - > get_preset_color ( ) ) {
current_btn - > set_pressed ( true ) ;
break ;
}
}
}
bool ColorPicker : : _select_from_recent_preset_hbc ( const Color & p_color ) {
for ( int i = 0 ; i < recent_preset_hbc - > get_child_count ( ) ; i + + ) {
ColorPresetButton * current_btn = Object : : cast_to < ColorPresetButton > ( recent_preset_hbc - > get_child ( i ) ) ;
if ( current_btn & & p_color = = current_btn - > get_preset_color ( ) ) {
current_btn - > set_pressed ( true ) ;
return true ;
}
}
return false ;
}
2023-04-03 18:01:11 +02:00
void ColorPicker : : _reset_sliders_theme ( ) {
2022-06-30 17:04:32 +05:30
Ref < StyleBoxFlat > style_box_flat ( memnew ( StyleBoxFlat ) ) ;
2023-04-03 18:01:11 +02:00
style_box_flat - > set_content_margin ( SIDE_TOP , 16 * theme_cache . base_scale ) ;
2022-06-30 17:04:32 +05:30
style_box_flat - > set_bg_color ( Color ( 0.2 , 0.23 , 0.31 ) . lerp ( Color ( 0 , 0 , 0 , 1 ) , 0.3 ) . clamp ( ) ) ;
2023-10-19 18:05:19 +02:00
2025-06-07 22:30:40 +08:00
for ( int i = 0 ; i < MODE_SLIDER_COUNT ; i + + ) {
2023-10-19 18:05:19 +02:00
sliders [ i ] - > begin_bulk_theme_override ( ) ;
2024-11-20 23:26:52 +01:00
sliders [ i ] - > add_theme_icon_override ( SNAME ( " grabber " ) , theme_cache . bar_arrow ) ;
sliders [ i ] - > add_theme_icon_override ( SNAME ( " grabber_highlight " ) , theme_cache . bar_arrow ) ;
sliders [ i ] - > add_theme_constant_override ( SNAME ( " grabber_offset " ) , 8 * theme_cache . base_scale ) ;
2022-06-30 17:04:32 +05:30
if ( ! colorize_sliders ) {
2024-11-20 23:26:52 +01:00
sliders [ i ] - > add_theme_style_override ( SNAME ( " slider " ) , style_box_flat ) ;
2022-06-30 17:04:32 +05:30
}
2023-10-19 18:05:19 +02:00
sliders [ i ] - > end_bulk_theme_override ( ) ;
2022-05-29 20:47:37 +05:30
}
2023-10-19 18:05:19 +02:00
alpha_slider - > begin_bulk_theme_override ( ) ;
2024-11-20 23:26:52 +01:00
alpha_slider - > add_theme_icon_override ( SNAME ( " grabber " ) , theme_cache . bar_arrow ) ;
alpha_slider - > add_theme_icon_override ( SNAME ( " grabber_highlight " ) , theme_cache . bar_arrow ) ;
alpha_slider - > add_theme_constant_override ( SNAME ( " grabber_offset " ) , 8 * theme_cache . base_scale ) ;
2022-06-30 17:04:32 +05:30
if ( ! colorize_sliders ) {
2024-11-20 23:26:52 +01:00
alpha_slider - > add_theme_style_override ( SNAME ( " slider " ) , style_box_flat ) ;
2022-06-30 17:04:32 +05:30
}
2023-10-19 18:05:19 +02:00
alpha_slider - > end_bulk_theme_override ( ) ;
2022-05-29 20:47:37 +05:30
}
2021-06-16 09:43:34 -07:00
void ColorPicker : : _html_submitted ( const String & p_html ) {
2025-05-23 12:45:29 +08:00
if ( updating ) {
2014-02-09 22:10:30 -03:00
return ;
2020-05-14 16:41:43 +02:00
}
2025-05-23 12:45:29 +08:00
Color new_color = color ;
if ( text_is_constructor | | ! is_color_valid_hex ( color ) ) {
Ref < Expression > expr ;
expr . instantiate ( ) ;
Error err = expr - > parse ( p_html ) ;
if ( err = = OK ) {
Variant result = expr - > execute ( Array ( ) , nullptr , false , true ) ;
// This is basically the same as Variant::operator Color(), but remains original color if Color::from_string() fails
if ( result . get_type ( ) = = Variant : : COLOR ) {
new_color = result ;
} else if ( result . get_type ( ) = = Variant : : STRING ) {
new_color = Color : : from_string ( result , color ) ;
} else if ( result . get_type ( ) = = Variant : : INT ) {
new_color = Color : : hex ( result ) ;
}
}
} else {
new_color = Color : : from_string ( p_html . strip_edges ( ) , color ) ;
String html_no_prefix = p_html . strip_edges ( ) . trim_prefix ( " # " ) ;
if ( html_no_prefix . is_valid_hex_number ( false ) ) {
// Convert invalid HTML color codes that software like Figma supports.
if ( html_no_prefix . length ( ) = = 1 ) {
// Turn `#1` into `#111111`.
html_no_prefix = html_no_prefix . repeat ( 6 ) ;
} else if ( html_no_prefix . length ( ) = = 2 ) {
// Turn `#12` into `#121212`.
html_no_prefix = html_no_prefix . repeat ( 3 ) ;
} else if ( html_no_prefix . length ( ) = = 5 ) {
// Turn `#12345` into `#11223344`.
html_no_prefix = html_no_prefix . left ( 4 ) ;
} else if ( html_no_prefix . length ( ) = = 7 ) {
// Turn `#1234567` into `#123456`.
html_no_prefix = html_no_prefix . left ( 6 ) ;
}
2023-11-04 11:09:18 +01:00
}
2025-05-23 12:45:29 +08:00
new_color = Color : : from_string ( html_no_prefix , new_color ) ;
2023-11-04 11:09:18 +01:00
}
2023-04-10 21:06:02 +02:00
2020-05-14 16:41:43 +02:00
if ( ! is_editing_alpha ( ) ) {
2023-12-04 17:19:39 +01:00
new_color . a = color . a ;
2020-05-14 16:41:43 +02:00
}
2016-02-01 21:32:47 -03:00
2025-05-23 12:45:29 +08:00
if ( new_color = = color ) {
2022-09-24 15:43:41 +02:00
return ;
}
2023-12-04 17:19:39 +01:00
color = new_color ;
2020-05-14 16:41:43 +02:00
if ( ! is_inside_tree ( ) ) {
2016-02-01 21:32:47 -03:00
return ;
2020-05-14 16:41:43 +02:00
}
2016-02-01 21:32:47 -03:00
2017-01-14 11:07:57 -03:00
set_pick_color ( color ) ;
2021-07-17 18:22:52 -03:00
emit_signal ( SNAME ( " color_changed " ) , color ) ;
2014-02-09 22:10:30 -03:00
}
2019-05-03 19:38:45 +02:00
void ColorPicker : : _update_color ( bool p_update_sliders ) {
2014-02-09 22:10:30 -03:00
updating = true ;
2019-05-03 19:38:45 +02:00
if ( p_update_sliders ) {
2022-05-29 20:47:37 +05:30
float step = modes [ current_mode ] - > get_slider_step ( ) ;
2023-10-23 18:33:56 +02:00
float spinbox_arrow_step = modes [ current_mode ] - > get_spinbox_arrow_step ( ) ;
2022-05-29 20:47:37 +05:30
for ( int i = 0 ; i < current_slider_count ; i + + ) {
sliders [ i ] - > set_max ( modes [ current_mode ] - > get_slider_max ( i ) ) ;
sliders [ i ] - > set_step ( step ) ;
sliders [ i ] - > set_value ( modes [ current_mode ] - > get_slider_value ( i ) ) ;
2025-01-31 13:56:39 +01:00
values [ i ] - > set_custom_arrow_step ( spinbox_arrow_step ) ;
values [ i ] - > set_allow_greater ( modes [ current_mode ] - > get_allow_greater ( ) ) ;
2016-07-02 20:08:25 -05:00
}
2025-05-23 12:45:29 +08:00
alpha_slider - > set_max ( modes [ current_mode ] - > get_alpha_slider_max ( ) ) ;
2022-05-29 20:47:37 +05:30
alpha_slider - > set_step ( step ) ;
2025-05-23 12:45:29 +08:00
alpha_slider - > set_value ( modes [ current_mode ] - > get_alpha_slider_value ( ) ) ;
intensity_slider - > set_value ( intensity ) ;
intensity_value - > set_prefix ( intensity < 0 ? " " : " + " ) ;
2014-02-09 22:10:30 -03:00
}
2016-07-02 20:08:25 -05:00
_update_text_value ( ) ;
2014-02-09 22:10:30 -03:00
2024-11-20 23:26:52 +01:00
if ( current_shape ! = SHAPE_NONE ) {
2025-06-07 22:30:40 +08:00
for ( Control * control : shapes [ get_current_shape_index ( ) ] - > controls ) {
2024-11-20 23:26:52 +01:00
control - > queue_redraw ( ) ;
}
}
2022-08-13 23:21:24 +02:00
sample - > queue_redraw ( ) ;
2024-11-20 23:26:52 +01:00
2022-05-29 20:47:37 +05:30
for ( int i = 0 ; i < current_slider_count ; i + + ) {
2022-08-13 23:21:24 +02:00
sliders [ i ] - > queue_redraw ( ) ;
2021-02-17 12:30:56 +07:00
}
2022-08-13 23:21:24 +02:00
alpha_slider - > queue_redraw ( ) ;
2014-02-09 22:10:30 -03:00
updating = false ;
2025-03-21 16:42:23 +02:00
queue_accessibility_update ( ) ;
2014-02-09 22:10:30 -03:00
}
2015-12-23 23:17:09 -03:00
void ColorPicker : : _update_presets ( ) {
2021-08-18 02:09:48 +02:00
int preset_size = _get_preset_size ( ) ;
// Only update the preset button size if it has changed.
if ( preset_size ! = prev_preset_size ) {
prev_preset_size = preset_size ;
btn_add_preset - > set_custom_minimum_size ( Size2 ( preset_size , preset_size ) ) ;
for ( int i = 1 ; i < preset_container - > get_child_count ( ) ; i + + ) {
ColorPresetButton * cpb = Object : : cast_to < ColorPresetButton > ( preset_container - > get_child ( i ) ) ;
cpb - > set_custom_minimum_size ( Size2 ( preset_size , preset_size ) ) ;
}
}
2022-06-30 17:04:32 +05:30
# ifdef TOOLS_ENABLED
2022-10-11 14:57:20 +02:00
if ( editor_settings ) {
2024-05-18 10:45:16 +07:00
String cached_name = editor_settings - > call ( SNAME ( " get_project_metadata " ) , " color_picker " , " palette_name " , String ( ) ) ;
palette_path = editor_settings - > call ( SNAME ( " get_project_metadata " ) , " color_picker " , " palette_path " , 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 ) {
2024-05-28 12:55:07 +02:00
palette_name - > set_text ( vformat ( " %s* " , palette_name - > get_text ( ) . remove_char ( ' * ' ) ) ) ;
2025-04-29 10:42:28 +08:00
palette_name - > set_tooltip_text ( TTRC ( " The changes to this palette have not been saved to a file. " ) ) ;
2024-05-18 10:45:16 +07:00
}
2021-08-18 02:09:48 +02:00
}
2022-06-30 17:04:32 +05:30
}
# endif
2024-05-18 10:45:16 +07:00
// 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 ) ;
2022-06-30 17:04:32 +05:30
}
void ColorPicker : : _update_recent_presets ( ) {
# ifdef TOOLS_ENABLED
2022-10-11 14:57:20 +02:00
if ( editor_settings ) {
2022-06-30 17:04:32 +05:30
int recent_preset_count = recent_preset_hbc - > get_child_count ( ) ;
for ( int i = 0 ; i < recent_preset_count ; i + + ) {
memdelete ( recent_preset_hbc - > get_child ( 0 ) ) ;
}
recent_presets . clear ( ) ;
2024-04-15 15:18:34 +02:00
for ( const Color & preset : recent_preset_cache ) {
recent_presets . push_back ( preset ) ;
2022-06-30 17:04:32 +05:30
}
int preset_size = _get_preset_size ( ) ;
2024-04-15 15:18:34 +02:00
for ( const Color & preset : recent_presets ) {
_add_recent_preset_button ( preset_size , preset ) ;
2022-06-30 17:04:32 +05:30
}
2021-08-18 02:09:48 +02:00
_notification ( NOTIFICATION_VISIBILITY_CHANGED ) ;
2017-09-27 14:44:48 -05:00
}
2022-06-30 17:04:32 +05:30
# endif
2015-12-23 23:17:09 -03:00
}
2025-04-29 10:42:28 +08:00
# ifdef TOOLS_ENABLED
2016-01-26 19:10:56 -03:00
void ColorPicker : : _text_type_toggled ( ) {
text_is_constructor = ! text_is_constructor ;
if ( text_is_constructor ) {
2025-05-23 12:45:29 +08:00
hex_label - > set_text ( ETR ( " Expr " ) ) ;
2016-01-26 19:10:56 -03:00
text_type - > set_text ( " " ) ;
2025-05-23 12:45:29 +08:00
text_type - > set_button_icon ( theme_cache . color_script ) ;
2019-01-26 19:07:32 -02:00
2025-05-23 12:45:29 +08:00
c_text - > set_tooltip_text ( RTR ( " Execute an expression as a color. " ) ) ;
2016-01-26 19:10:56 -03:00
} else {
2025-05-23 12:45:29 +08:00
hex_label - > set_text ( ETR ( " Hex " ) ) ;
2016-01-26 19:10:56 -03:00
text_type - > set_text ( " # " ) ;
2024-10-09 15:21:47 -07:00
text_type - > set_button_icon ( nullptr ) ;
2019-01-26 19:07:32 -02:00
2023-12-15 20:56:06 -03:00
c_text - > set_tooltip_text ( ETR ( " Enter a hex code ( \" #ff0000 \" ) or named color ( \" red \" ). " ) ) ;
2016-01-26 19:10:56 -03:00
}
_update_color ( ) ;
}
2025-04-29 10:42:28 +08:00
# endif // TOOLS_ENABLED
2016-01-26 19:10:56 -03:00
2017-01-14 11:07:57 -03:00
Color ColorPicker : : get_pick_color ( ) const {
2014-02-09 22:10:30 -03:00
return color ;
}
2024-02-22 18:01:28 -06:00
Color ColorPicker : : get_old_color ( ) const {
return old_color ;
}
2022-05-29 20:47:37 +05:30
void ColorPicker : : set_picker_shape ( PickerShapeType p_shape ) {
ERR_FAIL_INDEX ( p_shape , SHAPE_MAX ) ;
2022-06-30 17:04:32 +05:30
if ( p_shape = = current_shape ) {
2022-03-16 15:50:48 +08:00
return ;
}
2022-10-21 23:20:28 -04:00
if ( current_shape ! = SHAPE_NONE ) {
2025-06-07 22:30:40 +08:00
shape_popup - > set_item_checked ( get_current_shape_index ( ) , false ) ;
2022-10-21 23:20:28 -04:00
}
if ( p_shape ! = SHAPE_NONE ) {
2025-06-07 22:30:40 +08:00
shape_popup - > set_item_checked ( shape_to_index ( p_shape ) , true ) ;
btn_shape - > set_button_icon ( shape_popup - > get_item_icon ( shape_to_index ( p_shape ) ) ) ;
2022-10-21 23:20:28 -04:00
}
2022-06-30 17:04:32 +05:30
2022-05-29 20:47:37 +05:30
current_shape = p_shape ;
2023-12-13 20:05:20 +00:00
# ifdef TOOLS_ENABLED
if ( editor_settings ) {
editor_settings - > call ( SNAME ( " set_project_metadata " ) , " color_picker " , " picker_shape " , current_shape ) ;
}
# endif
2025-09-01 13:06:44 +03:00
_copy_normalized_to_hsv_okhsl ( ) ;
2021-02-23 17:22:46 +07:00
_update_controls ( ) ;
_update_color ( ) ;
}
ColorPicker : : PickerShapeType ColorPicker : : get_picker_shape ( ) const {
2022-05-29 20:47:37 +05:30
return current_shape ;
2021-02-23 17:22:46 +07:00
}
2021-08-18 02:09:48 +02:00
inline int ColorPicker : : _get_preset_size ( ) {
2023-09-12 15:01:42 +02:00
return ( int ( get_minimum_size ( ) . width ) - ( preset_container - > get_h_separation ( ) * ( PRESET_COLUMN_COUNT - 1 ) ) ) / PRESET_COLUMN_COUNT ;
2021-08-18 02:09:48 +02:00
}
void ColorPicker : : _add_preset_button ( int p_size , const Color & p_color ) {
2025-04-29 10:42:28 +08:00
ColorPresetButton * btn_preset_new = memnew ( ColorPresetButton ( p_color , p_size , false ) ) ;
2023-01-14 03:37:19 +01:00
SET_DRAG_FORWARDING_GCDU ( btn_preset_new , ColorPicker ) ;
2022-09-29 12:53:28 +03:00
btn_preset_new - > set_button_group ( preset_group ) ;
preset_container - > add_child ( btn_preset_new ) ;
btn_preset_new - > set_pressed ( true ) ;
2024-05-13 16:56:03 +02:00
btn_preset_new - > connect ( SceneStringName ( gui_input ) , callable_mp ( this , & ColorPicker : : _preset_input ) . bind ( p_color ) ) ;
2021-08-18 02:09:48 +02:00
}
2022-06-30 17:04:32 +05:30
void ColorPicker : : _add_recent_preset_button ( int p_size , const Color & p_color ) {
2025-04-29 10:42:28 +08:00
ColorPresetButton * btn_preset_new = memnew ( ColorPresetButton ( p_color , p_size , true ) ) ;
2022-09-29 12:53:28 +03:00
btn_preset_new - > set_button_group ( recent_preset_group ) ;
recent_preset_hbc - > add_child ( btn_preset_new ) ;
recent_preset_hbc - > move_child ( btn_preset_new , 0 ) ;
btn_preset_new - > set_pressed ( true ) ;
2024-06-01 13:15:13 +03:00
btn_preset_new - > connect ( SceneStringName ( toggled ) , callable_mp ( this , & ColorPicker : : _recent_preset_pressed ) . bind ( btn_preset_new ) ) ;
2022-06-30 17:04:32 +05:30
}
2024-05-18 10:45:16 +07:00
void ColorPicker : : _load_palette ( ) {
List < String > extensions ;
ResourceLoader : : get_recognized_extensions_for_type ( " ColorPalette " , & extensions ) ;
2025-04-29 10:42:28 +08:00
file_dialog - > set_title ( ETR ( " Load Color Palette " ) ) ;
2024-05-18 10:45:16 +07:00
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 ( bool p_is_save_as ) {
if ( ! p_is_save_as & & ! palette_path . is_empty ( ) ) {
file_dialog - > set_file_mode ( FileDialog : : FILE_MODE_SAVE_FILE ) ;
_palette_file_selected ( palette_path ) ;
return ;
} else {
List < String > extensions ;
ResourceLoader : : get_recognized_extensions_for_type ( " ColorPalette " , & extensions ) ;
2025-04-29 10:42:28 +08:00
file_dialog - > set_title ( ETR ( " Save Color Palette " ) ) ;
2024-05-18 10:45:16 +07:00
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 ( ) ;
}
}
2025-04-29 10:42:28 +08:00
# ifdef TOOLS_ENABLED
2024-05-18 10:45:16 +07:00
void ColorPicker : : _quick_open_palette_file_selected ( const String & p_path ) {
2025-04-29 10:42:28 +08:00
_ensure_file_dialog ( ) ;
2024-05-18 10:45:16 +07:00
file_dialog - > set_file_mode ( FileDialog : : FILE_MODE_OPEN_FILE ) ;
_palette_file_selected ( p_path ) ;
}
2025-06-07 22:30:40 +08:00
GridContainer * ColorPicker : : get_slider_container ( ) {
return slider_gc ;
}
2025-04-29 10:42:28 +08:00
# endif // ifdef TOOLS_ENABLED
2024-05-18 10:45:16 +07:00
void ColorPicker : : _palette_file_selected ( const String & p_path ) {
switch ( file_dialog - > get_file_mode ( ) ) {
case FileDialog : : FileMode : : FILE_MODE_OPEN_FILE : {
Ref < ColorPalette > 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 ( ) ;
palette_path = p_path ;
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_path " , palette_path ) ;
editor_settings - > call ( SNAME ( " set_project_metadata " ) , " color_picker " , " palette_edited " , false ) ;
}
# endif
_update_presets ( ) ;
}
2022-06-30 17:04:32 +05:30
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 ( ) ;
} else {
p_preset_container - > hide ( ) ;
2022-05-29 20:47:37 +05:30
}
2022-06-30 17:04:32 +05:30
_update_drop_down_arrow ( p_is_btn_pressed , p_btn_preset ) ;
2024-05-18 10:45:16 +07:00
palette_name - > hide ( ) ;
if ( btn_preset - > is_pressed ( ) & & ! palette_name - > get_text ( ) . is_empty ( ) ) {
palette_name - > show ( ) ;
}
2022-06-30 17:04:32 +05:30
}
2022-05-29 20:47:37 +05:30
2022-06-30 17:04:32 +05:30
void ColorPicker : : _update_drop_down_arrow ( const bool & p_is_btn_pressed , Button * p_btn_preset ) {
if ( p_is_btn_pressed ) {
2024-10-09 15:21:47 -07:00
p_btn_preset - > set_button_icon ( theme_cache . expanded_arrow ) ;
2022-06-30 17:04:32 +05:30
} else {
2024-10-09 15:21:47 -07:00
p_btn_preset - > set_button_icon ( theme_cache . folded_arrow ) ;
2022-06-30 17:04:32 +05:30
}
}
2022-05-29 20:47:37 +05:30
2022-06-30 17:04:32 +05:30
void ColorPicker : : _set_mode_popup_value ( ColorModeType p_mode ) {
ERR_FAIL_INDEX ( p_mode , MODE_MAX + 1 ) ;
if ( p_mode = = MODE_MAX ) {
set_colorize_sliders ( ! colorize_sliders ) ;
} else {
set_color_mode ( p_mode ) ;
}
}
Variant ColorPicker : : _get_drag_data_fw ( const Point2 & p_point , Control * p_from_control ) {
ColorPresetButton * dragged_preset_button = Object : : cast_to < ColorPresetButton > ( p_from_control ) ;
if ( ! dragged_preset_button ) {
return Variant ( ) ;
}
2025-04-29 10:42:28 +08:00
ColorPresetButton * drag_preview = memnew ( ColorPresetButton ( dragged_preset_button - > get_preset_color ( ) , _get_preset_size ( ) , false ) ) ;
2022-06-30 17:04:32 +05:30
set_drag_preview ( drag_preview ) ;
Dictionary drag_data ;
drag_data [ " type " ] = " color_preset " ;
drag_data [ " color_preset " ] = dragged_preset_button - > get_index ( ) ;
return drag_data ;
}
bool ColorPicker : : _can_drop_data_fw ( const Point2 & p_point , const Variant & p_data , Control * p_from_control ) const {
Dictionary d = p_data ;
if ( ! d . has ( " type " ) | | String ( d [ " type " ] ) ! = " color_preset " ) {
return false ;
}
return true ;
}
void ColorPicker : : _drop_data_fw ( const Point2 & p_point , const Variant & p_data , Control * p_from_control ) {
Dictionary d = p_data ;
if ( ! d . has ( " type " ) ) {
2022-05-29 20:47:37 +05:30
return ;
}
2022-06-30 17:04:32 +05:30
if ( String ( d [ " type " ] ) = = " color_preset " ) {
int preset_from_id = d [ " color_preset " ] ;
int hover_now = p_from_control - > get_index ( ) ;
if ( preset_from_id = = hover_now | | hover_now = = - 1 ) {
return ;
}
preset_container - > move_child ( preset_container - > get_child ( preset_from_id ) , hover_now ) ;
}
2022-05-29 20:47:37 +05:30
}
2025-04-29 10:42:28 +08:00
void ColorPicker : : _ensure_file_dialog ( ) {
if ( file_dialog ) {
return ;
}
file_dialog = memnew ( FileDialog ) ;
file_dialog - > set_mode_overrides_title ( false ) ;
file_dialog - > set_access ( FileDialog : : ACCESS_FILESYSTEM ) ;
file_dialog - > set_current_dir ( Engine : : get_singleton ( ) - > is_editor_hint ( ) ? " res:// " : " user:// " ) ;
add_child ( file_dialog , false , INTERNAL_MODE_FRONT ) ;
file_dialog - > connect ( " file_selected " , callable_mp ( this , & ColorPicker : : _palette_file_selected ) ) ;
}
2015-12-23 23:17:09 -03:00
void ColorPicker : : add_preset ( const Color & p_color ) {
2022-06-30 17:04:32 +05:30
List < Color > : : Element * e = presets . find ( p_color ) ;
if ( e ) {
presets . move_to_back ( e ) ;
2021-08-18 02:09:48 +02:00
2025-09-21 22:17:38 +08:00
for ( int i = 1 ; i < preset_container - > get_child_count ( ) ; i + + ) {
ColorPresetButton * current_btn = Object : : cast_to < ColorPresetButton > ( preset_container - > get_child ( i ) ) ;
if ( current_btn & & p_color = = current_btn - > get_preset_color ( ) ) {
preset_container - > move_child ( current_btn , preset_container - > get_child_count ( ) - 1 ) ;
current_btn - > set_pressed ( true ) ;
break ;
}
}
2015-12-23 23:17:09 -03:00
} else {
presets . push_back ( p_color ) ;
2021-08-18 02:09:48 +02:00
_add_preset_button ( _get_preset_size ( ) , p_color ) ;
2015-12-23 23:17:09 -03:00
}
2018-12-12 21:55:29 +01:00
2025-03-16 10:36:01 +01:00
List < Color > : : Element * cache_e = preset_cache . find ( p_color ) ;
if ( cache_e ) {
preset_cache . move_to_back ( cache_e ) ;
} else {
preset_cache . push_back ( p_color ) ;
}
2024-05-18 10:45:16 +07:00
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. " ) ) ;
}
2018-12-12 21:55:29 +01:00
# ifdef TOOLS_ENABLED
2022-10-11 14:57:20 +02:00
if ( editor_settings ) {
2020-02-17 18:06:54 -03:00
PackedColorArray arr_to_save = get_presets ( ) ;
2024-05-18 10:45:16 +07:00
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 ) ;
2018-12-12 21:55:29 +01:00
}
# endif
2015-12-23 23:17:09 -03:00
}
2022-06-30 17:04:32 +05:30
void ColorPicker : : add_recent_preset ( const Color & p_color ) {
if ( ! _select_from_recent_preset_hbc ( p_color ) ) {
if ( recent_preset_hbc - > get_child_count ( ) > = PRESET_COLUMN_COUNT ) {
recent_preset_cache . pop_front ( ) ;
recent_presets . pop_front ( ) ;
2022-10-24 22:07:02 +01:00
recent_preset_hbc - > get_child ( PRESET_COLUMN_COUNT - 1 ) - > queue_free ( ) ;
2022-06-30 17:04:32 +05:30
}
recent_presets . push_back ( p_color ) ;
recent_preset_cache . push_back ( p_color ) ;
_add_recent_preset_button ( _get_preset_size ( ) , p_color ) ;
}
_select_from_preset_container ( p_color ) ;
# ifdef TOOLS_ENABLED
2022-10-11 14:57:20 +02:00
if ( editor_settings ) {
2022-06-30 17:04:32 +05:30
PackedColorArray arr_to_save = get_recent_presets ( ) ;
2022-10-11 14:57:20 +02:00
editor_settings - > call ( SNAME ( " set_project_metadata " ) , " color_picker " , " recent_presets " , arr_to_save ) ;
2022-06-30 17:04:32 +05:30
}
# endif
}
2018-10-03 16:12:38 +02:00
void ColorPicker : : erase_preset ( const Color & p_color ) {
2022-06-30 17:04:32 +05:30
List < Color > : : Element * e = presets . find ( p_color ) ;
if ( e ) {
presets . erase ( e ) ;
2021-07-07 14:17:44 -04:00
preset_cache . erase ( preset_cache . find ( p_color ) ) ;
2021-08-18 02:09:48 +02:00
// Find preset button to remove.
for ( int i = 1 ; i < preset_container - > get_child_count ( ) ; i + + ) {
ColorPresetButton * current_btn = Object : : cast_to < ColorPresetButton > ( preset_container - > get_child ( i ) ) ;
if ( current_btn & & p_color = = current_btn - > get_preset_color ( ) ) {
2022-10-24 22:07:02 +01:00
current_btn - > queue_free ( ) ;
2024-11-07 13:27:11 +01:00
// Removing focused control loose the focus totally. We focus on previous button to keep it possible to navigate with keyboard/joypad.
Control * focus_target = Object : : cast_to < Control > ( preset_container - > get_child ( i - 1 ) ) ;
focus_target - > grab_focus ( ) ;
2021-08-18 02:09:48 +02:00
break ;
}
}
2018-12-12 21:55:29 +01:00
2024-05-28 12:55:07 +02:00
palette_name - > set_text ( vformat ( " %s* " , palette_name - > get_text ( ) . remove_char ( ' * ' ) ) ) ;
2024-05-18 10:45:16 +07:00
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_path = String ( ) ;
palette_name - > hide ( ) ;
}
2018-12-12 21:55:29 +01:00
# ifdef TOOLS_ENABLED
2022-10-11 14:57:20 +02:00
if ( editor_settings ) {
2020-02-17 18:06:54 -03:00
PackedColorArray arr_to_save = get_presets ( ) ;
2024-05-18 10:45:16 +07:00
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 ( ) ) ;
editor_settings - > call ( set_project_metadata , " color_picker " , " palette_path " , palette_path ) ;
2018-12-12 21:55:29 +01:00
}
# endif
2018-10-03 16:12:38 +02:00
}
}
2022-06-30 17:04:32 +05:30
void ColorPicker : : erase_recent_preset ( const Color & p_color ) {
List < Color > : : Element * e = recent_presets . find ( p_color ) ;
if ( e ) {
recent_presets . erase ( e ) ;
recent_preset_cache . erase ( recent_preset_cache . find ( p_color ) ) ;
// Find recent preset button to remove.
for ( int i = 1 ; i < recent_preset_hbc - > get_child_count ( ) ; i + + ) {
ColorPresetButton * current_btn = Object : : cast_to < ColorPresetButton > ( recent_preset_hbc - > get_child ( i ) ) ;
if ( current_btn & & p_color = = current_btn - > get_preset_color ( ) ) {
2022-10-24 22:07:02 +01:00
current_btn - > queue_free ( ) ;
2022-06-30 17:04:32 +05:30
break ;
}
}
# ifdef TOOLS_ENABLED
2022-10-11 14:57:20 +02:00
if ( editor_settings ) {
2022-06-30 17:04:32 +05:30
PackedColorArray arr_to_save = get_recent_presets ( ) ;
2022-10-11 14:57:20 +02:00
editor_settings - > call ( SNAME ( " set_project_metadata " ) , " color_picker " , " recent_presets " , arr_to_save ) ;
2022-06-30 17:04:32 +05:30
}
# endif
}
}
2020-02-17 18:06:54 -03:00
PackedColorArray ColorPicker : : get_presets ( ) const {
PackedColorArray arr ;
2018-10-03 16:12:38 +02:00
arr . resize ( presets . size ( ) ) ;
2024-04-15 15:18:34 +02:00
int i = 0 ;
for ( List < Color > : : ConstIterator itr = presets . begin ( ) ; itr ! = presets . end ( ) ; + + itr , + + i ) {
arr . set ( i , * itr ) ;
2018-10-03 16:12:38 +02:00
}
return arr ;
}
2022-06-30 17:04:32 +05:30
PackedColorArray ColorPicker : : get_recent_presets ( ) const {
PackedColorArray arr ;
arr . resize ( recent_presets . size ( ) ) ;
2024-04-15 15:18:34 +02:00
int i = 0 ;
for ( List < Color > : : ConstIterator itr = recent_presets . begin ( ) ; itr ! = recent_presets . end ( ) ; + + itr , + + i ) {
arr . set ( i , * itr ) ;
2022-06-30 17:04:32 +05:30
}
return arr ;
}
2022-05-29 20:47:37 +05:30
void ColorPicker : : set_color_mode ( ColorModeType p_mode ) {
ERR_FAIL_INDEX ( p_mode , MODE_MAX ) ;
2022-06-30 17:04:32 +05:30
if ( current_mode = = p_mode ) {
return ;
}
mode_popup - > set_item_checked ( current_mode , false ) ;
mode_popup - > set_item_checked ( p_mode , true ) ;
if ( p_mode < MODE_BUTTON_COUNT ) {
mode_btns [ p_mode ] - > set_pressed ( true ) ;
} else if ( current_mode < MODE_BUTTON_COUNT ) {
mode_btns [ current_mode ] - > set_pressed ( false ) ;
}
current_mode = p_mode ;
2023-12-13 20:05:20 +00:00
# ifdef TOOLS_ENABLED
if ( editor_settings ) {
editor_settings - > call ( SNAME ( " set_project_metadata " ) , " color_picker " , " color_mode " , current_mode ) ;
}
# endif
2022-06-30 17:04:32 +05:30
if ( ! is_inside_tree ( ) ) {
return ;
}
_update_controls ( ) ;
_update_color ( ) ;
2014-02-09 22:10:30 -03:00
}
2022-05-29 20:47:37 +05:30
ColorPicker : : ColorModeType ColorPicker : : get_color_mode ( ) const {
return current_mode ;
2014-02-09 22:10:30 -03:00
}
2022-06-30 17:04:32 +05:30
void ColorPicker : : set_colorize_sliders ( bool p_colorize_sliders ) {
if ( colorize_sliders = = p_colorize_sliders ) {
return ;
}
colorize_sliders = p_colorize_sliders ;
mode_popup - > set_item_checked ( MODE_MAX + 1 , colorize_sliders ) ;
if ( colorize_sliders ) {
Ref < StyleBoxEmpty > style_box_empty ( memnew ( StyleBoxEmpty ) ) ;
2025-06-07 22:30:40 +08:00
for ( int i = 0 ; i < MODE_SLIDER_COUNT ; i + + ) {
2025-05-23 12:45:29 +08:00
sliders [ i ] - > add_theme_style_override ( " slider " , style_box_empty ) ;
2022-06-30 17:04:32 +05:30
}
2025-05-23 12:45:29 +08:00
2022-06-30 17:04:32 +05:30
alpha_slider - > add_theme_style_override ( " slider " , style_box_empty ) ;
} else {
Ref < StyleBoxFlat > style_box_flat ( memnew ( StyleBoxFlat ) ) ;
2023-04-03 18:01:11 +02:00
style_box_flat - > set_content_margin ( SIDE_TOP , 16 * theme_cache . base_scale ) ;
2022-06-30 17:04:32 +05:30
style_box_flat - > set_bg_color ( Color ( 0.2 , 0.23 , 0.31 ) . lerp ( Color ( 0 , 0 , 0 , 1 ) , 0.3 ) . clamp ( ) ) ;
2025-06-07 22:30:40 +08:00
for ( int i = 0 ; i < MODE_SLIDER_COUNT ; i + + ) {
2025-05-23 12:45:29 +08:00
sliders [ i ] - > add_theme_style_override ( " slider " , style_box_flat ) ;
2022-06-30 17:04:32 +05:30
}
2025-05-23 12:45:29 +08:00
2022-06-30 17:04:32 +05:30
alpha_slider - > add_theme_style_override ( " slider " , style_box_flat ) ;
}
}
bool ColorPicker : : is_colorizing_sliders ( ) const {
return colorize_sliders ;
}
2018-05-29 15:21:06 +03:00
void ColorPicker : : set_deferred_mode ( bool p_enabled ) {
deferred_mode_enabled = p_enabled ;
}
bool ColorPicker : : is_deferred_mode ( ) const {
return deferred_mode_enabled ;
}
2016-07-02 20:08:25 -05:00
void ColorPicker : : _update_text_value ( ) {
2025-05-23 12:45:29 +08:00
if ( text_is_constructor | | ! is_color_valid_hex ( color ) ) {
String t = " Color " + color_to_string ( color , edit_alpha & & color . a < 1 , true ) ;
2019-01-26 19:07:32 -02:00
2025-05-23 12:45:29 +08:00
text_type - > set_text ( " " ) ;
text_type - > set_button_icon ( theme_cache . color_script ) ;
text_type - > set_disabled ( ! is_color_valid_hex ( color ) ) ;
hex_label - > set_text ( ETR ( " Expr " ) ) ;
c_text - > set_text ( t ) ;
2025-10-03 23:33:47 +02:00
c_text - > set_tooltip_text ( RTR ( " Execute an expression as a color. " ) ) ;
2025-05-23 12:45:29 +08:00
} else {
text_type - > set_text ( " # " ) ;
text_type - > set_button_icon ( nullptr ) ;
text_type - > set_disabled ( false ) ;
hex_label - > set_text ( ETR ( " Hex " ) ) ;
2019-01-26 19:07:32 -02:00
c_text - > set_text ( color . to_html ( edit_alpha & & color . a < 1 ) ) ;
2025-10-03 23:33:47 +02:00
c_text - > set_tooltip_text ( ETR ( " Enter a hex code ( \" #ff0000 \" ) or named color ( \" red \" ). " ) ) ;
2019-01-26 19:07:32 -02:00
}
2016-07-02 20:08:25 -05:00
}
2021-05-10 16:59:46 +02:00
void ColorPicker : : _sample_input ( const Ref < InputEvent > & p_event ) {
2025-01-17 18:12:36 +02:00
if ( ! display_old_color ) {
return ;
}
2021-05-10 16:59:46 +02:00
const Ref < InputEventMouseButton > mb = p_event ;
2021-08-13 16:31:57 -05:00
if ( mb . is_valid ( ) & & mb - > is_pressed ( ) & & mb - > get_button_index ( ) = = MouseButton : : LEFT ) {
2021-05-10 16:59:46 +02:00
const Rect2 rect_old = Rect2 ( Point2 ( ) , Size2 ( sample - > get_size ( ) . width * 0.5 , sample - > get_size ( ) . height * 0.95 ) ) ;
if ( rect_old . has_point ( mb - > get_position ( ) ) ) {
// Revert to the old color when left-clicking the old color sample.
2022-08-01 22:54:33 +02:00
set_pick_color ( old_color ) ;
2024-11-07 13:27:11 +01:00
sample - > set_focus_mode ( FOCUS_NONE ) ;
2021-07-17 18:22:52 -03:00
emit_signal ( SNAME ( " color_changed " ) , color ) ;
2021-05-10 16:59:46 +02:00
}
}
2024-11-07 13:27:11 +01:00
if ( p_event - > is_action_pressed ( SNAME ( " ui_accept " ) , false , true ) ) {
set_pick_color ( old_color ) ;
emit_signal ( SNAME ( " color_changed " ) , color ) ;
}
2021-05-10 16:59:46 +02:00
}
2015-11-21 02:51:42 -03:00
void ColorPicker : : _sample_draw ( ) {
2020-01-05 18:01:24 +01:00
// Covers the right half of the sample if the old color is being displayed,
// or the whole sample if it's not being displayed.
Rect2 rect_new ;
2024-11-07 13:27:11 +01:00
Rect2 rect_old ;
2020-01-05 18:01:24 +01:00
if ( display_old_color ) {
rect_new = Rect2 ( Point2 ( sample - > get_size ( ) . width * 0.5 , 0 ) , Size2 ( sample - > get_size ( ) . width * 0.5 , sample - > get_size ( ) . height * 0.95 ) ) ;
// Draw both old and new colors for easier comparison (only if spawned from a ColorPickerButton).
2024-11-07 13:27:11 +01:00
rect_old = Rect2 ( Point2 ( ) , Size2 ( sample - > get_size ( ) . width * 0.5 , sample - > get_size ( ) . height * 0.95 ) ) ;
2020-01-05 18:01:24 +01:00
2022-10-28 01:39:28 +02:00
if ( old_color . a < 1.0 ) {
2023-09-12 15:01:42 +02:00
sample - > draw_texture_rect ( theme_cache . sample_bg , rect_old , true ) ;
2020-01-05 18:01:24 +01:00
}
sample - > draw_rect ( rect_old , old_color ) ;
2023-11-06 14:53:52 +01:00
if ( ! old_color . is_equal_approx ( color ) ) {
// Draw a revert indicator to indicate that the old sample can be clicked to revert to this old color.
// Adapt icon color to the background color (taking alpha checkerboard into account) so that it's always visible.
sample - > draw_texture ( theme_cache . sample_revert ,
rect_old . size * 0.5 - theme_cache . sample_revert - > get_size ( ) * 0.5 ,
Math : : lerp ( 0.75f , old_color . get_luminance ( ) , old_color . a ) < 0.455 ? Color ( 1 , 1 , 1 ) : ( Color ( 0.01 , 0.01 , 0.01 ) ) ) ;
2024-11-07 13:27:11 +01:00
sample - > set_focus_mode ( FOCUS_ALL ) ;
} else {
sample - > set_focus_mode ( FOCUS_NONE ) ;
2023-11-06 14:53:52 +01:00
}
2025-05-23 12:45:29 +08:00
if ( is_color_overbright ( color ) ) {
2020-01-05 18:01:24 +01:00
// Draw an indicator to denote that the old color is "overbright" and can't be displayed accurately in the preview.
2023-04-03 18:01:11 +02:00
sample - > draw_texture ( theme_cache . overbright_indicator , Point2 ( ) ) ;
2020-01-05 18:01:24 +01:00
}
} else {
rect_new = Rect2 ( Point2 ( ) , Size2 ( sample - > get_size ( ) . width , sample - > get_size ( ) . height * 0.95 ) ) ;
}
2019-09-27 01:07:41 +02:00
2017-09-27 14:44:48 -05:00
if ( color . a < 1.0 ) {
2023-09-12 15:01:42 +02:00
sample - > draw_texture_rect ( theme_cache . sample_bg , rect_new , true ) ;
2017-09-27 14:44:48 -05:00
}
2019-09-27 01:07:41 +02:00
2020-01-05 18:01:24 +01:00
sample - > draw_rect ( rect_new , color ) ;
2019-09-27 01:07:41 +02:00
2025-09-03 20:39:18 -03:00
if ( display_old_color & & ! old_color . is_equal_approx ( color ) & & sample - > has_focus ( true ) ) {
2024-11-07 13:27:11 +01:00
RID ci = sample - > get_canvas_item ( ) ;
theme_cache . sample_focus - > draw ( ci , rect_old ) ;
}
2025-05-23 12:45:29 +08:00
if ( is_color_overbright ( color ) ) {
2020-01-05 18:01:24 +01:00
// Draw an indicator to denote that the new color is "overbright" and can't be displayed accurately in the preview.
2024-11-20 23:26:52 +01:00
sample - > draw_texture ( theme_cache . overbright_indicator , Point2 ( sample - > get_size ( ) . width * 0.5 , 0 ) ) ;
2015-12-25 17:59:23 -03:00
}
}
2021-02-17 12:30:56 +07:00
void ColorPicker : : _slider_draw ( int p_which ) {
2022-06-30 17:04:32 +05:30
if ( colorize_sliders ) {
modes [ current_mode ] - > slider_draw ( p_which ) ;
}
2021-02-17 12:30:56 +07:00
}
2025-05-23 12:45:29 +08:00
void ColorPicker : : _alpha_slider_draw ( ) {
if ( ! colorize_sliders ) {
return ;
}
Vector < Vector2 > pos ;
pos . resize ( 4 ) ;
Vector < Color > col ;
col . resize ( 4 ) ;
Size2 size = alpha_slider - > get_size ( ) ;
Color left_color ;
Color right_color ;
const real_t margin = 16 * theme_cache . base_scale ;
alpha_slider - > draw_texture_rect ( theme_cache . sample_bg , Rect2 ( Point2 ( 0 , 0 ) , Size2 ( size . x , margin ) ) , true ) ;
left_color = color_normalized ;
left_color . a = 0 ;
right_color = color_normalized ;
right_color . a = 1 ;
col . set ( 0 , left_color ) ;
col . set ( 1 , right_color ) ;
col . set ( 2 , right_color ) ;
col . set ( 3 , left_color ) ;
pos . set ( 0 , Vector2 ( 0 , 0 ) ) ;
pos . set ( 1 , Vector2 ( size . x , 0 ) ) ;
pos . set ( 2 , Vector2 ( size . x , margin ) ) ;
pos . set ( 3 , Vector2 ( 0 , margin ) ) ;
alpha_slider - > draw_polygon ( pos , col ) ;
}
2022-06-30 17:04:32 +05:30
void ColorPicker : : _slider_or_spin_input ( const Ref < InputEvent > & p_event ) {
if ( line_edit_mouse_release ) {
line_edit_mouse_release = false ;
return ;
}
Ref < InputEventMouseButton > bev = p_event ;
if ( bev . is_valid ( ) & & ! bev - > is_pressed ( ) & & bev - > get_button_index ( ) = = MouseButton : : LEFT ) {
add_recent_preset ( color ) ;
}
}
void ColorPicker : : _line_edit_input ( const Ref < InputEvent > & p_event ) {
Ref < InputEventMouseButton > bev = p_event ;
if ( bev . is_valid ( ) & & ! bev - > is_pressed ( ) & & bev - > get_button_index ( ) = = MouseButton : : LEFT ) {
line_edit_mouse_release = true ;
}
}
2021-08-18 02:09:48 +02:00
void ColorPicker : : _preset_input ( const Ref < InputEvent > & p_event , const Color & p_color ) {
2017-08-11 15:10:05 -04:00
Ref < InputEventMouseButton > bev = p_event ;
2017-05-20 12:38:03 -03:00
if ( bev . is_valid ( ) ) {
2021-08-13 16:31:57 -05:00
if ( bev - > is_pressed ( ) & & bev - > get_button_index ( ) = = MouseButton : : LEFT ) {
2021-08-18 02:09:48 +02:00
set_pick_color ( p_color ) ;
2022-06-30 17:04:32 +05:30
add_recent_preset ( color ) ;
2021-08-18 02:09:48 +02:00
emit_signal ( SNAME ( " color_changed " ) , p_color ) ;
2022-10-21 23:20:28 -04:00
} else if ( bev - > is_pressed ( ) & & bev - > get_button_index ( ) = = MouseButton : : RIGHT & & can_add_swatches ) {
2021-08-18 02:09:48 +02:00
erase_preset ( p_color ) ;
emit_signal ( SNAME ( " preset_removed " ) , p_color ) ;
2015-12-23 23:17:09 -03:00
}
2017-05-20 12:38:03 -03:00
}
2024-11-07 13:27:11 +01:00
if ( p_event - > is_action_pressed ( SNAME ( " ui_accept " ) , false , true ) ) {
set_pick_color ( p_color ) ;
add_recent_preset ( color ) ;
emit_signal ( SNAME ( " color_changed " ) , p_color ) ;
} else if ( p_event - > is_action_pressed ( SNAME ( " ui_colorpicker_delete_preset " ) , false , true ) & & can_add_swatches ) {
erase_preset ( p_color ) ;
emit_signal ( SNAME ( " preset_removed " ) , p_color ) ;
}
2015-12-23 23:17:09 -03:00
}
2022-06-30 17:04:32 +05:30
void ColorPicker : : _recent_preset_pressed ( const bool p_pressed , ColorPresetButton * p_preset ) {
if ( ! p_pressed ) {
return ;
}
2025-05-23 12:45:29 +08:00
// Avoid applying and recalculating the intensity for non-overbright color if it doesn't change.
if ( color ! = p_preset - > get_preset_color ( ) ) {
set_pick_color ( p_preset - > get_preset_color ( ) ) ;
}
2022-06-30 17:04:32 +05:30
recent_presets . move_to_back ( recent_presets . find ( p_preset - > get_preset_color ( ) ) ) ;
List < Color > : : Element * e = recent_preset_cache . find ( p_preset - > get_preset_color ( ) ) ;
if ( e ) {
recent_preset_cache . move_to_back ( e ) ;
}
recent_preset_hbc - > move_child ( p_preset , 0 ) ;
emit_signal ( SNAME ( " color_changed " ) , p_preset - > get_preset_color ( ) ) ;
}
void ColorPicker : : _text_changed ( const String & ) {
text_changed = true ;
}
2015-12-23 23:17:09 -03:00
void ColorPicker : : _add_preset_pressed ( ) {
add_preset ( color ) ;
2021-07-17 18:22:52 -03:00
emit_signal ( SNAME ( " preset_added " ) , color ) ;
2014-02-09 22:10:30 -03:00
}
2025-01-14 15:15:34 +02:00
void ColorPicker : : _pick_button_pressed_native ( ) {
if ( ! DisplayServer : : get_singleton ( ) - > color_picker ( callable_mp ( this , & ColorPicker : : _native_cb ) ) ) {
// Fallback to default/legacy picker.
if ( DisplayServer : : get_singleton ( ) - > has_feature ( DisplayServer : : FEATURE_SCREEN_CAPTURE ) & & ! get_tree ( ) - > get_root ( ) - > is_embedding_subwindows ( ) ) {
_pick_button_pressed ( ) ;
} else {
_pick_button_pressed_legacy ( ) ;
}
}
}
void ColorPicker : : _native_cb ( bool p_status , const Color & p_color ) {
if ( p_status ) {
set_pick_color ( p_color ) ;
if ( ! deferred_mode_enabled ) {
emit_signal ( SNAME ( " color_changed " ) , color ) ;
}
}
}
2023-02-05 17:35:39 +01:00
void ColorPicker : : _pick_button_pressed ( ) {
2023-03-15 23:30:42 +01:00
is_picking_color = true ;
2025-02-01 21:23:51 +02:00
pre_picking_color = color ;
2023-03-15 23:30:42 +01:00
if ( ! picker_window ) {
picker_window = memnew ( Popup ) ;
2025-01-08 10:32:25 +02:00
bool has_feature_exclude_from_capture = DisplayServer : : get_singleton ( ) - > has_feature ( DisplayServer : : FEATURE_SCREEN_EXCLUDE_FROM_CAPTURE ) ;
if ( ! has_feature_exclude_from_capture ) {
picker_window - > set_size ( Vector2i ( 28 , 28 ) ) ;
} else {
picker_window - > set_size ( Vector2i ( 55 , 72 ) ) ;
picker_window - > set_flag ( Window : : FLAG_EXCLUDE_FROM_CAPTURE , true ) ; // Only supported on MacOS and Windows.
}
2024-05-13 16:56:03 +02:00
picker_window - > connect ( SceneStringName ( visibility_changed ) , callable_mp ( this , & ColorPicker : : _pick_finished ) ) ;
2024-02-27 22:19:47 +02:00
picker_window - > connect ( SceneStringName ( window_input ) , callable_mp ( this , & ColorPicker : : _target_gui_input ) ) ;
picker_preview = memnew ( Panel ) ;
picker_preview - > set_mouse_filter ( MOUSE_FILTER_IGNORE ) ;
picker_preview - > set_size ( Vector2i ( 55 , 72 ) ) ;
picker_window - > add_child ( picker_preview ) ;
picker_preview_color = memnew ( Panel ) ;
picker_preview_color - > set_mouse_filter ( MOUSE_FILTER_IGNORE ) ;
2025-01-08 10:32:25 +02:00
if ( ! has_feature_exclude_from_capture ) {
picker_preview_color - > set_size ( Vector2i ( 24 , 24 ) ) ;
picker_preview_color - > set_position ( Vector2i ( 2 , 2 ) ) ;
} else {
picker_preview_color - > set_size ( Vector2i ( 51 , 15 ) ) ;
picker_preview_color - > set_position ( Vector2i ( 2 , 55 ) ) ;
}
2024-02-27 22:19:47 +02:00
picker_preview - > add_child ( picker_preview_color ) ;
2025-01-08 10:32:25 +02:00
if ( has_feature_exclude_from_capture ) {
picker_texture_zoom = memnew ( TextureRect ) ;
picker_texture_zoom - > set_mouse_filter ( MOUSE_FILTER_IGNORE ) ;
picker_texture_zoom - > set_custom_minimum_size ( Vector2i ( 51 , 51 ) ) ;
picker_texture_zoom - > set_position ( Vector2i ( 2 , 2 ) ) ;
picker_texture_zoom - > set_texture_filter ( CanvasItem : : TEXTURE_FILTER_NEAREST ) ;
picker_preview - > add_child ( picker_texture_zoom ) ;
}
2024-02-27 22:19:47 +02:00
picker_preview_style_box . instantiate ( ) ;
picker_preview - > add_theme_style_override ( SceneStringName ( panel ) , picker_preview_style_box ) ;
picker_preview_style_box_color . instantiate ( ) ;
picker_preview_color - > add_theme_style_override ( SceneStringName ( panel ) , picker_preview_style_box_color ) ;
2023-06-20 12:47:52 +02:00
add_child ( picker_window , false , INTERNAL_MODE_FRONT ) ;
2023-03-15 23:30:42 +01:00
}
2024-02-27 22:19:47 +02:00
set_process_internal ( true ) ;
2023-03-15 23:30:42 +01:00
picker_window - > popup ( ) ;
}
2024-02-27 22:19:47 +02:00
void ColorPicker : : _target_gui_input ( const Ref < InputEvent > & p_event ) {
const Ref < InputEventMouseButton > mouse_event = p_event ;
2025-02-01 21:23:51 +02:00
if ( mouse_event . is_null ( ) ) {
return ;
}
if ( mouse_event - > get_button_index ( ) = = MouseButton : : LEFT ) {
if ( mouse_event - > is_pressed ( ) ) {
picker_window - > hide ( ) ;
_pick_finished ( ) ;
}
} else if ( mouse_event - > get_button_index ( ) = = MouseButton : : RIGHT ) {
set_pick_color ( pre_picking_color ) ; // Cancel.
is_picking_color = false ;
set_process_internal ( false ) ;
2024-02-27 22:19:47 +02:00
picker_window - > hide ( ) ;
2025-02-01 21:23:51 +02:00
} else {
Window * w = picker_window - > get_parent_visible_window ( ) ;
while ( w ) {
Point2i win_mpos = w - > get_mouse_position ( ) ; // Mouse position local to the window.
Size2i win_size = w - > get_size ( ) ;
if ( win_mpos . x > = 0 & & win_mpos . y > = 0 & & win_mpos . x < = win_size . x & & win_mpos . y < = win_size . y ) {
// Mouse event inside window bounds, forward this event to the window.
Ref < InputEventMouseButton > new_ev = p_event - > duplicate ( ) ;
new_ev - > set_position ( win_mpos ) ;
new_ev - > set_global_position ( win_mpos ) ;
w - > push_input ( new_ev , true ) ;
return ;
}
w = w - > get_parent_visible_window ( ) ;
}
2024-02-27 22:19:47 +02:00
}
}
2023-03-15 23:30:42 +01:00
void ColorPicker : : _pick_finished ( ) {
if ( picker_window - > is_visible ( ) ) {
return ;
}
2024-02-22 18:01:28 -06:00
if ( Input : : get_singleton ( ) - > is_action_just_pressed ( SNAME ( " ui_cancel " ) ) ) {
2025-02-01 21:23:51 +02:00
set_pick_color ( pre_picking_color ) ;
2023-03-15 23:30:42 +01:00
} else {
emit_signal ( SNAME ( " color_changed " ) , color ) ;
}
is_picking_color = false ;
set_process_internal ( false ) ;
picker_window - > hide ( ) ;
}
2024-05-18 10:45:16 +07:00
void ColorPicker : : _update_menu_items ( ) {
options_menu - > clear ( ) ;
options_menu - > reset_size ( ) ;
2025-04-29 10:42:28 +08:00
options_menu - > add_icon_item ( get_theme_icon ( SNAME ( " save " ) , SNAME ( " FileDialog " ) ) , ETR ( " Save " ) , static_cast < int > ( MenuOption : : MENU_SAVE ) ) ;
options_menu - > set_item_tooltip ( - 1 , ETR ( " Save the current color palette to reuse later. " ) ) ;
options_menu - > set_item_disabled ( - 1 , presets . is_empty ( ) ) ;
options_menu - > add_icon_item ( get_theme_icon ( SNAME ( " save " ) , SNAME ( " FileDialog " ) ) , ETR ( " Save As " ) , static_cast < int > ( MenuOption : : MENU_SAVE_AS ) ) ;
options_menu - > set_item_tooltip ( - 1 , ETR ( " Save the current color palette as a new to reuse later. " ) ) ;
options_menu - > set_item_disabled ( - 1 , palette_path . is_empty ( ) ) ;
options_menu - > add_icon_item ( get_theme_icon ( SNAME ( " load " ) , SNAME ( " FileDialog " ) ) , ETR ( " Load " ) , static_cast < int > ( MenuOption : : MENU_LOAD ) ) ;
2024-05-18 10:45:16 +07:00
options_menu - > set_item_tooltip ( - 1 , ETR ( " Load existing color palette. " ) ) ;
2025-04-29 10:42:28 +08:00
# ifdef TOOLS_ENABLED
2024-05-18 10:45:16 +07:00
if ( Engine : : get_singleton ( ) - > is_editor_hint ( ) ) {
2025-04-29 10:42:28 +08:00
options_menu - > add_icon_item ( get_theme_icon ( SNAME ( " load " ) , SNAME ( " FileDialog " ) ) , TTRC ( " Quick Load " ) , static_cast < int > ( MenuOption : : MENU_QUICKLOAD ) ) ;
options_menu - > set_item_tooltip ( - 1 , TTRC ( " Load existing color palette. " ) ) ;
2024-05-18 10:45:16 +07:00
}
2025-04-29 10:42:28 +08:00
# endif // TOOLS_ENABLED
2024-05-18 10:45:16 +07:00
2025-04-29 10:42:28 +08:00
options_menu - > add_icon_item ( get_theme_icon ( SNAME ( " clear " ) , SNAME ( " FileDialog " ) ) , ETR ( " Clear " ) , static_cast < int > ( MenuOption : : MENU_CLEAR ) ) ;
options_menu - > set_item_tooltip ( - 1 , ETR ( " Clear the currently loaded color palettes in the picker. " ) ) ;
options_menu - > set_item_disabled ( - 1 , presets . is_empty ( ) ) ;
2024-05-18 10:45:16 +07:00
}
void ColorPicker : : _options_menu_cbk ( int p_which ) {
2025-04-29 10:42:28 +08:00
_ensure_file_dialog ( ) ;
2024-05-18 10:45:16 +07:00
MenuOption option = static_cast < MenuOption > ( p_which ) ;
switch ( option ) {
case MenuOption : : MENU_SAVE :
_save_palette ( false ) ;
break ;
case MenuOption : : MENU_SAVE_AS :
_save_palette ( true ) ;
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 ( " " ) ;
palette_path = String ( ) ;
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_path " , palette_path ) ;
editor_settings - > call ( SNAME ( " set_project_metadata " ) , " color_picker " , " palette_edited " , false ) ;
}
# endif // TOOLS_ENABLED
}
break ;
default :
break ;
}
}
2024-11-07 13:27:11 +01:00
void ColorPicker : : _block_input_on_popup_show ( ) {
if ( ! get_tree ( ) - > get_root ( ) - > is_embedding_subwindows ( ) ) {
get_viewport ( ) - > set_disable_input ( true ) ;
}
}
void ColorPicker : : _enable_input_on_popup_hide ( ) {
if ( ! get_tree ( ) - > get_root ( ) - > is_embedding_subwindows ( ) ) {
get_viewport ( ) - > set_disable_input ( false ) ;
}
}
2023-03-15 23:30:42 +01:00
void ColorPicker : : _pick_button_pressed_legacy ( ) {
2021-02-18 19:53:32 +07:00
if ( ! is_inside_tree ( ) ) {
return ;
}
2025-02-01 21:23:51 +02:00
pre_picking_color = color ;
2021-02-18 19:53:32 +07:00
2023-02-05 17:35:39 +01:00
if ( ! picker_window ) {
picker_window = memnew ( Popup ) ;
picker_window - > hide ( ) ;
picker_window - > set_transient ( true ) ;
2023-06-20 12:47:52 +02:00
add_child ( picker_window , false , INTERNAL_MODE_FRONT ) ;
2023-02-05 17:35:39 +01:00
picker_texture_rect = memnew ( TextureRect ) ;
picker_texture_rect - > set_anchors_preset ( Control : : PRESET_FULL_RECT ) ;
2024-09-20 01:50:31 +02:00
picker_texture_rect - > set_expand_mode ( TextureRect : : EXPAND_IGNORE_SIZE ) ;
2024-02-27 22:19:47 +02:00
picker_texture_rect - > set_default_cursor_shape ( Control : : CURSOR_CROSS ) ;
2023-02-05 17:35:39 +01:00
picker_window - > add_child ( picker_texture_rect ) ;
2024-05-13 16:56:03 +02:00
picker_texture_rect - > connect ( SceneStringName ( gui_input ) , callable_mp ( this , & ColorPicker : : _picker_texture_input ) ) ;
2023-02-05 17:35:39 +01:00
2024-02-27 22:19:47 +02:00
picker_preview = memnew ( Panel ) ;
picker_preview - > set_mouse_filter ( MOUSE_FILTER_IGNORE ) ;
2025-01-14 00:14:40 +02:00
picker_preview - > set_size ( Vector2i ( 55 , 72 ) ) ;
2024-02-27 22:19:47 +02:00
picker_window - > add_child ( picker_preview ) ;
picker_preview_color = memnew ( Panel ) ;
picker_preview_color - > set_mouse_filter ( MOUSE_FILTER_IGNORE ) ;
2025-01-14 00:14:40 +02:00
picker_preview_color - > set_size ( Vector2i ( 51 , 15 ) ) ;
picker_preview_color - > set_position ( Vector2i ( 2 , 55 ) ) ;
2024-02-27 22:19:47 +02:00
picker_preview - > add_child ( picker_preview_color ) ;
2025-01-14 00:14:40 +02:00
picker_texture_zoom = memnew ( TextureRect ) ;
picker_texture_zoom - > set_mouse_filter ( MOUSE_FILTER_IGNORE ) ;
picker_texture_zoom - > set_custom_minimum_size ( Vector2i ( 51 , 51 ) ) ;
picker_texture_zoom - > set_position ( Vector2i ( 2 , 2 ) ) ;
picker_texture_zoom - > set_texture_filter ( CanvasItem : : TEXTURE_FILTER_NEAREST ) ;
picker_preview - > add_child ( picker_texture_zoom ) ;
2023-02-05 17:35:39 +01:00
2024-10-20 22:59:39 +02:00
picker_preview_style_box . instantiate ( ) ;
2024-02-27 22:19:47 +02:00
picker_preview - > add_theme_style_override ( SceneStringName ( panel ) , picker_preview_style_box ) ;
2024-10-20 22:59:39 +02:00
2024-02-27 22:19:47 +02:00
picker_preview_style_box_color . instantiate ( ) ;
picker_preview_color - > add_theme_style_override ( SceneStringName ( panel ) , picker_preview_style_box_color ) ;
2023-02-05 17:35:39 +01:00
}
Rect2i screen_rect ;
if ( picker_window - > is_embedded ( ) ) {
2024-02-27 22:19:47 +02:00
Ref < ImageTexture > tx = ImageTexture : : create_from_image ( picker_window - > get_embedder ( ) - > get_texture ( ) - > get_image ( ) ) ;
2023-02-05 17:35:39 +01:00
screen_rect = picker_window - > get_embedder ( ) - > get_visible_rect ( ) ;
picker_window - > set_position ( Point2i ( ) ) ;
2024-02-27 22:19:47 +02:00
picker_texture_rect - > set_texture ( tx ) ;
2025-01-14 00:14:40 +02:00
Vector2 ofs = picker_window - > get_mouse_position ( ) ;
picker_preview - > set_position ( ofs - Vector2 ( 28 , 28 ) ) ;
Vector2 scale = screen_rect . size / tx - > get_image ( ) - > get_size ( ) ;
ofs / = scale ;
2024-02-27 22:19:47 +02:00
Ref < AtlasTexture > atlas ;
atlas . instantiate ( ) ;
atlas - > set_atlas ( tx ) ;
2025-01-14 00:14:40 +02:00
atlas - > set_region ( Rect2i ( ofs . x - 8 , ofs . y - 8 , 17 , 17 ) ) ;
2024-02-27 22:19:47 +02:00
picker_texture_zoom - > set_texture ( atlas ) ;
2022-06-13 18:54:48 +08:00
} else {
2023-02-05 17:35:39 +01:00
screen_rect = picker_window - > get_parent_rect ( ) ;
picker_window - > set_position ( screen_rect . position ) ;
Ref < Image > target_image = Image : : create_empty ( screen_rect . size . x , screen_rect . size . y , false , Image : : FORMAT_RGB8 ) ;
DisplayServer * ds = DisplayServer : : get_singleton ( ) ;
// Add the Texture of each Window to the Image.
Vector < DisplayServer : : WindowID > wl = ds - > get_window_list ( ) ;
// FIXME: sort windows by visibility.
2024-11-29 21:15:23 +01:00
for ( const DisplayServer : : WindowID & window_id : wl ) {
Window * w = Window : : get_from_id ( window_id ) ;
if ( ! w ) {
2023-02-05 17:35:39 +01:00
continue ;
}
Ref < Image > img = w - > get_texture ( ) - > get_image ( ) ;
2024-08-25 14:15:10 +02:00
if ( img . is_null ( ) | | img - > is_empty ( ) ) {
2023-02-05 17:35:39 +01:00
continue ;
}
img - > convert ( Image : : FORMAT_RGB8 ) ;
target_image - > blit_rect ( img , Rect2i ( Point2i ( 0 , 0 ) , img - > get_size ( ) ) , w - > get_position ( ) ) ;
}
2025-01-14 00:14:40 +02:00
Ref < ImageTexture > tx = ImageTexture : : create_from_image ( target_image ) ;
picker_texture_rect - > set_texture ( tx ) ;
Vector2 ofs = screen_rect . position - DisplayServer : : get_singleton ( ) - > mouse_get_position ( ) ;
picker_preview - > set_position ( ofs - Vector2 ( 28 , 28 ) ) ;
Ref < AtlasTexture > atlas ;
atlas . instantiate ( ) ;
atlas - > set_atlas ( tx ) ;
atlas - > set_region ( Rect2i ( ofs . x - 8 , ofs . y - 8 , 17 , 17 ) ) ;
picker_texture_zoom - > set_texture ( atlas ) ;
2015-12-25 11:08:02 -03:00
}
2023-02-05 17:35:39 +01:00
picker_window - > set_size ( screen_rect . size ) ;
picker_window - > popup ( ) ;
2015-12-25 11:08:02 -03:00
}
2023-03-15 23:30:42 +01:00
void ColorPicker : : _picker_texture_input ( const Ref < InputEvent > & p_event ) {
if ( ! is_inside_tree ( ) ) {
return ;
}
Ref < InputEventMouseButton > bev = p_event ;
if ( bev . is_valid ( ) & & bev - > get_button_index ( ) = = MouseButton : : LEFT & & ! bev - > is_pressed ( ) ) {
set_pick_color ( picker_color ) ;
emit_signal ( SNAME ( " color_changed " ) , color ) ;
picker_window - > hide ( ) ;
}
Ref < InputEventMouseMotion > mev = p_event ;
if ( mev . is_valid ( ) ) {
Ref < Image > img = picker_texture_rect - > get_texture ( ) - > get_image ( ) ;
if ( img . is_valid ( ) & & ! img - > is_empty ( ) ) {
Vector2 ofs = mev - > get_position ( ) ;
2024-02-27 22:19:47 +02:00
picker_preview - > set_position ( ofs - Vector2 ( 28 , 28 ) ) ;
Vector2 scale = picker_texture_rect - > get_size ( ) / img - > get_size ( ) ;
ofs / = scale ;
2023-03-15 23:30:42 +01:00
picker_color = img - > get_pixel ( ofs . x , ofs . y ) ;
2024-02-27 22:19:47 +02:00
picker_preview_style_box_color - > set_bg_color ( picker_color ) ;
picker_preview_style_box - > set_bg_color ( picker_color . get_luminance ( ) < 0.5 ? Color ( 1.0f , 1.0f , 1.0f ) : Color ( 0.0f , 0.0f , 0.0f ) ) ;
Ref < AtlasTexture > atlas = picker_texture_zoom - > get_texture ( ) ;
if ( atlas . is_valid ( ) ) {
atlas - > set_region ( Rect2i ( ofs . x - 8 , ofs . y - 8 , 17 , 17 ) ) ;
}
2023-03-15 23:30:42 +01:00
}
}
}
2018-03-09 21:02:58 +01:00
void ColorPicker : : _html_focus_exit ( ) {
2021-07-16 18:36:05 -03:00
if ( c_text - > is_menu_visible ( ) ) {
2020-03-24 17:11:09 +05:30
return ;
2020-05-14 16:41:43 +02:00
}
2024-02-22 18:01:28 -06:00
if ( is_visible_in_tree ( ) ) {
_html_submitted ( c_text - > get_text ( ) ) ;
} else {
_update_text_value ( ) ;
}
2018-03-09 21:02:58 +01:00
}
2022-10-21 23:20:28 -04:00
void ColorPicker : : set_can_add_swatches ( bool p_enabled ) {
if ( can_add_swatches = = p_enabled ) {
2022-03-16 15:50:48 +08:00
return ;
}
2022-10-21 23:20:28 -04:00
can_add_swatches = p_enabled ;
2019-02-24 14:42:46 -06:00
if ( ! p_enabled ) {
2021-08-18 02:09:48 +02:00
btn_add_preset - > set_disabled ( true ) ;
btn_add_preset - > set_focus_mode ( FOCUS_NONE ) ;
2019-02-24 14:42:46 -06:00
} else {
2021-08-18 02:09:48 +02:00
btn_add_preset - > set_disabled ( false ) ;
btn_add_preset - > set_focus_mode ( FOCUS_ALL ) ;
2019-02-24 14:42:46 -06:00
}
}
2022-10-21 23:20:28 -04:00
bool ColorPicker : : are_swatches_enabled ( ) const {
return can_add_swatches ;
2019-02-24 14:42:46 -06:00
}
void ColorPicker : : set_presets_visible ( bool p_visible ) {
2022-03-16 15:50:48 +08:00
if ( presets_visible = = p_visible ) {
return ;
}
2019-02-24 14:42:46 -06:00
presets_visible = p_visible ;
2025-01-22 13:42:30 +01:00
swatches_vbc - > set_visible ( p_visible ) ;
2019-02-24 14:42:46 -06:00
}
bool ColorPicker : : are_presets_visible ( ) const {
return presets_visible ;
}
2022-10-21 23:20:28 -04:00
void ColorPicker : : set_modes_visible ( bool p_visible ) {
if ( color_modes_visible = = p_visible ) {
return ;
}
color_modes_visible = p_visible ;
mode_hbc - > set_visible ( p_visible ) ;
}
bool ColorPicker : : are_modes_visible ( ) const {
return color_modes_visible ;
}
void ColorPicker : : set_sampler_visible ( bool p_visible ) {
if ( sampler_visible = = p_visible ) {
return ;
}
sampler_visible = p_visible ;
sample_hbc - > set_visible ( p_visible ) ;
}
bool ColorPicker : : is_sampler_visible ( ) const {
return sampler_visible ;
}
void ColorPicker : : set_sliders_visible ( bool p_visible ) {
if ( sliders_visible = = p_visible ) {
return ;
}
sliders_visible = p_visible ;
slider_gc - > set_visible ( p_visible ) ;
}
bool ColorPicker : : are_sliders_visible ( ) const {
return sliders_visible ;
}
void ColorPicker : : set_hex_visible ( bool p_visible ) {
if ( hex_visible = = p_visible ) {
return ;
}
hex_visible = p_visible ;
hex_hbc - > set_visible ( p_visible ) ;
}
bool ColorPicker : : is_hex_visible ( ) const {
return hex_visible ;
}
2014-02-09 22:10:30 -03:00
void ColorPicker : : _bind_methods ( ) {
2017-02-13 12:47:24 +01:00
ClassDB : : bind_method ( D_METHOD ( " set_pick_color " , " color " ) , & ColorPicker : : set_pick_color ) ;
ClassDB : : bind_method ( D_METHOD ( " get_pick_color " ) , & ColorPicker : : get_pick_color ) ;
2018-05-29 15:21:06 +03:00
ClassDB : : bind_method ( D_METHOD ( " set_deferred_mode " , " mode " ) , & ColorPicker : : set_deferred_mode ) ;
ClassDB : : bind_method ( D_METHOD ( " is_deferred_mode " ) , & ColorPicker : : is_deferred_mode ) ;
2022-05-29 20:47:37 +05:30
ClassDB : : bind_method ( D_METHOD ( " set_color_mode " , " color_mode " ) , & ColorPicker : : set_color_mode ) ;
ClassDB : : bind_method ( D_METHOD ( " get_color_mode " ) , & ColorPicker : : get_color_mode ) ;
2017-02-13 12:47:24 +01:00
ClassDB : : bind_method ( D_METHOD ( " set_edit_alpha " , " show " ) , & ColorPicker : : set_edit_alpha ) ;
ClassDB : : bind_method ( D_METHOD ( " is_editing_alpha " ) , & ColorPicker : : is_editing_alpha ) ;
2025-05-23 12:45:29 +08:00
ClassDB : : bind_method ( D_METHOD ( " set_edit_intensity " , " show " ) , & ColorPicker : : set_edit_intensity ) ;
ClassDB : : bind_method ( D_METHOD ( " is_editing_intensity " ) , & ColorPicker : : is_editing_intensity ) ;
2022-10-21 23:20:28 -04:00
ClassDB : : bind_method ( D_METHOD ( " set_can_add_swatches " , " enabled " ) , & ColorPicker : : set_can_add_swatches ) ;
ClassDB : : bind_method ( D_METHOD ( " are_swatches_enabled " ) , & ColorPicker : : are_swatches_enabled ) ;
2019-02-24 14:42:46 -06:00
ClassDB : : bind_method ( D_METHOD ( " set_presets_visible " , " visible " ) , & ColorPicker : : set_presets_visible ) ;
ClassDB : : bind_method ( D_METHOD ( " are_presets_visible " ) , & ColorPicker : : are_presets_visible ) ;
2022-10-21 23:20:28 -04:00
ClassDB : : bind_method ( D_METHOD ( " set_modes_visible " , " visible " ) , & ColorPicker : : set_modes_visible ) ;
ClassDB : : bind_method ( D_METHOD ( " are_modes_visible " ) , & ColorPicker : : are_modes_visible ) ;
ClassDB : : bind_method ( D_METHOD ( " set_sampler_visible " , " visible " ) , & ColorPicker : : set_sampler_visible ) ;
ClassDB : : bind_method ( D_METHOD ( " is_sampler_visible " ) , & ColorPicker : : is_sampler_visible ) ;
ClassDB : : bind_method ( D_METHOD ( " set_sliders_visible " , " visible " ) , & ColorPicker : : set_sliders_visible ) ;
ClassDB : : bind_method ( D_METHOD ( " are_sliders_visible " ) , & ColorPicker : : are_sliders_visible ) ;
ClassDB : : bind_method ( D_METHOD ( " set_hex_visible " , " visible " ) , & ColorPicker : : set_hex_visible ) ;
ClassDB : : bind_method ( D_METHOD ( " is_hex_visible " ) , & ColorPicker : : is_hex_visible ) ;
2017-07-19 02:03:34 +07:00
ClassDB : : bind_method ( D_METHOD ( " add_preset " , " color " ) , & ColorPicker : : add_preset ) ;
2018-10-03 16:12:38 +02:00
ClassDB : : bind_method ( D_METHOD ( " erase_preset " , " color " ) , & ColorPicker : : erase_preset ) ;
ClassDB : : bind_method ( D_METHOD ( " get_presets " ) , & ColorPicker : : get_presets ) ;
2022-06-30 17:04:32 +05:30
ClassDB : : bind_method ( D_METHOD ( " add_recent_preset " , " color " ) , & ColorPicker : : add_recent_preset ) ;
ClassDB : : bind_method ( D_METHOD ( " erase_recent_preset " , " color " ) , & ColorPicker : : erase_recent_preset ) ;
ClassDB : : bind_method ( D_METHOD ( " get_recent_presets " ) , & ColorPicker : : get_recent_presets ) ;
2022-05-29 20:47:37 +05:30
ClassDB : : bind_method ( D_METHOD ( " set_picker_shape " , " shape " ) , & ColorPicker : : set_picker_shape ) ;
2021-02-23 17:22:46 +07:00
ClassDB : : bind_method ( D_METHOD ( " get_picker_shape " ) , & ColorPicker : : get_picker_shape ) ;
2014-02-09 22:10:30 -03:00
2018-01-12 00:35:12 +02:00
ADD_PROPERTY ( PropertyInfo ( Variant : : COLOR , " color " ) , " set_pick_color " , " get_pick_color " ) ;
ADD_PROPERTY ( PropertyInfo ( Variant : : BOOL , " edit_alpha " ) , " set_edit_alpha " , " is_editing_alpha " ) ;
2025-05-23 12:45:29 +08:00
ADD_PROPERTY ( PropertyInfo ( Variant : : BOOL , " edit_intensity " ) , " set_edit_intensity " , " is_editing_intensity " ) ;
ADD_PROPERTY ( PropertyInfo ( Variant : : INT , " color_mode " , PROPERTY_HINT_ENUM , " RGB,HSV,LINEAR,OKHSL " ) , " set_color_mode " , " get_color_mode " ) ;
2018-05-29 15:21:06 +03:00
ADD_PROPERTY ( PropertyInfo ( Variant : : BOOL , " deferred_mode " ) , " set_deferred_mode " , " is_deferred_mode " ) ;
2025-06-07 22:30:40 +08:00
ADD_PROPERTY ( PropertyInfo ( Variant : : INT , " picker_shape " , PROPERTY_HINT_ENUM , " HSV Rectangle,HSV Rectangle Wheel,VHS Circle,OKHSL Circle,OK HS Rectangle:5,OK HL Rectangle,None:4 " ) , " set_picker_shape " , " get_picker_shape " ) ;
2022-10-21 23:20:28 -04:00
ADD_PROPERTY ( PropertyInfo ( Variant : : BOOL , " can_add_swatches " ) , " set_can_add_swatches " , " are_swatches_enabled " ) ;
ADD_GROUP ( " Customization " , " " ) ;
ADD_PROPERTY ( PropertyInfo ( Variant : : BOOL , " sampler_visible " ) , " set_sampler_visible " , " is_sampler_visible " ) ;
ADD_PROPERTY ( PropertyInfo ( Variant : : BOOL , " color_modes_visible " ) , " set_modes_visible " , " are_modes_visible " ) ;
ADD_PROPERTY ( PropertyInfo ( Variant : : BOOL , " sliders_visible " ) , " set_sliders_visible " , " are_sliders_visible " ) ;
ADD_PROPERTY ( PropertyInfo ( Variant : : BOOL , " hex_visible " ) , " set_hex_visible " , " is_hex_visible " ) ;
2019-02-24 14:42:46 -06:00
ADD_PROPERTY ( PropertyInfo ( Variant : : BOOL , " presets_visible " ) , " set_presets_visible " , " are_presets_visible " ) ;
2018-01-12 00:35:12 +02:00
2014-02-09 22:10:30 -03:00
ADD_SIGNAL ( MethodInfo ( " color_changed " , PropertyInfo ( Variant : : COLOR , " color " ) ) ) ;
2018-10-03 16:12:38 +02:00
ADD_SIGNAL ( MethodInfo ( " preset_added " , PropertyInfo ( Variant : : COLOR , " color " ) ) ) ;
ADD_SIGNAL ( MethodInfo ( " preset_removed " , PropertyInfo ( Variant : : COLOR , " color " ) ) ) ;
2021-02-23 17:22:46 +07:00
2022-05-29 20:47:37 +05:30
BIND_ENUM_CONSTANT ( MODE_RGB ) ;
BIND_ENUM_CONSTANT ( MODE_HSV ) ;
2025-05-23 12:45:29 +08:00
# ifndef DISABLE_DEPRECATED
2022-05-29 20:47:37 +05:30
BIND_ENUM_CONSTANT ( MODE_RAW ) ;
2025-05-23 12:45:29 +08:00
# endif
BIND_ENUM_CONSTANT ( MODE_LINEAR ) ;
2022-05-29 20:47:37 +05:30
BIND_ENUM_CONSTANT ( MODE_OKHSL ) ;
2021-02-23 17:22:46 +07:00
BIND_ENUM_CONSTANT ( SHAPE_HSV_RECTANGLE ) ;
BIND_ENUM_CONSTANT ( SHAPE_HSV_WHEEL ) ;
BIND_ENUM_CONSTANT ( SHAPE_VHS_CIRCLE ) ;
2022-04-18 11:29:29 -07:00
BIND_ENUM_CONSTANT ( SHAPE_OKHSL_CIRCLE ) ;
2022-10-21 23:20:28 -04:00
BIND_ENUM_CONSTANT ( SHAPE_NONE ) ;
2025-06-07 22:30:40 +08:00
BIND_ENUM_CONSTANT ( SHAPE_OK_HS_RECTANGLE ) ;
BIND_ENUM_CONSTANT ( SHAPE_OK_HL_RECTANGLE ) ;
2023-09-08 21:00:10 +02:00
BIND_THEME_ITEM_CUSTOM ( Theme : : DATA_TYPE_CONSTANT , ColorPicker , content_margin , " margin " ) ;
BIND_THEME_ITEM ( Theme : : DATA_TYPE_CONSTANT , ColorPicker , label_width ) ;
BIND_THEME_ITEM ( Theme : : DATA_TYPE_CONSTANT , ColorPicker , sv_width ) ;
BIND_THEME_ITEM ( Theme : : DATA_TYPE_CONSTANT , ColorPicker , sv_height ) ;
BIND_THEME_ITEM ( Theme : : DATA_TYPE_CONSTANT , ColorPicker , h_width ) ;
BIND_THEME_ITEM ( Theme : : DATA_TYPE_CONSTANT , ColorPicker , center_slider_grabbers ) ;
2024-11-07 13:27:11 +01:00
BIND_THEME_ITEM ( Theme : : DATA_TYPE_STYLEBOX , ColorPicker , sample_focus ) ;
BIND_THEME_ITEM ( Theme : : DATA_TYPE_STYLEBOX , ColorPicker , picker_focus_rectangle ) ;
BIND_THEME_ITEM ( Theme : : DATA_TYPE_STYLEBOX , ColorPicker , picker_focus_circle ) ;
BIND_THEME_ITEM ( Theme : : DATA_TYPE_COLOR , ColorPicker , focused_not_editing_cursor_color ) ;
2023-09-08 21:00:10 +02:00
2024-05-18 10:45:16 +07:00
BIND_THEME_ITEM ( Theme : : DATA_TYPE_ICON , ColorPicker , menu_option ) ;
2023-09-08 21:00:10 +02:00
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 ) ;
BIND_THEME_ITEM ( Theme : : DATA_TYPE_ICON , ColorPicker , add_preset ) ;
BIND_THEME_ITEM ( Theme : : DATA_TYPE_ICON , ColorPicker , shape_rect ) ;
BIND_THEME_ITEM ( Theme : : DATA_TYPE_ICON , ColorPicker , shape_rect_wheel ) ;
BIND_THEME_ITEM ( Theme : : DATA_TYPE_ICON , ColorPicker , shape_circle ) ;
BIND_THEME_ITEM ( Theme : : DATA_TYPE_ICON , ColorPicker , bar_arrow ) ;
2023-09-12 15:01:42 +02:00
BIND_THEME_ITEM ( Theme : : DATA_TYPE_ICON , ColorPicker , sample_bg ) ;
2023-11-06 14:53:52 +01:00
BIND_THEME_ITEM ( Theme : : DATA_TYPE_ICON , ColorPicker , sample_revert ) ;
2023-09-08 21:00:10 +02:00
BIND_THEME_ITEM ( Theme : : DATA_TYPE_ICON , ColorPicker , overbright_indicator ) ;
BIND_THEME_ITEM ( Theme : : DATA_TYPE_ICON , ColorPicker , picker_cursor ) ;
2025-01-10 09:55:54 +02:00
BIND_THEME_ITEM ( Theme : : DATA_TYPE_ICON , ColorPicker , picker_cursor_bg ) ;
2023-09-12 15:01:42 +02:00
BIND_THEME_ITEM ( Theme : : DATA_TYPE_ICON , ColorPicker , color_hue ) ;
2023-09-08 21:00:10 +02:00
2025-05-23 12:45:29 +08:00
BIND_THEME_ITEM ( Theme : : DATA_TYPE_ICON , ColorPicker , color_script ) ;
2023-09-08 21:00:10 +02:00
BIND_THEME_ITEM_EXT ( Theme : : DATA_TYPE_STYLEBOX , ColorPicker , mode_button_normal , " tab_unselected " , " TabContainer " ) ;
BIND_THEME_ITEM_EXT ( Theme : : DATA_TYPE_STYLEBOX , ColorPicker , mode_button_pressed , " tab_selected " , " TabContainer " ) ;
BIND_THEME_ITEM_EXT ( Theme : : DATA_TYPE_STYLEBOX , ColorPicker , mode_button_hover , " tab_selected " , " TabContainer " ) ;
2025-03-06 15:42:10 -03:00
ADD_CLASS_DEPENDENCY ( " LineEdit " ) ;
ADD_CLASS_DEPENDENCY ( " MenuButton " ) ;
ADD_CLASS_DEPENDENCY ( " PopupMenu " ) ;
2014-02-09 22:10:30 -03:00
}
2022-11-04 09:46:13 -04:00
ColorPicker : : ColorPicker ( ) {
2023-06-20 12:47:52 +02:00
internal_margin = memnew ( MarginContainer ) ;
add_child ( internal_margin , false , INTERNAL_MODE_FRONT ) ;
VBoxContainer * real_vbox = memnew ( VBoxContainer ) ;
internal_margin - > add_child ( real_vbox ) ;
2024-11-20 23:26:52 +01:00
shape_container = memnew ( HBoxContainer ) ;
shape_container - > set_v_size_flags ( SIZE_SHRINK_BEGIN ) ;
real_vbox - > add_child ( shape_container ) ;
2015-12-23 23:17:09 -03:00
2022-10-21 23:20:28 -04:00
sample_hbc = memnew ( HBoxContainer ) ;
2023-06-20 12:47:52 +02:00
real_vbox - > add_child ( sample_hbc ) ;
2019-12-28 18:08:16 +01:00
2022-06-30 17:04:32 +05:30
btn_pick = memnew ( Button ) ;
2024-11-30 19:50:53 +01:00
btn_pick - > set_icon_alignment ( HORIZONTAL_ALIGNMENT_CENTER ) ;
2025-03-21 16:42:23 +02:00
btn_pick - > set_accessibility_name ( ETR ( " Pick " ) ) ;
2022-10-21 23:20:28 -04:00
sample_hbc - > add_child ( btn_pick ) ;
2022-06-30 17:04:32 +05:30
2022-05-29 20:47:37 +05:30
sample = memnew ( TextureRect ) ;
2022-10-21 23:20:28 -04:00
sample_hbc - > add_child ( sample ) ;
2019-12-28 18:08:16 +01:00
sample - > set_h_size_flags ( SIZE_EXPAND_FILL ) ;
2024-05-13 16:56:03 +02:00
sample - > connect ( SceneStringName ( gui_input ) , callable_mp ( this , & ColorPicker : : _sample_input ) ) ;
sample - > connect ( SceneStringName ( draw ) , callable_mp ( this , & ColorPicker : : _sample_draw ) ) ;
2019-12-28 18:08:16 +01:00
2022-06-30 17:04:32 +05:30
btn_shape = memnew ( MenuButton ) ;
btn_shape - > set_flat ( false ) ;
2022-10-21 23:20:28 -04:00
sample_hbc - > add_child ( btn_shape ) ;
2022-06-30 17:04:32 +05:30
btn_shape - > set_toggle_mode ( true ) ;
2023-12-15 20:56:06 -03:00
btn_shape - > set_tooltip_text ( ETR ( " Select a picker shape. " ) ) ;
2024-11-30 19:50:53 +01:00
btn_shape - > set_icon_alignment ( HORIZONTAL_ALIGNMENT_CENTER ) ;
2024-11-07 13:27:11 +01:00
btn_shape - > set_focus_mode ( FOCUS_ALL ) ;
2022-06-30 17:04:32 +05:30
2024-11-20 23:26:52 +01:00
add_shape ( memnew ( ColorPickerShapeRectangle ( this ) ) ) ;
add_shape ( memnew ( ColorPickerShapeWheel ( this ) ) ) ;
add_shape ( memnew ( ColorPickerShapeVHSCircle ( this ) ) ) ;
add_shape ( memnew ( ColorPickerShapeOKHSLCircle ( this ) ) ) ;
2025-06-07 22:30:40 +08:00
add_shape ( memnew ( ColorPickerShapeOKHSRectangle ( this ) ) ) ;
add_shape ( memnew ( ColorPickerShapeOKHLRectangle ( this ) ) ) ;
2022-06-30 17:04:32 +05:30
shape_popup = btn_shape - > get_popup ( ) ;
2024-11-20 23:26:52 +01:00
{
int i = 0 ;
for ( const ColorPickerShape * shape : shapes ) {
2025-06-07 22:30:40 +08:00
shape_popup - > add_radio_check_item ( shape - > get_name ( ) , index_to_shape ( i ) ) ;
2024-11-20 23:26:52 +01:00
i + + ;
}
}
2025-06-07 22:30:40 +08:00
shape_popup - > set_item_checked ( get_current_shape_index ( ) , true ) ;
2024-05-14 14:13:31 +02:00
shape_popup - > connect ( SceneStringName ( id_pressed ) , callable_mp ( this , & ColorPicker : : set_picker_shape ) ) ;
2024-11-07 13:27:11 +01:00
shape_popup - > connect ( " about_to_popup " , callable_mp ( this , & ColorPicker : : _block_input_on_popup_show ) ) ;
shape_popup - > connect ( SNAME ( " popup_hide " ) , callable_mp ( this , & ColorPicker : : _enable_input_on_popup_hide ) ) ;
2022-06-30 17:04:32 +05:30
2024-11-20 23:26:52 +01:00
add_mode ( memnew ( ColorModeRGB ( this ) ) ) ;
add_mode ( memnew ( ColorModeHSV ( this ) ) ) ;
2025-05-23 12:45:29 +08:00
add_mode ( memnew ( ColorModeLinear ( this ) ) ) ;
2024-11-20 23:26:52 +01:00
add_mode ( memnew ( ColorModeOKHSL ( this ) ) ) ;
2022-06-30 17:04:32 +05:30
2022-10-21 23:20:28 -04:00
mode_hbc = memnew ( HBoxContainer ) ;
2023-06-20 12:47:52 +02:00
real_vbox - > add_child ( mode_hbc ) ;
2022-06-30 17:04:32 +05:30
mode_group . instantiate ( ) ;
2019-12-28 18:08:16 +01:00
2022-06-30 17:04:32 +05:30
for ( int i = 0 ; i < MODE_BUTTON_COUNT ; i + + ) {
mode_btns [ i ] = memnew ( Button ) ;
mode_hbc - > add_child ( mode_btns [ i ] ) ;
2024-11-07 13:27:11 +01:00
mode_btns [ i ] - > set_focus_mode ( FOCUS_ALL ) ;
2022-06-30 17:04:32 +05:30
mode_btns [ i ] - > set_h_size_flags ( SIZE_EXPAND_FILL ) ;
mode_btns [ i ] - > set_toggle_mode ( true ) ;
mode_btns [ i ] - > set_text ( modes [ i ] - > get_name ( ) ) ;
mode_btns [ i ] - > set_button_group ( mode_group ) ;
2024-05-14 09:40:21 +02:00
mode_btns [ i ] - > connect ( SceneStringName ( pressed ) , callable_mp ( this , & ColorPicker : : set_color_mode ) . bind ( ( ColorModeType ) i ) ) ;
2022-06-30 17:04:32 +05:30
}
mode_btns [ 0 ] - > set_pressed ( true ) ;
btn_mode = memnew ( MenuButton ) ;
btn_mode - > set_flat ( false ) ;
mode_hbc - > add_child ( btn_mode ) ;
btn_mode - > set_toggle_mode ( true ) ;
2025-06-12 07:55:29 +03:00
btn_mode - > set_accessibility_name ( ETR ( " Select a picker mode. " ) ) ;
2023-12-15 20:56:06 -03:00
btn_mode - > set_tooltip_text ( ETR ( " Select a picker mode. " ) ) ;
2024-11-07 13:27:11 +01:00
btn_mode - > set_focus_mode ( FOCUS_ALL ) ;
2022-06-30 17:04:32 +05:30
mode_popup = btn_mode - > get_popup ( ) ;
2024-11-20 23:26:52 +01:00
{
int i = 0 ;
for ( const ColorMode * mode : modes ) {
mode_popup - > add_radio_check_item ( mode - > get_name ( ) , i ) ;
i + + ;
}
2022-06-30 17:04:32 +05:30
}
mode_popup - > add_separator ( ) ;
2024-09-24 15:49:30 +08:00
mode_popup - > add_check_item ( ETR ( " Colorized Sliders " ) , MODE_MAX ) ;
2022-06-30 17:04:32 +05:30
mode_popup - > set_item_checked ( current_mode , true ) ;
mode_popup - > set_item_checked ( MODE_MAX + 1 , true ) ;
2024-05-14 14:13:31 +02:00
mode_popup - > connect ( SceneStringName ( id_pressed ) , callable_mp ( this , & ColorPicker : : _set_mode_popup_value ) ) ;
2024-11-07 13:27:11 +01:00
mode_popup - > connect ( " about_to_popup " , callable_mp ( this , & ColorPicker : : _block_input_on_popup_show ) ) ;
mode_popup - > connect ( SNAME ( " popup_hide " ) , callable_mp ( this , & ColorPicker : : _enable_input_on_popup_hide ) ) ;
2014-02-09 22:10:30 -03:00
2022-10-21 23:20:28 -04:00
slider_gc = memnew ( GridContainer ) ;
2014-02-09 22:10:30 -03:00
2025-01-17 18:12:36 +02:00
real_vbox - > add_child ( slider_gc ) ;
2022-10-21 23:20:28 -04:00
slider_gc - > set_h_size_flags ( SIZE_EXPAND_FILL ) ;
slider_gc - > set_columns ( 3 ) ;
2014-02-09 22:10:30 -03:00
2025-05-23 12:45:29 +08:00
for ( int i = 0 ; i < SLIDER_MAX ; i + + ) {
2022-10-21 23:20:28 -04:00
create_slider ( slider_gc , i ) ;
2014-02-09 22:10:30 -03:00
}
2022-05-29 20:47:37 +05:30
alpha_label - > set_text ( " A " ) ;
2014-02-09 22:10:30 -03:00
2025-05-23 12:45:29 +08:00
intensity_label - > set_text ( " I " ) ;
intensity_slider - > set_min ( - 10 ) ;
intensity_slider - > set_max ( 10 ) ;
intensity_slider - > set_step ( 0.001 ) ;
intensity_value - > set_allow_greater ( true ) ;
intensity_value - > set_custom_arrow_step ( 1 ) ;
2022-10-21 23:20:28 -04:00
hex_hbc = memnew ( HBoxContainer ) ;
hex_hbc - > set_alignment ( ALIGNMENT_BEGIN ) ;
2025-01-17 18:12:36 +02:00
real_vbox - > add_child ( hex_hbc ) ;
2025-05-23 12:45:29 +08:00
hex_label = memnew ( Label ( ETR ( " Hex " ) ) ) ;
hex_hbc - > add_child ( hex_label ) ;
2019-01-26 19:07:32 -02:00
2022-05-29 20:47:37 +05:30
text_type = memnew ( Button ) ;
2022-10-21 23:20:28 -04:00
hex_hbc - > add_child ( text_type ) ;
2025-04-29 10:42:28 +08:00
text_type - > set_auto_translate_mode ( AUTO_TRANSLATE_MODE_DISABLED ) ;
text_type - > set_tooltip_auto_translate_mode ( AUTO_TRANSLATE_MODE_ALWAYS ) ;
2019-01-26 19:07:32 -02:00
text_type - > set_text ( " # " ) ;
2025-04-29 10:42:28 +08:00
# ifdef TOOLS_ENABLED
2019-01-26 19:07:32 -02:00
if ( Engine : : get_singleton ( ) - > is_editor_hint ( ) ) {
2025-04-29 10:42:28 +08:00
text_type - > set_tooltip_text ( TTRC ( " Switch between hexadecimal and code values. " ) ) ;
2024-05-14 09:40:21 +02:00
text_type - > connect ( SceneStringName ( pressed ) , callable_mp ( this , & ColorPicker : : _text_type_toggled ) ) ;
2019-01-26 19:07:32 -02:00
} else {
2025-04-29 10:42:28 +08:00
text_type - > set_accessibility_name ( ETR ( " Hexadecimal Values " ) ) ;
# else
{
text_type - > set_accessibility_name ( ETR ( " Hexadecimal Values " ) ) ;
# endif // TOOLS_ENABLED
2019-01-26 19:07:32 -02:00
text_type - > set_flat ( true ) ;
}
2016-01-26 19:10:56 -03:00
2022-05-29 20:47:37 +05:30
c_text = memnew ( LineEdit ) ;
2022-10-21 23:20:28 -04:00
hex_hbc - > add_child ( c_text ) ;
2023-04-10 21:06:02 +02:00
c_text - > set_h_size_flags ( SIZE_EXPAND_FILL ) ;
2022-10-16 20:37:35 +08:00
c_text - > set_select_all_on_focus ( true ) ;
2025-06-12 07:55:29 +03:00
c_text - > set_accessibility_name ( ETR ( " Hex code or named color " ) ) ;
2023-12-15 20:56:06 -03:00
c_text - > set_tooltip_text ( ETR ( " Enter a hex code ( \" #ff0000 \" ) or named color ( \" red \" ). " ) ) ;
c_text - > set_placeholder ( ETR ( " Hex code or named color " ) ) ;
2024-11-02 16:15:39 +01:00
c_text - > connect ( SceneStringName ( text_submitted ) , callable_mp ( this , & ColorPicker : : _html_submitted ) ) ;
2024-05-14 11:42:00 +02:00
c_text - > connect ( SceneStringName ( text_changed ) , callable_mp ( this , & ColorPicker : : _text_changed ) ) ;
2024-05-13 16:56:03 +02:00
c_text - > connect ( SceneStringName ( focus_exited ) , callable_mp ( this , & ColorPicker : : _html_focus_exit ) ) ;
2018-03-09 21:02:58 +01:00
2014-02-09 22:10:30 -03:00
_update_controls ( ) ;
updating = false ;
2015-12-23 23:17:09 -03:00
2025-01-22 13:42:30 +01:00
swatches_vbc = memnew ( VBoxContainer ) ;
real_vbox - > add_child ( swatches_vbc ) ;
2022-05-29 20:47:37 +05:30
preset_container = memnew ( GridContainer ) ;
2019-07-30 12:03:00 +01:00
preset_container - > set_h_size_flags ( SIZE_EXPAND_FILL ) ;
2022-06-30 17:04:32 +05:30
preset_container - > set_columns ( PRESET_COLUMN_COUNT ) ;
preset_container - > hide ( ) ;
preset_group . instantiate ( ) ;
2024-05-18 10:45:16 +07:00
HBoxContainer * palette_box = memnew ( HBoxContainer ) ;
palette_box - > set_h_size_flags ( SIZE_EXPAND_FILL ) ;
2025-01-22 13:42:30 +01:00
swatches_vbc - > add_child ( palette_box ) ;
2024-05-18 10:45:16 +07:00
btn_preset = memnew ( Button ) ;
2025-03-12 20:12:33 +08:00
btn_preset - > set_text ( ETR ( " Swatches " ) ) ;
2022-06-30 17:04:32 +05:30
btn_preset - > set_flat ( true ) ;
btn_preset - > set_toggle_mode ( true ) ;
2024-11-07 13:27:11 +01:00
btn_preset - > set_focus_mode ( FOCUS_ALL ) ;
2022-06-30 17:04:32 +05:30
btn_preset - > set_text_alignment ( HORIZONTAL_ALIGNMENT_LEFT ) ;
2025-01-22 16:33:53 +01:00
btn_preset - > set_h_size_flags ( SIZE_EXPAND_FILL ) ;
2024-06-01 13:15:13 +03:00
btn_preset - > connect ( SceneStringName ( toggled ) , callable_mp ( this , & ColorPicker : : _show_hide_preset ) . bind ( btn_preset , preset_container ) ) ;
2024-05-18 10:45:16 +07:00
palette_box - > add_child ( btn_preset ) ;
2025-01-22 19:23:29 +01:00
menu_btn = memnew ( MenuButton ) ;
2025-04-29 10:42:28 +08:00
menu_btn - > set_flat ( false ) ;
2024-11-07 13:27:11 +01:00
menu_btn - > set_focus_mode ( FOCUS_ALL ) ;
2024-05-18 10:45:16 +07:00
menu_btn - > set_tooltip_text ( ETR ( " Show all options available. " ) ) ;
2025-01-22 19:23:29 +01:00
menu_btn - > connect ( " about_to_popup " , callable_mp ( this , & ColorPicker : : _update_menu_items ) ) ;
2024-05-18 10:45:16 +07:00
palette_box - > add_child ( menu_btn ) ;
2025-01-22 19:23:29 +01:00
options_menu = menu_btn - > get_popup ( ) ;
options_menu - > connect ( SceneStringName ( id_pressed ) , callable_mp ( this , & ColorPicker : : _options_menu_cbk ) ) ;
2024-11-07 13:27:11 +01:00
options_menu - > connect ( " about_to_popup " , callable_mp ( this , & ColorPicker : : _block_input_on_popup_show ) ) ;
options_menu - > connect ( SNAME ( " popup_hide " ) , callable_mp ( this , & ColorPicker : : _enable_input_on_popup_hide ) ) ;
2025-01-22 19:23:29 +01:00
2024-05-18 10:45:16 +07:00
palette_name = memnew ( Label ) ;
palette_name - > hide ( ) ;
palette_name - > set_mouse_filter ( MOUSE_FILTER_PASS ) ;
2025-01-22 13:42:30 +01:00
swatches_vbc - > add_child ( palette_name ) ;
2022-06-30 17:04:32 +05:30
2025-01-22 13:42:30 +01:00
swatches_vbc - > add_child ( preset_container ) ;
2015-12-23 23:17:09 -03:00
2022-06-30 17:04:32 +05:30
recent_preset_hbc = memnew ( HBoxContainer ) ;
recent_preset_hbc - > set_v_size_flags ( SIZE_SHRINK_BEGIN ) ;
recent_preset_hbc - > hide ( ) ;
recent_preset_group . instantiate ( ) ;
2024-09-24 15:49:30 +08:00
btn_recent_preset = memnew ( Button ( ETR ( " Recent Colors " ) ) ) ;
2022-06-30 17:04:32 +05:30
btn_recent_preset - > set_flat ( true ) ;
btn_recent_preset - > set_toggle_mode ( true ) ;
2024-11-07 13:27:11 +01:00
btn_recent_preset - > set_focus_mode ( FOCUS_ALL ) ;
2022-06-30 17:04:32 +05:30
btn_recent_preset - > set_text_alignment ( HORIZONTAL_ALIGNMENT_LEFT ) ;
2024-06-01 13:15:13 +03:00
btn_recent_preset - > connect ( SceneStringName ( toggled ) , callable_mp ( this , & ColorPicker : : _show_hide_preset ) . bind ( btn_recent_preset , recent_preset_hbc ) ) ;
2025-01-22 13:42:30 +01:00
swatches_vbc - > add_child ( btn_recent_preset ) ;
2022-06-30 17:04:32 +05:30
2025-01-22 13:42:30 +01:00
swatches_vbc - > add_child ( recent_preset_hbc ) ;
2022-06-30 17:04:32 +05:30
set_pick_color ( Color ( 1 , 1 , 1 ) ) ;
2022-05-29 20:47:37 +05:30
btn_add_preset = memnew ( Button ) ;
2021-11-24 20:58:47 -06:00
btn_add_preset - > set_icon_alignment ( HORIZONTAL_ALIGNMENT_CENTER ) ;
2023-12-15 20:56:06 -03:00
btn_add_preset - > set_tooltip_text ( ETR ( " Add current color as a preset. " ) ) ;
2024-05-14 09:40:21 +02:00
btn_add_preset - > connect ( SceneStringName ( pressed ) , callable_mp ( this , & ColorPicker : : _add_preset_pressed ) ) ;
2021-08-18 02:09:48 +02:00
preset_container - > add_child ( btn_add_preset ) ;
2025-04-18 00:05:49 +03:00
perm_hb = memnew ( HBoxContainer ) ;
perm_hb - > set_alignment ( BoxContainer : : ALIGNMENT_CENTER ) ;
LinkButton * perm_link = memnew ( LinkButton ) ;
perm_link - > set_text ( ETR ( " Screen Recording permission missing! " ) ) ;
perm_link - > set_tooltip_text ( ETR ( " Screen Recording permission is required to pick colors from the other application windows. \n Click here to request access... " ) ) ;
perm_link - > connect ( SceneStringName ( pressed ) , callable_mp ( this , & ColorPicker : : _req_permission ) ) ;
perm_hb - > add_child ( perm_link ) ;
real_vbox - > add_child ( perm_hb ) ;
perm_hb - > set_visible ( false ) ;
}
void ColorPicker : : _req_permission ( ) {
# ifdef MACOS_ENABLED
OS : : get_singleton ( ) - > request_permission ( " macos.permission.RECORD_SCREEN " ) ;
# endif
2014-02-09 22:10:30 -03:00
}
2022-05-29 20:47:37 +05:30
ColorPicker : : ~ ColorPicker ( ) {
2024-11-20 23:26:52 +01:00
for ( ColorMode * mode : modes ) {
memdelete ( mode ) ;
}
for ( ColorPickerShape * shape : shapes ) {
memdelete ( shape ) ;
2022-05-29 20:47:37 +05:30
}
}
2014-02-09 22:10:30 -03:00
/////////////////
2024-02-22 18:01:28 -06:00
void ColorPickerPopupPanel : : _input_from_window ( const Ref < InputEvent > & p_event ) {
if ( p_event - > is_action_pressed ( SNAME ( " ui_accept " ) , false , true ) ) {
_close_pressed ( ) ;
}
PopupPanel : : _input_from_window ( p_event ) ;
}
/////////////////
2020-01-05 18:01:24 +01:00
void ColorPickerButton : : _about_to_popup ( ) {
2024-11-07 13:27:11 +01:00
if ( ! get_tree ( ) - > get_root ( ) - > is_embedding_subwindows ( ) ) {
get_viewport ( ) - > set_disable_input ( true ) ;
}
2020-01-05 18:01:24 +01:00
set_pressed ( true ) ;
2021-05-10 16:59:46 +02:00
if ( picker ) {
picker - > set_old_color ( color ) ;
}
2020-01-05 18:01:24 +01:00
}
2014-02-09 22:10:30 -03:00
void ColorPickerButton : : _color_changed ( const Color & p_color ) {
2018-05-15 17:12:35 -03:00
color = p_color ;
2025-03-21 16:42:23 +02:00
queue_accessibility_update ( ) ;
2022-08-13 23:21:24 +02:00
queue_redraw ( ) ;
2021-07-17 18:22:52 -03:00
emit_signal ( SNAME ( " color_changed " ) , color ) ;
2014-02-09 22:10:30 -03:00
}
2018-04-12 16:47:53 -05:00
void ColorPickerButton : : _modal_closed ( ) {
2024-02-22 18:01:28 -06:00
if ( Input : : get_singleton ( ) - > is_action_just_pressed ( SNAME ( " ui_cancel " ) ) ) {
set_pick_color ( picker - > get_old_color ( ) ) ;
emit_signal ( SNAME ( " color_changed " ) , color ) ;
}
2021-07-17 18:22:52 -03:00
emit_signal ( SNAME ( " popup_closed " ) ) ;
2020-09-09 21:38:29 +03:00
set_pressed ( false ) ;
2024-11-07 13:27:11 +01:00
if ( ! get_tree ( ) - > get_root ( ) - > is_embedding_subwindows ( ) ) {
get_viewport ( ) - > set_disable_input ( false ) ;
}
2018-04-12 16:47:53 -05:00
}
2014-02-09 22:10:30 -03:00
void ColorPickerButton : : pressed ( ) {
2018-05-15 17:12:35 -03:00
_update_picker ( ) ;
2020-03-19 23:32:09 -03:00
2023-01-30 13:27:15 +01:00
Size2 minsize = popup - > get_contents_minimum_size ( ) ;
float viewport_height = get_viewport_rect ( ) . size . y ;
2021-08-30 08:42:33 -07:00
2022-03-06 00:57:42 +01:00
popup - > reset_size ( ) ;
2021-08-18 02:09:48 +02:00
picker - > _update_presets ( ) ;
2022-06-30 17:04:32 +05:30
picker - > _update_recent_presets ( ) ;
2020-03-19 23:32:09 -03:00
2023-01-30 13:27:15 +01:00
// Determine in which direction to show the popup. By default popup horizontally centered below the button.
// But if the popup doesn't fit below and the button is in the bottom half of the viewport, show above.
bool show_above = false ;
if ( get_global_position ( ) . y + get_size ( ) . y + minsize . y > viewport_height & & get_global_position ( ) . y * 2 + get_size ( ) . y > viewport_height ) {
show_above = true ;
2020-03-19 23:32:09 -03:00
}
2023-01-30 13:27:15 +01:00
float h_offset = ( get_size ( ) . x - minsize . x ) / 2 ;
float v_offset = show_above ? - minsize . y : get_size ( ) . y ;
popup - > set_position ( get_screen_position ( ) + Vector2 ( h_offset , v_offset ) ) ;
2014-02-09 22:10:30 -03:00
popup - > popup ( ) ;
2024-11-07 13:27:11 +01:00
if ( ! picker - > is_hex_visible ( ) & & picker - > get_picker_shape ( ) ! = ColorPicker : : SHAPE_NONE ) {
callable_mp ( picker , & ColorPicker : : set_focus_on_picker_shape ) . call_deferred ( ) ;
} else if ( DisplayServer : : get_singleton ( ) - > has_hardware_keyboard ( ) ) {
2024-10-04 15:43:55 +05:30
picker - > set_focus_on_line_edit ( ) ;
}
2014-02-09 22:10:30 -03:00
}
void ColorPickerButton : : _notification ( int p_what ) {
2019-04-22 22:28:38 -03:00
switch ( p_what ) {
2025-03-21 16:42:23 +02:00
case NOTIFICATION_ACCESSIBILITY_UPDATE : {
RID ae = get_accessibility_element ( ) ;
ERR_FAIL_COND ( ae . is_null ( ) ) ;
DisplayServer : : get_singleton ( ) - > accessibility_update_set_role ( ae , DisplayServer : : AccessibilityRole : : ROLE_BUTTON ) ;
DisplayServer : : get_singleton ( ) - > accessibility_update_set_popup_type ( ae , DisplayServer : : AccessibilityPopupType : : POPUP_DIALOG ) ;
DisplayServer : : get_singleton ( ) - > accessibility_update_set_color_value ( ae , color ) ;
} break ;
2019-04-22 22:28:38 -03:00
case NOTIFICATION_DRAW : {
2023-04-03 18:01:11 +02:00
const Rect2 r = Rect2 ( theme_cache . normal_style - > get_offset ( ) , get_size ( ) - theme_cache . normal_style - > get_minimum_size ( ) ) ;
draw_texture_rect ( theme_cache . background_icon , r , true ) ;
2019-04-22 22:28:38 -03:00
draw_rect ( r , color ) ;
2019-09-27 01:07:41 +02:00
if ( color . r > 1 | | color . g > 1 | | color . b > 1 ) {
// Draw an indicator to denote that the color is "overbright" and can't be displayed accurately in the preview
2023-04-03 18:01:11 +02:00
draw_texture ( theme_cache . overbright_indicator , theme_cache . normal_style - > get_offset ( ) ) ;
2019-09-27 01:07:41 +02:00
}
2019-04-22 22:28:38 -03:00
} break ;
2022-02-15 18:06:48 +01:00
2020-03-04 13:36:09 -03:00
case NOTIFICATION_WM_CLOSE_REQUEST : {
2020-05-14 16:41:43 +02:00
if ( popup ) {
2019-04-22 22:28:38 -03:00
popup - > hide ( ) ;
2020-05-14 16:41:43 +02:00
}
2019-04-22 22:28:38 -03:00
} break ;
2019-04-18 15:50:35 -07:00
2022-02-15 18:06:48 +01:00
case NOTIFICATION_VISIBILITY_CHANGED : {
if ( popup & & ! is_visible_in_tree ( ) ) {
popup - > hide ( ) ;
}
} break ;
2019-04-18 15:50:35 -07:00
}
2014-02-09 22:10:30 -03:00
}
2017-01-14 11:07:57 -03:00
void ColorPickerButton : : set_pick_color ( const Color & p_color ) {
2022-03-16 15:50:48 +08:00
if ( color = = p_color ) {
return ;
}
2018-05-15 17:12:35 -03:00
color = p_color ;
if ( picker ) {
picker - > set_pick_color ( p_color ) ;
}
2025-03-21 16:42:23 +02:00
queue_accessibility_update ( ) ;
2022-08-13 23:21:24 +02:00
queue_redraw ( ) ;
2014-02-09 22:10:30 -03:00
}
2020-05-14 14:29:06 +02:00
2017-01-14 11:07:57 -03:00
Color ColorPickerButton : : get_pick_color ( ) const {
2018-05-15 17:12:35 -03:00
return color ;
2014-02-09 22:10:30 -03:00
}
void ColorPickerButton : : set_edit_alpha ( bool p_show ) {
2022-03-16 15:50:48 +08:00
if ( edit_alpha = = p_show ) {
return ;
}
2018-05-15 17:12:35 -03:00
edit_alpha = p_show ;
if ( picker ) {
picker - > set_edit_alpha ( p_show ) ;
}
2014-02-09 22:10:30 -03:00
}
bool ColorPickerButton : : is_editing_alpha ( ) const {
2018-05-15 17:12:35 -03:00
return edit_alpha ;
2014-02-09 22:10:30 -03:00
}
2025-05-23 12:45:29 +08:00
void ColorPickerButton : : set_edit_intensity ( bool p_show ) {
if ( edit_intensity = = p_show ) {
return ;
}
edit_intensity = p_show ;
if ( picker ) {
picker - > set_edit_intensity ( p_show ) ;
}
}
bool ColorPickerButton : : is_editing_intensity ( ) const {
return edit_intensity ;
}
2018-05-15 17:12:35 -03:00
ColorPicker * ColorPickerButton : : get_picker ( ) {
_update_picker ( ) ;
2016-06-19 02:08:22 -03:00
return picker ;
}
2018-07-10 15:06:36 +02:00
PopupPanel * ColorPickerButton : : get_popup ( ) {
_update_picker ( ) ;
2017-12-01 22:58:53 +02:00
return popup ;
}
2018-05-15 17:12:35 -03:00
void ColorPickerButton : : _update_picker ( ) {
if ( ! picker ) {
2024-02-22 18:01:28 -06:00
popup = memnew ( ColorPickerPopupPanel ) ;
2020-03-19 23:32:09 -03:00
popup - > set_wrap_controls ( true ) ;
2018-05-15 17:12:35 -03:00
picker = memnew ( ColorPicker ) ;
2022-03-18 19:02:57 -05:00
picker - > set_anchors_and_offsets_preset ( PRESET_FULL_RECT ) ;
2018-05-15 17:12:35 -03:00
popup - > add_child ( picker ) ;
2021-08-25 15:49:30 +02:00
add_child ( popup , false , INTERNAL_MODE_FRONT ) ;
2020-02-21 18:28:45 +01:00
picker - > connect ( " color_changed " , callable_mp ( this , & ColorPickerButton : : _color_changed ) ) ;
2020-01-05 18:01:24 +01:00
popup - > connect ( " about_to_popup " , callable_mp ( this , & ColorPickerButton : : _about_to_popup ) ) ;
2020-09-09 21:38:29 +03:00
popup - > connect ( " popup_hide " , callable_mp ( this , & ColorPickerButton : : _modal_closed ) ) ;
2025-08-21 13:54:17 +02:00
popup - > connect ( " tree_exiting " , callable_mp ( this , & ColorPickerButton : : _modal_closed ) ) ;
2024-05-13 16:56:03 +02:00
picker - > connect ( SceneStringName ( minimum_size_changed ) , callable_mp ( ( Window * ) popup , & Window : : reset_size ) ) ;
2018-05-15 17:12:35 -03:00
picker - > set_pick_color ( color ) ;
picker - > set_edit_alpha ( edit_alpha ) ;
2025-05-23 12:45:29 +08:00
picker - > set_edit_intensity ( edit_intensity ) ;
2020-01-05 18:01:24 +01:00
picker - > set_display_old_color ( true ) ;
2021-07-17 18:22:52 -03:00
emit_signal ( SNAME ( " picker_created " ) ) ;
2018-05-15 17:12:35 -03:00
}
}
2014-02-09 22:10:30 -03:00
void ColorPickerButton : : _bind_methods ( ) {
2017-02-12 01:11:37 +01:00
ClassDB : : bind_method ( D_METHOD ( " set_pick_color " , " color " ) , & ColorPickerButton : : set_pick_color ) ;
2017-02-13 12:47:24 +01:00
ClassDB : : bind_method ( D_METHOD ( " get_pick_color " ) , & ColorPickerButton : : get_pick_color ) ;
2017-08-09 13:19:41 +02:00
ClassDB : : bind_method ( D_METHOD ( " get_picker " ) , & ColorPickerButton : : get_picker ) ;
2017-12-01 22:58:53 +02:00
ClassDB : : bind_method ( D_METHOD ( " get_popup " ) , & ColorPickerButton : : get_popup ) ;
2017-02-12 01:11:37 +01:00
ClassDB : : bind_method ( D_METHOD ( " set_edit_alpha " , " show " ) , & ColorPickerButton : : set_edit_alpha ) ;
ClassDB : : bind_method ( D_METHOD ( " is_editing_alpha " ) , & ColorPickerButton : : is_editing_alpha ) ;
2025-05-23 12:45:29 +08:00
ClassDB : : bind_method ( D_METHOD ( " set_edit_intensity " , " show " ) , & ColorPickerButton : : set_edit_intensity ) ;
ClassDB : : bind_method ( D_METHOD ( " is_editing_intensity " ) , & ColorPickerButton : : is_editing_intensity ) ;
2020-01-05 18:01:24 +01:00
ClassDB : : bind_method ( D_METHOD ( " _about_to_popup " ) , & ColorPickerButton : : _about_to_popup ) ;
2014-02-09 22:10:30 -03:00
ADD_SIGNAL ( MethodInfo ( " color_changed " , PropertyInfo ( Variant : : COLOR , " color " ) ) ) ;
2018-04-12 16:47:53 -05:00
ADD_SIGNAL ( MethodInfo ( " popup_closed " ) ) ;
2019-08-30 16:25:15 -04:00
ADD_SIGNAL ( MethodInfo ( " picker_created " ) ) ;
2014-02-09 22:10:30 -03:00
ADD_PROPERTY ( PropertyInfo ( Variant : : COLOR , " color " ) , " set_pick_color " , " get_pick_color " ) ;
2017-02-13 12:47:24 +01:00
ADD_PROPERTY ( PropertyInfo ( Variant : : BOOL , " edit_alpha " ) , " set_edit_alpha " , " is_editing_alpha " ) ;
2025-05-23 12:45:29 +08:00
ADD_PROPERTY ( PropertyInfo ( Variant : : BOOL , " edit_intensity " ) , " set_edit_intensity " , " is_editing_intensity " ) ;
2023-09-08 21:00:10 +02:00
BIND_THEME_ITEM_CUSTOM ( Theme : : DATA_TYPE_STYLEBOX , ColorPickerButton , normal_style , " normal " ) ;
BIND_THEME_ITEM_CUSTOM ( Theme : : DATA_TYPE_ICON , ColorPickerButton , background_icon , " bg " ) ;
BIND_THEME_ITEM_EXT ( Theme : : DATA_TYPE_ICON , ColorPickerButton , overbright_indicator , " overbright_indicator " , " ColorPicker " ) ;
2014-02-09 22:10:30 -03:00
}
2022-03-04 09:18:44 +01:00
ColorPickerButton : : ColorPickerButton ( const String & p_text ) :
Button ( p_text ) {
2018-09-21 02:18:40 -03:00
set_toggle_mode ( true ) ;
2014-02-09 22:10:30 -03:00
}
2021-08-18 02:09:48 +02:00
/////////////////
void ColorPresetButton : : _notification ( int p_what ) {
switch ( p_what ) {
2025-03-21 16:42:23 +02:00
case NOTIFICATION_ACCESSIBILITY_UPDATE : {
RID ae = get_accessibility_element ( ) ;
ERR_FAIL_COND ( ae . is_null ( ) ) ;
DisplayServer : : get_singleton ( ) - > accessibility_update_set_role ( ae , DisplayServer : : AccessibilityRole : : ROLE_BUTTON ) ;
DisplayServer : : get_singleton ( ) - > accessibility_update_set_color_value ( ae , preset_color ) ;
} break ;
2021-08-18 02:09:48 +02:00
case NOTIFICATION_DRAW : {
const Rect2 r = Rect2 ( Point2 ( 0 , 0 ) , get_size ( ) ) ;
2023-04-03 18:01:11 +02:00
Ref < StyleBox > sb_raw = theme_cache . foreground_style - > duplicate ( ) ;
2021-08-18 02:09:48 +02:00
Ref < StyleBoxFlat > sb_flat = sb_raw ;
Ref < StyleBoxTexture > sb_texture = sb_raw ;
if ( sb_flat . is_valid ( ) ) {
2022-06-30 17:04:32 +05:30
sb_flat - > set_border_width ( SIDE_BOTTOM , 2 ) ;
if ( get_draw_mode ( ) = = DRAW_PRESSED | | get_draw_mode ( ) = = DRAW_HOVER_PRESSED ) {
sb_flat - > set_border_color ( Color ( 1 , 1 , 1 , 1 ) ) ;
} else {
sb_flat - > set_border_color ( Color ( 0 , 0 , 0 , 1 ) ) ;
}
2021-08-18 02:09:48 +02:00
if ( preset_color . a < 1 ) {
// Draw a background pattern when the color is transparent.
sb_flat - > set_bg_color ( Color ( 1 , 1 , 1 ) ) ;
sb_flat - > draw ( get_canvas_item ( ) , r ) ;
Rect2 bg_texture_rect = r . grow_side ( SIDE_LEFT , - sb_flat - > get_margin ( SIDE_LEFT ) ) ;
bg_texture_rect = bg_texture_rect . grow_side ( SIDE_RIGHT , - sb_flat - > get_margin ( SIDE_RIGHT ) ) ;
bg_texture_rect = bg_texture_rect . grow_side ( SIDE_TOP , - sb_flat - > get_margin ( SIDE_TOP ) ) ;
bg_texture_rect = bg_texture_rect . grow_side ( SIDE_BOTTOM , - sb_flat - > get_margin ( SIDE_BOTTOM ) ) ;
2023-04-03 18:01:11 +02:00
draw_texture_rect ( theme_cache . background_icon , bg_texture_rect , true ) ;
2021-08-18 02:09:48 +02:00
sb_flat - > set_bg_color ( preset_color ) ;
}
sb_flat - > set_bg_color ( preset_color ) ;
sb_flat - > draw ( get_canvas_item ( ) , r ) ;
} else if ( sb_texture . is_valid ( ) ) {
if ( preset_color . a < 1 ) {
// Draw a background pattern when the color is transparent.
bool use_tile_texture = ( sb_texture - > get_h_axis_stretch_mode ( ) = = StyleBoxTexture : : AxisStretchMode : : AXIS_STRETCH_MODE_TILE ) | | ( sb_texture - > get_h_axis_stretch_mode ( ) = = StyleBoxTexture : : AxisStretchMode : : AXIS_STRETCH_MODE_TILE_FIT ) ;
2023-04-03 18:01:11 +02:00
draw_texture_rect ( theme_cache . background_icon , r , use_tile_texture ) ;
2021-08-18 02:09:48 +02:00
}
sb_texture - > set_modulate ( preset_color ) ;
sb_texture - > draw ( get_canvas_item ( ) , r ) ;
} else {
WARN_PRINT ( " Unsupported StyleBox used for ColorPresetButton. Use StyleBoxFlat or StyleBoxTexture instead. " ) ;
}
2024-11-07 13:27:11 +01:00
2025-09-03 20:39:18 -03:00
if ( has_focus ( true ) ) {
2024-11-07 13:27:11 +01:00
RID ci = get_canvas_item ( ) ;
theme_cache . focus_style - > draw ( ci , Rect2 ( Point2 ( ) , get_size ( ) ) ) ;
}
2025-05-23 12:45:29 +08:00
if ( is_color_overbright ( preset_color ) ) {
2021-08-18 02:09:48 +02:00
// Draw an indicator to denote that the color is "overbright" and can't be displayed accurately in the preview
2023-04-03 18:01:11 +02:00
draw_texture ( theme_cache . overbright_indicator , Vector2 ( 0 , 0 ) ) ;
2021-08-18 02:09:48 +02:00
}
} break ;
}
}
void ColorPresetButton : : set_preset_color ( const Color & p_color ) {
preset_color = p_color ;
2025-03-21 16:42:23 +02:00
queue_accessibility_update ( ) ;
2021-08-18 02:09:48 +02:00
}
Color ColorPresetButton : : get_preset_color ( ) const {
return preset_color ;
}
2025-04-29 10:42:28 +08:00
String ColorPresetButton : : get_tooltip ( const Point2 & p_pos ) const {
Color color = get_preset_color ( ) ;
if ( recent ) {
2025-05-23 12:45:29 +08:00
return vformat ( atr ( ETR ( " Color: %s \n LMB: Apply color " ) ) , color_to_string ( color , color . a < 1 ) ) ;
2025-04-29 10:42:28 +08:00
}
2025-05-23 12:45:29 +08:00
return vformat ( atr ( ETR ( " Color: %s \n LMB: Apply color \n RMB: Remove preset " ) ) , color_to_string ( color , color . a < 1 ) ) ;
2025-04-29 10:42:28 +08:00
}
2023-09-08 21:00:10 +02:00
void ColorPresetButton : : _bind_methods ( ) {
BIND_THEME_ITEM_CUSTOM ( Theme : : DATA_TYPE_STYLEBOX , ColorPresetButton , foreground_style , " preset_fg " ) ;
2024-11-07 13:27:11 +01:00
BIND_THEME_ITEM_CUSTOM ( Theme : : DATA_TYPE_STYLEBOX , ColorPresetButton , focus_style , " preset_focus " ) ;
2023-09-08 21:00:10 +02:00
BIND_THEME_ITEM_CUSTOM ( Theme : : DATA_TYPE_ICON , ColorPresetButton , background_icon , " preset_bg " ) ;
BIND_THEME_ITEM ( Theme : : DATA_TYPE_ICON , ColorPresetButton , overbright_indicator ) ;
}
2025-04-29 10:42:28 +08:00
ColorPresetButton : : ColorPresetButton ( Color p_color , int p_size , bool p_recent ) {
2021-08-18 02:09:48 +02:00
preset_color = p_color ;
2025-04-29 10:42:28 +08:00
recent = p_recent ;
2022-06-30 17:04:32 +05:30
set_toggle_mode ( true ) ;
set_custom_minimum_size ( Size2 ( p_size , p_size ) ) ;
2025-05-23 12:45:29 +08:00
set_accessibility_name ( vformat ( atr ( ETR ( " Color: %s " ) ) , color_to_string ( p_color , p_color . a < 1 ) ) ) ;
2025-04-29 10:42:28 +08:00
set_tooltip_auto_translate_mode ( AUTO_TRANSLATE_MODE_DISABLED ) ;
2021-08-18 02:09:48 +02:00
}
ColorPresetButton : : ~ ColorPresetButton ( ) {
}