瀏覽代碼

ColorPicker: Add intensity slider

Add intensity slider to all color modes. Replace raw mode by linear mode, which uses linear color space.

When color is overbright, automatically switch hex text to script text. Allow executing expression in script text field to set color. Add the "script" icon to the default theme.
LuoZhihao 2 月之前
父節點
當前提交
8a9409257b

+ 11 - 3
doc/classes/ColorPicker.xml

@@ -73,6 +73,9 @@
 		<member name="edit_alpha" type="bool" setter="set_edit_alpha" getter="is_editing_alpha" default="true">
 		<member name="edit_alpha" type="bool" setter="set_edit_alpha" getter="is_editing_alpha" default="true">
 			If [code]true[/code], shows an alpha channel slider (opacity).
 			If [code]true[/code], shows an alpha channel slider (opacity).
 		</member>
 		</member>
+		<member name="edit_intensity" type="bool" setter="set_edit_intensity" getter="is_editing_intensity" default="true">
+			If [code]true[/code], shows an intensity slider. The intensity is applied as follows: multiply the color by [code]2 ** intensity[/code] in linear RGB space, and then convert it back to sRGB.
+		</member>
 		<member name="hex_visible" type="bool" setter="set_hex_visible" getter="is_hex_visible" default="true">
 		<member name="hex_visible" type="bool" setter="set_hex_visible" getter="is_hex_visible" default="true">
 			If [code]true[/code], the hex color code input field is visible.
 			If [code]true[/code], the hex color code input field is visible.
 		</member>
 		</member>
@@ -111,13 +114,15 @@
 	</signals>
 	</signals>
 	<constants>
 	<constants>
 		<constant name="MODE_RGB" value="0" enum="ColorModeType">
 		<constant name="MODE_RGB" value="0" enum="ColorModeType">
-			Allows editing the color with Red/Green/Blue sliders.
+			Allows editing the color with Red/Green/Blue sliders in sRGB color space.
 		</constant>
 		</constant>
 		<constant name="MODE_HSV" value="1" enum="ColorModeType">
 		<constant name="MODE_HSV" value="1" enum="ColorModeType">
 			Allows editing the color with Hue/Saturation/Value sliders.
 			Allows editing the color with Hue/Saturation/Value sliders.
 		</constant>
 		</constant>
-		<constant name="MODE_RAW" value="2" enum="ColorModeType">
-			Allows the color R, G, B component values to go beyond 1.0, which can be used for certain special operations that require it (like tinting without darkening or rendering sprites in HDR).
+		<constant name="MODE_RAW" value="2" enum="ColorModeType" deprecated="This is replaced by [constant MODE_LINEAR].">
+		</constant>
+		<constant name="MODE_LINEAR" value="2" enum="ColorModeType">
+			Allows editing the color with Red/Green/Blue sliders in linear color space.
 		</constant>
 		</constant>
 		<constant name="MODE_OKHSL" value="3" enum="ColorModeType">
 		<constant name="MODE_OKHSL" value="3" enum="ColorModeType">
 			Allows editing the color with Hue/Saturation/Lightness sliders.
 			Allows editing the color with Hue/Saturation/Lightness sliders.
@@ -171,6 +176,9 @@
 		<theme_item name="color_hue" data_type="icon" type="Texture2D">
 		<theme_item name="color_hue" data_type="icon" type="Texture2D">
 			Custom texture for the hue selection slider on the right.
 			Custom texture for the hue selection slider on the right.
 		</theme_item>
 		</theme_item>
+		<theme_item name="color_script" data_type="icon" type="Texture2D">
+			The icon for the button that switches color text to hexadecimal.
+		</theme_item>
 		<theme_item name="expanded_arrow" data_type="icon" type="Texture2D">
 		<theme_item name="expanded_arrow" data_type="icon" type="Texture2D">
 			The icon for color preset drop down menu when expanded.
 			The icon for color preset drop down menu when expanded.
 		</theme_item>
 		</theme_item>

+ 3 - 0
doc/classes/ColorPickerButton.xml

@@ -35,6 +35,9 @@
 		<member name="edit_alpha" type="bool" setter="set_edit_alpha" getter="is_editing_alpha" default="true">
 		<member name="edit_alpha" type="bool" setter="set_edit_alpha" getter="is_editing_alpha" default="true">
 			If [code]true[/code], the alpha channel in the displayed [ColorPicker] will be visible.
 			If [code]true[/code], the alpha channel in the displayed [ColorPicker] will be visible.
 		</member>
 		</member>
+		<member name="edit_intensity" type="bool" setter="set_edit_intensity" getter="is_editing_intensity" default="true">
+			If [code]true[/code], the intensity slider in the displayed [ColorPicker] will be visible.
+		</member>
 		<member name="toggle_mode" type="bool" setter="set_toggle_mode" getter="is_toggle_mode" overrides="BaseButton" default="true" />
 		<member name="toggle_mode" type="bool" setter="set_toggle_mode" getter="is_toggle_mode" overrides="BaseButton" default="true" />
 	</members>
 	</members>
 	<signals>
 	<signals>

+ 3 - 0
doc/classes/EditorSettings.xml

@@ -965,6 +965,9 @@
 		<member name="interface/inspector/auto_unfold_foreign_scenes" type="bool" setter="" getter="">
 		<member name="interface/inspector/auto_unfold_foreign_scenes" type="bool" setter="" getter="">
 			If [code]true[/code], automatically expands property groups in the Inspector dock when opening a scene that hasn't been opened previously. If [code]false[/code], all groups remain collapsed by default.
 			If [code]true[/code], automatically expands property groups in the Inspector dock when opening a scene that hasn't been opened previously. If [code]false[/code], all groups remain collapsed by default.
 		</member>
 		</member>
+		<member name="interface/inspector/color_picker_show_intensity" type="bool" setter="" getter="">
+			If [code]true[/code], show the intensity slider in the [ColorPicker]s opened in the editor.
+		</member>
 		<member name="interface/inspector/default_color_picker_mode" type="int" setter="" getter="">
 		<member name="interface/inspector/default_color_picker_mode" type="int" setter="" getter="">
 			The default color picker mode to use when opening [ColorPicker]s in the editor. This mode can be temporarily adjusted on the color picker itself.
 			The default color picker mode to use when opening [ColorPicker]s in the editor. This mode can be temporarily adjusted on the color picker itself.
 		</member>
 		</member>

+ 2 - 0
editor/editor_node.cpp

@@ -4117,9 +4117,11 @@ void EditorNode::setup_color_picker(ColorPicker *p_picker) {
 	p_picker->set_editor_settings(EditorSettings::get_singleton());
 	p_picker->set_editor_settings(EditorSettings::get_singleton());
 	int default_color_mode = EditorSettings::get_singleton()->get_project_metadata("color_picker", "color_mode", EDITOR_GET("interface/inspector/default_color_picker_mode"));
 	int default_color_mode = EditorSettings::get_singleton()->get_project_metadata("color_picker", "color_mode", EDITOR_GET("interface/inspector/default_color_picker_mode"));
 	int picker_shape = EditorSettings::get_singleton()->get_project_metadata("color_picker", "picker_shape", EDITOR_GET("interface/inspector/default_color_picker_shape"));
 	int picker_shape = EditorSettings::get_singleton()->get_project_metadata("color_picker", "picker_shape", EDITOR_GET("interface/inspector/default_color_picker_shape"));
+	bool show_intensity = EditorSettings::get_singleton()->get_project_metadata("color_picker", "show_intensity", EDITOR_GET("interface/inspector/color_picker_show_intensity"));
 
 
 	p_picker->set_color_mode((ColorPicker::ColorModeType)default_color_mode);
 	p_picker->set_color_mode((ColorPicker::ColorModeType)default_color_mode);
 	p_picker->set_picker_shape((ColorPicker::PickerShapeType)picker_shape);
 	p_picker->set_picker_shape((ColorPicker::PickerShapeType)picker_shape);
+	p_picker->set_edit_intensity(show_intensity);
 
 
 	p_picker->set_quick_open_callback(callable_mp(this, &EditorNode::_palette_quick_open_dialog));
 	p_picker->set_quick_open_callback(callable_mp(this, &EditorNode::_palette_quick_open_dialog));
 	p_picker->set_palette_saved_callback(callable_mp(EditorFileSystem::get_singleton(), &EditorFileSystem::update_file));
 	p_picker->set_palette_saved_callback(callable_mp(EditorFileSystem::get_singleton(), &EditorFileSystem::update_file));

+ 1 - 0
editor/editor_settings.cpp

@@ -558,6 +558,7 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) {
 
 
 	EDITOR_SETTING_BASIC(Variant::INT, PROPERTY_HINT_ENUM, "interface/inspector/default_color_picker_mode", (int32_t)ColorPicker::MODE_RGB, "RGB,HSV,RAW,OKHSL")
 	EDITOR_SETTING_BASIC(Variant::INT, PROPERTY_HINT_ENUM, "interface/inspector/default_color_picker_mode", (int32_t)ColorPicker::MODE_RGB, "RGB,HSV,RAW,OKHSL")
 	EDITOR_SETTING_BASIC(Variant::INT, PROPERTY_HINT_ENUM, "interface/inspector/default_color_picker_shape", (int32_t)ColorPicker::SHAPE_OKHSL_CIRCLE, "HSV Rectangle,HSV Rectangle Wheel,VHS Circle,OKHSL Circle")
 	EDITOR_SETTING_BASIC(Variant::INT, PROPERTY_HINT_ENUM, "interface/inspector/default_color_picker_shape", (int32_t)ColorPicker::SHAPE_OKHSL_CIRCLE, "HSV Rectangle,HSV Rectangle Wheel,VHS Circle,OKHSL Circle")
+	EDITOR_SETTING_BASIC(Variant::BOOL, PROPERTY_HINT_NONE, "interface/inspector/color_picker_show_intensity", true, "");
 
 
 	// Theme
 	// Theme
 	EDITOR_SETTING_BASIC(Variant::BOOL, PROPERTY_HINT_ENUM, "interface/theme/follow_system_theme", false, "")
 	EDITOR_SETTING_BASIC(Variant::BOOL, PROPERTY_HINT_ENUM, "interface/theme/follow_system_theme", false, "")

+ 1 - 0
editor/themes/editor_theme_manager.cpp

@@ -1821,6 +1821,7 @@ void EditorThemeManager::_populate_standard_styles(const Ref<EditorTheme> &p_the
 		p_theme->set_icon("bar_arrow", "ColorPicker", p_theme->get_icon(SNAME("ColorPickerBarArrow"), EditorStringName(EditorIcons)));
 		p_theme->set_icon("bar_arrow", "ColorPicker", p_theme->get_icon(SNAME("ColorPickerBarArrow"), EditorStringName(EditorIcons)));
 		p_theme->set_icon("picker_cursor", "ColorPicker", p_theme->get_icon(SNAME("PickerCursor"), EditorStringName(EditorIcons)));
 		p_theme->set_icon("picker_cursor", "ColorPicker", p_theme->get_icon(SNAME("PickerCursor"), EditorStringName(EditorIcons)));
 		p_theme->set_icon("picker_cursor_bg", "ColorPicker", p_theme->get_icon(SNAME("PickerCursorBg"), EditorStringName(EditorIcons)));
 		p_theme->set_icon("picker_cursor_bg", "ColorPicker", p_theme->get_icon(SNAME("PickerCursorBg"), EditorStringName(EditorIcons)));
+		p_theme->set_icon("color_script", "ColorPicker", p_theme->get_icon(SNAME("Script"), EditorStringName(EditorIcons)));
 
 
 		// ColorPickerButton.
 		// ColorPickerButton.
 		p_theme->set_icon("bg", "ColorPickerButton", p_theme->get_icon(SNAME("GuiMiniCheckerboard"), EditorStringName(EditorIcons)));
 		p_theme->set_icon("bg", "ColorPickerButton", p_theme->get_icon(SNAME("GuiMiniCheckerboard"), EditorStringName(EditorIcons)));

+ 176 - 138
scene/gui/color_mode.cpp

@@ -39,13 +39,13 @@ ColorMode::ColorMode(ColorPicker *p_color_picker) {
 }
 }
 
 
 String ColorModeRGB::get_slider_label(int idx) const {
 String ColorModeRGB::get_slider_label(int idx) const {
-	ERR_FAIL_INDEX_V_MSG(idx, 3, String(), "Couldn't get slider label.");
+	ERR_FAIL_INDEX_V_MSG(idx, get_slider_count(), String(), "Couldn't get slider label.");
 	return labels[idx];
 	return labels[idx];
 }
 }
 
 
 float ColorModeRGB::get_slider_value(int idx) const {
 float ColorModeRGB::get_slider_value(int idx) const {
-	ERR_FAIL_INDEX_V_MSG(idx, 4, 0, "Couldn't get slider value.");
-	return color_picker->get_pick_color().components[idx] * 255;
+	ERR_FAIL_INDEX_V_MSG(idx, get_slider_count(), 0, "Couldn't get slider value.");
+	return color_picker->color_normalized.components[idx] * 255;
 }
 }
 
 
 Color ColorModeRGB::get_color() const {
 Color ColorModeRGB::get_color() const {
@@ -57,6 +57,25 @@ Color ColorModeRGB::get_color() const {
 	return color;
 	return color;
 }
 }
 
 
+void ColorModeRGB::_greater_value_inputted() {
+	HSlider **sliders = color_picker->sliders;
+	Color color_prev = color_picker->color;
+	for (int i = 0; i < 3; i++) {
+		if (sliders[i]->get_value() > 255) {
+			color_prev.components[i] = sliders[i]->get_value() / 255.0;
+		}
+	}
+	Color linear_color = color_prev.srgb_to_linear();
+	float multiplier = MAX(1, MAX(MAX(linear_color.r, linear_color.g), linear_color.b));
+	Color srgb = Color(linear_color.r / multiplier, linear_color.g / multiplier, linear_color.b / multiplier, linear_color.a).linear_to_srgb();
+	sliders[0]->set_value_no_signal(srgb.r * 255);
+	sliders[1]->set_value_no_signal(srgb.g * 255);
+	sliders[2]->set_value_no_signal(srgb.b * 255);
+
+	color_picker->intensity = Math::log2(multiplier);
+	color_picker->intensity_slider->set_value_no_signal(color_picker->intensity);
+}
+
 void ColorModeRGB::slider_draw(int p_which) {
 void ColorModeRGB::slider_draw(int p_which) {
 	Vector<Vector2> pos;
 	Vector<Vector2> pos;
 	pos.resize(4);
 	pos.resize(4);
@@ -66,37 +85,39 @@ void ColorModeRGB::slider_draw(int p_which) {
 	Size2 size = slider->get_size();
 	Size2 size = slider->get_size();
 	Color left_color;
 	Color left_color;
 	Color right_color;
 	Color right_color;
-	Color color = color_picker->get_pick_color();
+	Color color = color_picker->color_normalized;
 	const real_t margin = 16 * color_picker->theme_cache.base_scale;
 	const real_t margin = 16 * color_picker->theme_cache.base_scale;
 
 
-	if (p_which == ColorPicker::SLIDER_COUNT) {
-		slider->draw_texture_rect(color_picker->theme_cache.sample_bg, Rect2(Point2(0, 0), Size2(size.x, margin)), true);
+	left_color = Color(
+			p_which == 0 ? 0 : color.r,
+			p_which == 1 ? 0 : color.g,
+			p_which == 2 ? 0 : color.b);
+	right_color = Color(
+			p_which == 0 ? 1 : color.r,
+			p_which == 1 ? 1 : color.g,
+			p_which == 2 ? 1 : color.b);
+
+	if (rgb_texture[p_which].is_null()) {
+		rgb_texture[p_which].instantiate();
+		rgb_texture[p_which]->set_width(400);
+		rgb_texture[p_which]->set_height(6);
+	}
 
 
-		left_color = color;
-		left_color.a = 0;
-		right_color = color;
-		right_color.a = 1;
-	} else {
-		left_color = Color(
-				p_which == 0 ? 0 : color.r,
-				p_which == 1 ? 0 : color.g,
-				p_which == 2 ? 0 : color.b);
-		right_color = Color(
-				p_which == 0 ? 1 : color.r,
-				p_which == 1 ? 1 : color.g,
-				p_which == 2 ? 1 : color.b);
+	Ref<GradientTexture2D> gradient_texture = rgb_texture[p_which];
+
+	Ref<Gradient> gradient = gradient_texture->get_gradient();
+	if (gradient.is_null()) {
+		gradient.instantiate();
+		PackedFloat32Array offsets = { 0, 1 };
+		gradient->set_offsets(offsets);
+		gradient->set_interpolation_color_space(Gradient::ColorSpace::GRADIENT_COLOR_SPACE_SRGB);
+		gradient_texture->set_gradient(gradient);
 	}
 	}
 
 
-	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));
+	PackedColorArray colors = { left_color, right_color };
+	gradient->set_colors(colors);
 
 
-	slider->draw_polygon(pos, col);
+	slider->draw_texture_rect(gradient_texture, Rect2(Vector2(), Vector2(size.x, margin)), false);
 }
 }
 
 
 void ColorModeHSV::_value_changed() {
 void ColorModeHSV::_value_changed() {
@@ -108,38 +129,43 @@ void ColorModeHSV::_value_changed() {
 	if (values[2] > 0 || values[1] != cached_saturation) {
 	if (values[2] > 0 || values[1] != cached_saturation) {
 		cached_saturation = values[1];
 		cached_saturation = values[1];
 	}
 	}
+
+	// Cache real HSV values in ColorPicker.
+	color_picker->h = color_picker->sliders[0]->get_value() / 360.0;
+	color_picker->s = color_picker->sliders[1]->get_value() / 100.0;
+	color_picker->v = color_picker->sliders[2]->get_value() / 100.0;
+
+	color_picker->hsv_cached = true;
 }
 }
 
 
 String ColorModeHSV::get_slider_label(int idx) const {
 String ColorModeHSV::get_slider_label(int idx) const {
-	ERR_FAIL_INDEX_V_MSG(idx, 3, String(), "Couldn't get slider label.");
+	ERR_FAIL_INDEX_V_MSG(idx, get_slider_count(), String(), "Couldn't get slider label.");
 	return labels[idx];
 	return labels[idx];
 }
 }
 
 
 float ColorModeHSV::get_slider_max(int idx) const {
 float ColorModeHSV::get_slider_max(int idx) const {
-	ERR_FAIL_INDEX_V_MSG(idx, 4, 0, "Couldn't get slider max value.");
+	ERR_FAIL_INDEX_V_MSG(idx, get_slider_count(), 0, "Couldn't get slider max value.");
 	return slider_max[idx];
 	return slider_max[idx];
 }
 }
 
 
 float ColorModeHSV::get_slider_value(int idx) const {
 float ColorModeHSV::get_slider_value(int idx) const {
 	switch (idx) {
 	switch (idx) {
 		case 0: {
 		case 0: {
-			if (color_picker->get_pick_color().get_s() > 0) {
-				return color_picker->get_pick_color().get_h() * 360.0;
+			if (color_picker->color_normalized.get_s() > 0) {
+				return color_picker->color_normalized.get_h() * 360.0;
 			} else {
 			} else {
 				return cached_hue;
 				return cached_hue;
 			}
 			}
 		}
 		}
 		case 1: {
 		case 1: {
-			if (color_picker->get_pick_color().get_v() > 0) {
-				return color_picker->get_pick_color().get_s() * 100.0;
+			if (color_picker->color_normalized.get_v() > 0) {
+				return color_picker->color_normalized.get_s() * 100.0;
 			} else {
 			} else {
 				return cached_saturation;
 				return cached_saturation;
 			}
 			}
 		}
 		}
 		case 2:
 		case 2:
-			return color_picker->get_pick_color().get_v() * 100.0;
-		case 3:
-			return Math::round(color_picker->get_pick_color().components[3] * 255.0);
+			return color_picker->color_normalized.get_v() * 100.0;
 		default:
 		default:
 			ERR_FAIL_V_MSG(0, "Couldn't get slider value.");
 			ERR_FAIL_V_MSG(0, "Couldn't get slider value.");
 	}
 	}
@@ -147,8 +173,7 @@ float ColorModeHSV::get_slider_value(int idx) const {
 
 
 Color ColorModeHSV::get_color() const {
 Color ColorModeHSV::get_color() const {
 	Vector<float> values = color_picker->get_active_slider_values();
 	Vector<float> values = color_picker->get_active_slider_values();
-	Color color;
-	color.set_hsv(values[0] / 360.0, values[1] / 100.0, values[2] / 100.0, values[3] / 255.0);
+	Color color = Color::from_hsv(values[0] / 360.0, values[1] / 100.0, values[2] / 100.0, values[3] / 255.0);
 	return color;
 	return color;
 }
 }
 
 
@@ -161,17 +186,10 @@ void ColorModeHSV::slider_draw(int p_which) {
 	Size2 size = slider->get_size();
 	Size2 size = slider->get_size();
 	Color left_color;
 	Color left_color;
 	Color right_color;
 	Color right_color;
-	Color color = color_picker->get_pick_color();
+	Color color = color_picker->color_normalized;
 	const real_t margin = 16 * color_picker->theme_cache.base_scale;
 	const real_t margin = 16 * color_picker->theme_cache.base_scale;
 
 
-	if (p_which == ColorPicker::SLIDER_COUNT) {
-		slider->draw_texture_rect(color_picker->theme_cache.sample_bg, Rect2(Point2(0, 0), Size2(size.x, margin)), true);
-
-		left_color = color;
-		left_color.a = 0;
-		right_color = color;
-		right_color.a = 1;
-	} else if (p_which == 0) {
+	if (p_which == 0) {
 		float v = color.get_v();
 		float v = color.get_v();
 		left_color = Color(v, v, v);
 		left_color = Color(v, v, v);
 		right_color = left_color;
 		right_color = left_color;
@@ -203,31 +221,60 @@ void ColorModeHSV::slider_draw(int p_which) {
 	}
 	}
 }
 }
 
 
-String ColorModeRAW::get_slider_label(int idx) const {
-	ERR_FAIL_INDEX_V_MSG(idx, 3, String(), "Couldn't get slider label.");
+String ColorModeLinear::get_slider_label(int idx) const {
+	ERR_FAIL_INDEX_V_MSG(idx, get_slider_count(), String(), "Couldn't get slider label.");
 	return labels[idx];
 	return labels[idx];
 }
 }
 
 
-float ColorModeRAW::get_slider_max(int idx) const {
-	ERR_FAIL_INDEX_V_MSG(idx, 4, 0, "Couldn't get slider max value.");
+float ColorModeLinear::get_slider_max(int idx) const {
+	ERR_FAIL_INDEX_V_MSG(idx, get_slider_count(), 0, "Couldn't get slider max value.");
 	return slider_max[idx];
 	return slider_max[idx];
 }
 }
 
 
-float ColorModeRAW::get_slider_value(int idx) const {
-	ERR_FAIL_INDEX_V_MSG(idx, 4, 0, "Couldn't get slider value.");
-	return color_picker->get_pick_color().components[idx];
+float ColorModeLinear::get_slider_value(int idx) const {
+	ERR_FAIL_INDEX_V_MSG(idx, get_slider_count(), 0, "Couldn't get slider value.");
+	Color color = color_picker->color_normalized.srgb_to_linear();
+	return color.components[idx];
+}
+
+float ColorModeLinear::get_alpha_slider_max() const {
+	return 1;
 }
 }
 
 
-Color ColorModeRAW::get_color() const {
+float ColorModeLinear::get_alpha_slider_value() const {
+	return color_picker->get_pick_color().a;
+}
+
+Color ColorModeLinear::get_color() const {
 	Vector<float> values = color_picker->get_active_slider_values();
 	Vector<float> values = color_picker->get_active_slider_values();
 	Color color;
 	Color color;
 	for (int i = 0; i < 4; i++) {
 	for (int i = 0; i < 4; i++) {
 		color.components[i] = values[i];
 		color.components[i] = values[i];
 	}
 	}
-	return color;
+	return color.linear_to_srgb();
 }
 }
 
 
-void ColorModeRAW::slider_draw(int p_which) {
+void ColorModeLinear::_greater_value_inputted() {
+	HSlider **sliders = color_picker->sliders;
+	Color color_prev = color_picker->color;
+	Color linear_color = color_prev.srgb_to_linear();
+	for (int i = 0; i < 3; i++) {
+		if (sliders[i]->get_value() > 1 + CMP_EPSILON) {
+			linear_color.components[i] = sliders[i]->get_value();
+		}
+	}
+
+	float multiplier = MAX(1, MAX(MAX(linear_color.r, linear_color.g), linear_color.b));
+
+	sliders[0]->set_value_no_signal(linear_color.r / multiplier);
+	sliders[1]->set_value_no_signal(linear_color.g / multiplier);
+	sliders[2]->set_value_no_signal(linear_color.b / multiplier);
+
+	color_picker->intensity = Math::log2(multiplier);
+	color_picker->intensity_slider->set_value_no_signal(color_picker->intensity);
+}
+
+void ColorModeLinear::slider_draw(int p_which) {
 	Vector<Vector2> pos;
 	Vector<Vector2> pos;
 	pos.resize(4);
 	pos.resize(4);
 	Vector<Color> col;
 	Vector<Color> col;
@@ -236,40 +283,39 @@ void ColorModeRAW::slider_draw(int p_which) {
 	Size2 size = slider->get_size();
 	Size2 size = slider->get_size();
 	Color left_color;
 	Color left_color;
 	Color right_color;
 	Color right_color;
-	Color color = color_picker->get_pick_color();
+	Color color = color_picker->color_normalized.linear_to_srgb();
 	const real_t margin = 16 * color_picker->theme_cache.base_scale;
 	const real_t margin = 16 * color_picker->theme_cache.base_scale;
 
 
-	if (p_which == ColorPicker::SLIDER_COUNT) {
-		slider->draw_texture_rect(color_picker->theme_cache.sample_bg, Rect2(Point2(0, 0), Size2(size.x, margin)), true);
-
-		left_color = color;
-		left_color.a = 0;
-		right_color = color;
-		right_color.a = 1;
+	left_color = Color(
+			p_which == 0 ? 0 : color.r,
+			p_which == 1 ? 0 : color.g,
+			p_which == 2 ? 0 : color.b);
+	right_color = Color(
+			p_which == 0 ? 1 : color.r,
+			p_which == 1 ? 1 : color.g,
+			p_which == 2 ? 1 : color.b);
+
+	if (rgb_texture[p_which].is_null()) {
+		rgb_texture[p_which].instantiate();
+		rgb_texture[p_which]->set_width(400);
+		rgb_texture[p_which]->set_height(6);
+	}
 
 
-		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));
+	Ref<GradientTexture2D> gradient_texture = rgb_texture[p_which];
 
 
-		slider->draw_polygon(pos, col);
+	Ref<Gradient> gradient = gradient_texture->get_gradient();
+	if (gradient.is_null()) {
+		gradient.instantiate();
+		PackedFloat32Array offsets = { 0, 1 };
+		gradient->set_offsets(offsets);
+		gradient->set_interpolation_color_space(Gradient::ColorSpace::GRADIENT_COLOR_SPACE_LINEAR_SRGB);
+		gradient_texture->set_gradient(gradient);
 	}
 	}
-}
 
 
-bool ColorModeRAW::apply_theme() const {
-	for (int i = 0; i < ColorPicker::SLIDER_COUNT; i++) {
-		HSlider *slider = color_picker->get_slider(i);
-		slider->remove_theme_icon_override("grabber");
-		slider->remove_theme_icon_override("grabber_highlight");
-		slider->remove_theme_style_override("slider");
-		slider->remove_theme_constant_override("grabber_offset");
-	}
+	PackedColorArray colors = { left_color, right_color };
+	gradient->set_colors(colors);
 
 
-	return true;
+	slider->draw_texture_rect(gradient_texture, Rect2(Vector2(), Vector2(size.x, margin)), false);
 }
 }
 
 
 void ColorModeOKHSL::_value_changed() {
 void ColorModeOKHSL::_value_changed() {
@@ -281,38 +327,43 @@ void ColorModeOKHSL::_value_changed() {
 	if (values[2] > 0 || values[1] != cached_saturation) {
 	if (values[2] > 0 || values[1] != cached_saturation) {
 		cached_saturation = values[1];
 		cached_saturation = values[1];
 	}
 	}
+
+	// Cache real OKHSL values in ColorPicker.
+	color_picker->ok_hsl_h = color_picker->sliders[0]->get_value() / 360.0;
+	color_picker->ok_hsl_s = color_picker->sliders[1]->get_value() / 100.0;
+	color_picker->ok_hsl_l = color_picker->sliders[2]->get_value() / 100.0;
+
+	color_picker->okhsl_cached = true;
 }
 }
 
 
 String ColorModeOKHSL::get_slider_label(int idx) const {
 String ColorModeOKHSL::get_slider_label(int idx) const {
-	ERR_FAIL_INDEX_V_MSG(idx, 3, String(), "Couldn't get slider label.");
+	ERR_FAIL_INDEX_V_MSG(idx, get_slider_count(), String(), "Couldn't get slider label.");
 	return labels[idx];
 	return labels[idx];
 }
 }
 
 
 float ColorModeOKHSL::get_slider_max(int idx) const {
 float ColorModeOKHSL::get_slider_max(int idx) const {
-	ERR_FAIL_INDEX_V_MSG(idx, 4, 0, "Couldn't get slider max value.");
+	ERR_FAIL_INDEX_V_MSG(idx, get_slider_count(), 0, "Couldn't get slider max value.");
 	return slider_max[idx];
 	return slider_max[idx];
 }
 }
 
 
 float ColorModeOKHSL::get_slider_value(int idx) const {
 float ColorModeOKHSL::get_slider_value(int idx) const {
 	switch (idx) {
 	switch (idx) {
 		case 0: {
 		case 0: {
-			if (color_picker->get_pick_color().get_ok_hsl_s() > 0) {
-				return color_picker->get_pick_color().get_ok_hsl_h() * 360.0;
+			if (color_picker->color_normalized.get_ok_hsl_s() > 0) {
+				return color_picker->color_normalized.get_ok_hsl_h() * 360.0;
 			} else {
 			} else {
 				return cached_hue;
 				return cached_hue;
 			}
 			}
 		}
 		}
 		case 1: {
 		case 1: {
-			if (color_picker->get_pick_color().get_ok_hsl_l() > 0) {
-				return color_picker->get_pick_color().get_ok_hsl_s() * 100.0;
+			if (color_picker->color_normalized.get_ok_hsl_l() > 0) {
+				return color_picker->color_normalized.get_ok_hsl_s() * 100.0;
 			} else {
 			} else {
 				return cached_saturation;
 				return cached_saturation;
 			}
 			}
 		}
 		}
 		case 2:
 		case 2:
-			return color_picker->get_pick_color().get_ok_hsl_l() * 100.0;
-		case 3:
-			return Math::round(color_picker->get_pick_color().components[3] * 255.0);
+			return color_picker->color_normalized.get_ok_hsl_l() * 100.0;
 		default:
 		default:
 			ERR_FAIL_V_MSG(0, "Couldn't get slider value.");
 			ERR_FAIL_V_MSG(0, "Couldn't get slider value.");
 	}
 	}
@@ -320,8 +371,7 @@ float ColorModeOKHSL::get_slider_value(int idx) const {
 
 
 Color ColorModeOKHSL::get_color() const {
 Color ColorModeOKHSL::get_color() const {
 	Vector<float> values = color_picker->get_active_slider_values();
 	Vector<float> values = color_picker->get_active_slider_values();
-	Color color;
-	color.set_ok_hsl(values[0] / 360.0, values[1] / 100.0, values[2] / 100.0, values[3] / 255.0);
+	Color color = Color::from_ok_hsl(values[0] / 360.0, values[1] / 100.0, values[2] / 100.0, values[3] / 255.0);
 	return color;
 	return color;
 }
 }
 
 
@@ -334,17 +384,16 @@ void ColorModeOKHSL::slider_draw(int p_which) {
 	Vector<Color> col;
 	Vector<Color> col;
 	Color left_color;
 	Color left_color;
 	Color right_color;
 	Color right_color;
-	Color color = color_picker->get_pick_color();
+	Color color = color_picker->color_normalized;
+	float okhsl_l = color.get_ok_hsl_l();
+	float slider_hue = (Math::is_zero_approx(color.get_ok_hsl_s())) ? cached_hue / 360.0 : color.get_ok_hsl_h();
+	float slider_sat = (Math::is_zero_approx(okhsl_l) || Math::is_equal_approx(okhsl_l, 1)) ? cached_saturation / 100.0 : color.get_ok_hsl_s();
 
 
 	if (p_which == 2) { // L
 	if (p_which == 2) { // L
 		pos.resize(6);
 		pos.resize(6);
 		col.resize(6);
 		col.resize(6);
 		left_color = Color(0, 0, 0);
 		left_color = Color(0, 0, 0);
-		Color middle_color;
-		float slider_hue = (Math::is_zero_approx(color.get_ok_hsl_s())) ? cached_hue / 360.0 : color.get_ok_hsl_h();
-		float slider_sat = (Math::is_zero_approx(color.get_ok_hsl_l())) ? cached_saturation / 100.0 : color.get_ok_hsl_s();
-
-		middle_color.set_ok_hsl(slider_hue, slider_sat, 0.5);
+		Color middle_color = Color::from_ok_hsl(slider_hue, slider_sat, 0.5);
 		right_color.set_ok_hsl(slider_hue, slider_sat, 1);
 		right_color.set_ok_hsl(slider_hue, slider_sat, 1);
 
 
 		col.set(0, left_color);
 		col.set(0, left_color);
@@ -359,26 +408,13 @@ void ColorModeOKHSL::slider_draw(int p_which) {
 		pos.set(3, Vector2(size.x, margin));
 		pos.set(3, Vector2(size.x, margin));
 		pos.set(4, Vector2(size.x * 0.5, margin));
 		pos.set(4, Vector2(size.x * 0.5, margin));
 		pos.set(5, Vector2(0, margin));
 		pos.set(5, Vector2(0, margin));
-	} else {
+		slider->draw_polygon(pos, col);
+	} else if (p_which == 1) { // S
 		pos.resize(4);
 		pos.resize(4);
 		col.resize(4);
 		col.resize(4);
 
 
-		if (p_which == ColorPicker::SLIDER_COUNT) {
-			slider->draw_texture_rect(color_picker->theme_cache.sample_bg, Rect2(Point2(0, 0), Size2(size.x, margin)), true);
-
-			left_color = color;
-			left_color.a = 0;
-			right_color = color;
-			right_color.a = 1;
-		} else if (p_which == 0) {
-			float l = color.get_ok_hsl_l();
-			left_color = Color(l, l, l);
-			right_color = left_color;
-		} else {
-			left_color.set_ok_hsl(color.get_ok_hsl_h(), 0, color.get_ok_hsl_l());
-			float s_col_hue = (Math::is_zero_approx(color.get_ok_hsl_s())) ? cached_hue / 360.0 : color.get_ok_hsl_h();
-			right_color.set_ok_hsl(s_col_hue, 1, color.get_ok_hsl_l());
-		}
+		left_color.set_ok_hsl(slider_hue, 0, okhsl_l);
+		right_color.set_ok_hsl(slider_hue, 1, okhsl_l);
 
 
 		col.set(0, left_color);
 		col.set(0, left_color);
 		col.set(1, right_color);
 		col.set(1, right_color);
@@ -388,34 +424,36 @@ void ColorModeOKHSL::slider_draw(int p_which) {
 		pos.set(1, Vector2(size.x, 0));
 		pos.set(1, Vector2(size.x, 0));
 		pos.set(2, Vector2(size.x, margin));
 		pos.set(2, Vector2(size.x, margin));
 		pos.set(3, Vector2(0, margin));
 		pos.set(3, Vector2(0, margin));
-	}
-
-	slider->draw_polygon(pos, col);
-
-	if (p_which == 0) { // H
+		slider->draw_polygon(pos, col);
+	} else if (p_which == 0) { // H
 		const int precision = 7;
 		const int precision = 7;
+		if (hue_texture.is_null()) {
+			hue_texture.instantiate();
+			hue_texture->set_width(400);
+			hue_texture->set_height(6);
+		}
+		Ref<Gradient> hue_gradient = hue_texture->get_gradient();
+		if (hue_gradient.is_null()) {
+			hue_gradient.instantiate();
+			PackedFloat32Array offsets;
+			offsets.resize(precision);
+			for (int i = 0; i < precision; i++) {
+				float h = i / float(precision - 1);
+				offsets.write[i] = h;
+			}
+			hue_gradient->set_offsets(offsets);
+			hue_gradient->set_interpolation_color_space(Gradient::ColorSpace::GRADIENT_COLOR_SPACE_OKLAB);
+			hue_texture->set_gradient(hue_gradient);
+		}
 
 
-		Ref<Gradient> hue_gradient;
-		hue_gradient.instantiate();
-		PackedFloat32Array offsets;
-		offsets.resize(precision);
 		PackedColorArray colors;
 		PackedColorArray colors;
 		colors.resize(precision);
 		colors.resize(precision);
 
 
 		for (int i = 0; i < precision; i++) {
 		for (int i = 0; i < precision; i++) {
 			float h = i / float(precision - 1);
 			float h = i / float(precision - 1);
-			offsets.write[i] = h;
-			colors.write[i] = Color::from_ok_hsl(h, color.get_ok_hsl_s(), color.get_ok_hsl_l());
+			colors.write[i] = Color::from_ok_hsl(h, slider_sat, okhsl_l);
 		}
 		}
-		hue_gradient->set_offsets(offsets);
 		hue_gradient->set_colors(colors);
 		hue_gradient->set_colors(colors);
-		hue_gradient->set_interpolation_color_space(Gradient::ColorSpace::GRADIENT_COLOR_SPACE_OKLAB);
-		if (hue_texture.is_null()) {
-			hue_texture.instantiate();
-			hue_texture->set_width(800);
-			hue_texture->set_height(6);
-		}
-		hue_texture->set_gradient(hue_gradient);
 		slider->draw_texture_rect(hue_texture, Rect2(Vector2(), Vector2(size.x, margin)), false);
 		slider->draw_texture_rect(hue_texture, Rect2(Vector2(), Vector2(size.x, margin)), false);
 	}
 	}
 }
 }

+ 19 - 8
scene/gui/color_mode.h

@@ -48,12 +48,15 @@ public:
 	virtual bool get_allow_greater() const { return false; }
 	virtual bool get_allow_greater() const { return false; }
 	virtual float get_slider_value(int idx) const = 0;
 	virtual float get_slider_value(int idx) const = 0;
 
 
+	virtual float get_alpha_slider_max() const { return 255.0; }
+	virtual float get_alpha_slider_value() const { return color_picker->get_pick_color().a * 255.0; }
+
 	virtual Color get_color() const = 0;
 	virtual Color get_color() const = 0;
 
 
 	virtual void _value_changed() {}
 	virtual void _value_changed() {}
+	virtual void _greater_value_inputted() {}
 
 
 	virtual void slider_draw(int p_which) = 0;
 	virtual void slider_draw(int p_which) = 0;
-	virtual bool apply_theme() const { return false; }
 
 
 	ColorMode(ColorPicker *p_color_picker);
 	ColorMode(ColorPicker *p_color_picker);
 	virtual ~ColorMode() {}
 	virtual ~ColorMode() {}
@@ -62,7 +65,7 @@ public:
 class ColorModeHSV : public ColorMode {
 class ColorModeHSV : public ColorMode {
 public:
 public:
 	String labels[3] = { "H", "S", "V" };
 	String labels[3] = { "H", "S", "V" };
-	float slider_max[4] = { 359, 100, 100, 255 };
+	float slider_max[3] = { 359, 100, 100 };
 	float cached_hue = 0.0;
 	float cached_hue = 0.0;
 	float cached_saturation = 0.0;
 	float cached_saturation = 0.0;
 
 
@@ -86,6 +89,7 @@ public:
 class ColorModeRGB : public ColorMode {
 class ColorModeRGB : public ColorMode {
 public:
 public:
 	String labels[3] = { "R", "G", "B" };
 	String labels[3] = { "R", "G", "B" };
+	Ref<GradientTexture2D> rgb_texture[3];
 
 
 	virtual String get_name() const override { return "RGB"; }
 	virtual String get_name() const override { return "RGB"; }
 
 
@@ -97,18 +101,21 @@ public:
 
 
 	virtual Color get_color() const override;
 	virtual Color get_color() const override;
 
 
+	virtual void _greater_value_inputted() override;
+
 	virtual void slider_draw(int p_which) override;
 	virtual void slider_draw(int p_which) override;
 
 
 	ColorModeRGB(ColorPicker *p_color_picker) :
 	ColorModeRGB(ColorPicker *p_color_picker) :
 			ColorMode(p_color_picker) {}
 			ColorMode(p_color_picker) {}
 };
 };
 
 
-class ColorModeRAW : public ColorMode {
+class ColorModeLinear : public ColorMode {
 public:
 public:
 	String labels[3] = { "R", "G", "B" };
 	String labels[3] = { "R", "G", "B" };
-	float slider_max[4] = { 100, 100, 100, 1 };
+	float slider_max[3] = { 1, 1, 1 };
+	Ref<GradientTexture2D> rgb_texture[3];
 
 
-	virtual String get_name() const override { return "RAW"; }
+	virtual String get_name() const override { return "Linear"; }
 
 
 	virtual float get_slider_step() const override { return 0.001; }
 	virtual float get_slider_step() const override { return 0.001; }
 	virtual float get_spinbox_arrow_step() const override { return 0.01; }
 	virtual float get_spinbox_arrow_step() const override { return 0.01; }
@@ -117,19 +124,23 @@ public:
 	virtual bool get_allow_greater() const override { return true; }
 	virtual bool get_allow_greater() const override { return true; }
 	virtual float get_slider_value(int idx) const override;
 	virtual float get_slider_value(int idx) const override;
 
 
+	virtual float get_alpha_slider_max() const override;
+	virtual float get_alpha_slider_value() const override;
+
 	virtual Color get_color() const override;
 	virtual Color get_color() const override;
 
 
+	virtual void _greater_value_inputted() override;
+
 	virtual void slider_draw(int p_which) override;
 	virtual void slider_draw(int p_which) override;
-	virtual bool apply_theme() const override;
 
 
-	ColorModeRAW(ColorPicker *p_color_picker) :
+	ColorModeLinear(ColorPicker *p_color_picker) :
 			ColorMode(p_color_picker) {}
 			ColorMode(p_color_picker) {}
 };
 };
 
 
 class ColorModeOKHSL : public ColorMode {
 class ColorModeOKHSL : public ColorMode {
 public:
 public:
 	String labels[3] = { "H", "S", "L" };
 	String labels[3] = { "H", "S", "L" };
-	float slider_max[4] = { 359, 100, 100, 255 };
+	float slider_max[3] = { 359, 100, 100 };
 	float cached_hue = 0.0;
 	float cached_hue = 0.0;
 	float cached_saturation = 0.0;
 	float cached_saturation = 0.0;
 	Ref<GradientTexture2D> hue_texture;
 	Ref<GradientTexture2D> hue_texture;

+ 272 - 129
scene/gui/color_picker.cpp

@@ -31,6 +31,7 @@
 #include "color_picker.h"
 #include "color_picker.h"
 
 
 #include "core/io/image.h"
 #include "core/io/image.h"
+#include "core/math/expression.h"
 #include "scene/gui/color_mode.h"
 #include "scene/gui/color_mode.h"
 #include "scene/gui/color_picker_shape.h"
 #include "scene/gui/color_picker_shape.h"
 #include "scene/gui/file_dialog.h"
 #include "scene/gui/file_dialog.h"
@@ -53,6 +54,27 @@
 #include "scene/theme/theme_db.h"
 #include "scene/theme/theme_db.h"
 #include "thirdparty/misc/ok_color_shader.h"
 #include "thirdparty/misc/ok_color_shader.h"
 
 
+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;
+}
+
 void ColorPicker::_notification(int p_what) {
 void ColorPicker::_notification(int p_what) {
 	switch (p_what) {
 	switch (p_what) {
 		case NOTIFICATION_ACCESSIBILITY_UPDATE: {
 		case NOTIFICATION_ACCESSIBILITY_UPDATE: {
@@ -126,6 +148,7 @@ void ColorPicker::_notification(int p_what) {
 			}
 			}
 			alpha_label->set_custom_minimum_size(Size2(theme_cache.label_width, 0));
 			alpha_label->set_custom_minimum_size(Size2(theme_cache.label_width, 0));
 			alpha_slider->add_theme_constant_override(SNAME("center_grabber"), theme_cache.center_slider_grabbers);
 			alpha_slider->add_theme_constant_override(SNAME("center_grabber"), theme_cache.center_slider_grabbers);
+			intensity_label->set_custom_minimum_size(Size2(theme_cache.label_width, 0));
 
 
 			for (int i = 0; i < MODE_BUTTON_COUNT; i++) {
 			for (int i = 0; i < MODE_BUTTON_COUNT; i++) {
 				mode_btns[i]->begin_bulk_theme_override();
 				mode_btns[i]->begin_bulk_theme_override();
@@ -144,10 +167,9 @@ void ColorPicker::_notification(int p_what) {
 
 
 			_reset_sliders_theme();
 			_reset_sliders_theme();
 
 
-			if (Engine::get_singleton()->is_editor_hint()) {
-				// Adjust for the width of the "Script" icon.
-				text_type->set_custom_minimum_size(Size2(28 * theme_cache.base_scale, 0));
-			}
+			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));
 
 
 			_update_presets();
 			_update_presets();
 			_update_recent_presets();
 			_update_recent_presets();
@@ -348,17 +370,17 @@ void ColorPicker::_update_controls() {
 	alpha_slider->set_accessibility_name(ETR("Alpha"));
 	alpha_slider->set_accessibility_name(ETR("Alpha"));
 	alpha_value->set_accessibility_name(ETR("Alpha"));
 	alpha_value->set_accessibility_name(ETR("Alpha"));
 
 
-	slider_theme_modified = modes[current_mode]->apply_theme();
+	intensity_label->set_text("I");
+	intensity_slider->set_accessibility_name(ETR("Intensity"));
+	intensity_value->set_accessibility_name(ETR("Intensity"));
 
 
-	if (edit_alpha) {
-		alpha_value->show();
-		alpha_slider->show();
-		alpha_label->show();
-	} else {
-		alpha_value->hide();
-		alpha_slider->hide();
-		alpha_label->hide();
-	}
+	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);
 
 
 	int i = 0;
 	int i = 0;
 	for (ColorPickerShape *shape : shapes) {
 	for (ColorPickerShape *shape : shapes) {
@@ -381,17 +403,17 @@ void ColorPicker::_update_controls() {
 	btn_shape->set_visible(current_shape != SHAPE_NONE);
 	btn_shape->set_visible(current_shape != SHAPE_NONE);
 }
 }
 
 
-void ColorPicker::_set_pick_color(const Color &p_color, bool p_update_sliders) {
+void ColorPicker::_set_pick_color(const Color &p_color, bool p_update_sliders, bool p_calc_intensity) {
 	if (text_changed) {
 	if (text_changed) {
 		add_recent_preset(color);
 		add_recent_preset(color);
 		text_changed = false;
 		text_changed = false;
 	}
 	}
 
 
 	color = p_color;
 	color = p_color;
-	if (color != last_color) {
-		_copy_color_to_hsv();
-		last_color = color;
+	if (p_calc_intensity) {
+		_copy_color_to_normalized_and_intensity();
 	}
 	}
+	_copy_normalized_to_hsv_okhsl();
 
 
 	if (!is_inside_tree()) {
 	if (!is_inside_tree()) {
 		return;
 		return;
@@ -401,7 +423,7 @@ void ColorPicker::_set_pick_color(const Color &p_color, bool p_update_sliders) {
 }
 }
 
 
 void ColorPicker::set_pick_color(const Color &p_color) {
 void ColorPicker::set_pick_color(const Color &p_color) {
-	_set_pick_color(p_color, true); //because setters can't have more arguments
+	_set_pick_color(p_color, true, true); // Because setters can't have more arguments.
 }
 }
 
 
 void ColorPicker::set_old_color(const Color &p_color) {
 void ColorPicker::set_old_color(const Color &p_color) {
@@ -435,6 +457,32 @@ bool ColorPicker::is_editing_alpha() const {
 	return edit_alpha;
 	return edit_alpha;
 }
 }
 
 
+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;
+}
+
 void ColorPicker::_slider_drag_started() {
 void ColorPicker::_slider_drag_started() {
 	currently_dragging = true;
 	currently_dragging = true;
 }
 }
@@ -444,32 +492,18 @@ void ColorPicker::_slider_value_changed() {
 		return;
 		return;
 	}
 	}
 
 
-	color = modes[current_mode]->get_color();
+	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 ? "" : "+");
+
 	modes[current_mode]->_value_changed();
 	modes[current_mode]->_value_changed();
 
 
-	if (current_mode == MODE_HSV) {
-		h = sliders[0]->get_value() / 360.0;
-		s = sliders[1]->get_value() / 100.0;
-		v = sliders[2]->get_value() / 100.0;
-		ok_hsl_h = color.get_ok_hsl_h();
-		ok_hsl_s = color.get_ok_hsl_s();
-		ok_hsl_l = color.get_ok_hsl_l();
-
-		circle_keyboard_joypad_picker_cursor_position = Vector2i();
-		last_color = color;
-	} else if (current_mode == MODE_OKHSL) {
-		ok_hsl_h = sliders[0]->get_value() / 360.0;
-		ok_hsl_s = sliders[1]->get_value() / 100.0;
-		ok_hsl_l = sliders[2]->get_value() / 100.0;
-		h = color.get_h();
-		s = color.get_s();
-		v = color.get_v();
-
-		circle_keyboard_joypad_picker_cursor_position = Vector2i();
-		last_color = color;
-	}
-
-	_set_pick_color(color, false);
+	_set_pick_color(color, false, false);
 	if (!deferred_mode_enabled || !currently_dragging) {
 	if (!deferred_mode_enabled || !currently_dragging) {
 		emit_signal(SNAME("color_changed"), color);
 		emit_signal(SNAME("color_changed"), color);
 	}
 	}
@@ -518,14 +552,22 @@ void ColorPicker::create_slider(GridContainer *gc, int idx) {
 	slider->connect("drag_started", callable_mp(this, &ColorPicker::_slider_drag_started));
 	slider->connect("drag_started", callable_mp(this, &ColorPicker::_slider_drag_started));
 	slider->connect(SceneStringName(value_changed), callable_mp(this, &ColorPicker::_slider_value_changed).unbind(1));
 	slider->connect(SceneStringName(value_changed), callable_mp(this, &ColorPicker::_slider_value_changed).unbind(1));
 	slider->connect("drag_ended", callable_mp(this, &ColorPicker::_slider_drag_ended).unbind(1));
 	slider->connect("drag_ended", callable_mp(this, &ColorPicker::_slider_drag_ended).unbind(1));
-	slider->connect(SceneStringName(draw), callable_mp(this, &ColorPicker::_slider_draw).bind(idx));
+	if (idx < SLIDER_COUNT) {
+		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));
+	}
 	slider->connect(SceneStringName(gui_input), callable_mp(this, &ColorPicker::_slider_or_spin_input));
 	slider->connect(SceneStringName(gui_input), callable_mp(this, &ColorPicker::_slider_or_spin_input));
 
 
 	if (idx < SLIDER_COUNT) {
 	if (idx < SLIDER_COUNT) {
 		sliders[idx] = slider;
 		sliders[idx] = slider;
 		values[idx] = val;
 		values[idx] = val;
 		labels[idx] = lbl;
 		labels[idx] = lbl;
-	} else {
+	} else if (idx == SLIDER_INTENSITY) {
+		intensity_slider = slider;
+		intensity_value = val;
+		intensity_label = lbl;
+	} else if (idx == SLIDER_ALPHA) {
 		alpha_slider = slider;
 		alpha_slider = slider;
 		alpha_value = val;
 		alpha_value = val;
 		alpha_label = lbl;
 		alpha_label = lbl;
@@ -591,21 +633,53 @@ Vector<float> ColorPicker::get_active_slider_values() {
 	return cur_values;
 	return cur_values;
 }
 }
 
 
-void ColorPicker::_copy_color_to_hsv() {
-	ok_hsl_h = color.get_ok_hsl_h();
-	ok_hsl_s = color.get_ok_hsl_s();
-	ok_hsl_l = color.get_ok_hsl_l();
-	h = color.get_h();
-	s = color.get_s();
-	v = color.get_v();
+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;
 }
 }
 
 
-void ColorPicker::_copy_hsv_to_color() {
+void ColorPicker::_copy_hsv_okhsl_to_normalized() {
 	if (current_shape != SHAPE_NONE && shapes[current_shape]->is_ok_hsl()) {
 	if (current_shape != SHAPE_NONE && shapes[current_shape]->is_ok_hsl()) {
-		color.set_ok_hsl(ok_hsl_h, ok_hsl_s, ok_hsl_l, color.a);
+		color_normalized.set_ok_hsl(ok_hsl_h, ok_hsl_s, ok_hsl_l, color_normalized.a);
 	} else {
 	} else {
-		color.set_hsv(h, s, v, color.a);
+		color_normalized.set_hsv(h, s, v, color_normalized.a);
+	}
+}
+
+Color ColorPicker::_color_apply_intensity(const Color &col) const {
+	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;
 	}
 	}
+	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);
 }
 }
 
 
 void ColorPicker::_select_from_preset_container(const Color &p_color) {
 void ColorPicker::_select_from_preset_container(const Color &p_color) {
@@ -660,35 +734,52 @@ void ColorPicker::_reset_sliders_theme() {
 }
 }
 
 
 void ColorPicker::_html_submitted(const String &p_html) {
 void ColorPicker::_html_submitted(const String &p_html) {
-	if (updating || text_is_constructor || !c_text->is_visible()) {
+	if (updating) {
 		return;
 		return;
 	}
 	}
-
-	Color 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);
+	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);
+			}
 		}
 		}
+		new_color = Color::from_string(html_no_prefix, new_color);
 	}
 	}
-	new_color = Color::from_string(html_no_prefix, new_color);
 
 
 	if (!is_editing_alpha()) {
 	if (!is_editing_alpha()) {
 		new_color.a = color.a;
 		new_color.a = color.a;
 	}
 	}
 
 
-	if (new_color.to_argb32() == color.to_argb32()) {
+	if (new_color == color) {
 		return;
 		return;
 	}
 	}
 	color = new_color;
 	color = new_color;
@@ -714,9 +805,11 @@ void ColorPicker::_update_color(bool p_update_sliders) {
 			values[i]->set_custom_arrow_step(spinbox_arrow_step);
 			values[i]->set_custom_arrow_step(spinbox_arrow_step);
 			values[i]->set_allow_greater(modes[current_mode]->get_allow_greater());
 			values[i]->set_allow_greater(modes[current_mode]->get_allow_greater());
 		}
 		}
-		alpha_slider->set_max(modes[current_mode]->get_slider_max(current_slider_count));
+		alpha_slider->set_max(modes[current_mode]->get_alpha_slider_max());
 		alpha_slider->set_step(step);
 		alpha_slider->set_step(step);
-		alpha_slider->set_value(modes[current_mode]->get_slider_value(current_slider_count));
+		alpha_slider->set_value(modes[current_mode]->get_alpha_slider_value());
+		intensity_slider->set_value(intensity);
+		intensity_value->set_prefix(intensity < 0 ? "" : "+");
 	}
 	}
 
 
 	_update_text_value();
 	_update_text_value();
@@ -808,16 +901,16 @@ void ColorPicker::_update_recent_presets() {
 void ColorPicker::_text_type_toggled() {
 void ColorPicker::_text_type_toggled() {
 	text_is_constructor = !text_is_constructor;
 	text_is_constructor = !text_is_constructor;
 	if (text_is_constructor) {
 	if (text_is_constructor) {
+		hex_label->set_text(ETR("Expr"));
 		text_type->set_text("");
 		text_type->set_text("");
-		text_type->set_button_icon(get_editor_theme_icon(SNAME("Script")));
+		text_type->set_button_icon(theme_cache.color_script);
 
 
-		c_text->set_editable(false);
-		c_text->set_tooltip_text(TTRC("Copy this constructor in a script."));
+		c_text->set_tooltip_text(RTR("Execute an expression as a color."));
 	} else {
 	} else {
+		hex_label->set_text(ETR("Hex"));
 		text_type->set_text("#");
 		text_type->set_text("#");
 		text_type->set_button_icon(nullptr);
 		text_type->set_button_icon(nullptr);
 
 
-		c_text->set_editable(true);
 		c_text->set_tooltip_text(ETR("Enter a hex code (\"#ff0000\") or named color (\"red\")."));
 		c_text->set_tooltip_text(ETR("Enter a hex code (\"#ff0000\") or named color (\"red\")."));
 	}
 	}
 	_update_color();
 	_update_color();
@@ -845,7 +938,6 @@ void ColorPicker::set_picker_shape(PickerShapeType p_shape) {
 		btn_shape->set_button_icon(shape_popup->get_item_icon(p_shape));
 		btn_shape->set_button_icon(shape_popup->get_item_icon(p_shape));
 	}
 	}
 
 
-	circle_keyboard_joypad_picker_cursor_position = Vector2i();
 	current_shape = p_shape;
 	current_shape = p_shape;
 
 
 #ifdef TOOLS_ENABLED
 #ifdef TOOLS_ENABLED
@@ -854,8 +946,6 @@ void ColorPicker::set_picker_shape(PickerShapeType p_shape) {
 	}
 	}
 #endif
 #endif
 
 
-	_copy_color_to_hsv();
-
 	_update_controls();
 	_update_controls();
 	_update_color();
 	_update_color();
 }
 }
@@ -1012,7 +1102,6 @@ void ColorPicker::_set_mode_popup_value(ColorModeType p_mode) {
 	} else {
 	} else {
 		set_color_mode(p_mode);
 		set_color_mode(p_mode);
 	}
 	}
-	circle_keyboard_joypad_picker_cursor_position = Vector2i();
 }
 }
 
 
 Variant ColorPicker::_get_drag_data_fw(const Point2 &p_point, Control *p_from_control) {
 Variant ColorPicker::_get_drag_data_fw(const Point2 &p_point, Control *p_from_control) {
@@ -1215,10 +1304,6 @@ void ColorPicker::set_color_mode(ColorModeType p_mode) {
 		return;
 		return;
 	}
 	}
 
 
-	if (slider_theme_modified) {
-		_reset_sliders_theme();
-	}
-
 	mode_popup->set_item_checked(current_mode, false);
 	mode_popup->set_item_checked(current_mode, false);
 	mode_popup->set_item_checked(p_mode, true);
 	mode_popup->set_item_checked(p_mode, true);
 
 
@@ -1259,22 +1344,20 @@ void ColorPicker::set_colorize_sliders(bool p_colorize_sliders) {
 	if (colorize_sliders) {
 	if (colorize_sliders) {
 		Ref<StyleBoxEmpty> style_box_empty(memnew(StyleBoxEmpty));
 		Ref<StyleBoxEmpty> style_box_empty(memnew(StyleBoxEmpty));
 
 
-		if (!slider_theme_modified) {
-			for (int i = 0; i < SLIDER_COUNT; i++) {
-				sliders[i]->add_theme_style_override("slider", style_box_empty);
-			}
+		for (int i = 0; i < SLIDER_COUNT; i++) {
+			sliders[i]->add_theme_style_override("slider", style_box_empty);
 		}
 		}
+
 		alpha_slider->add_theme_style_override("slider", style_box_empty);
 		alpha_slider->add_theme_style_override("slider", style_box_empty);
 	} else {
 	} else {
 		Ref<StyleBoxFlat> style_box_flat(memnew(StyleBoxFlat));
 		Ref<StyleBoxFlat> style_box_flat(memnew(StyleBoxFlat));
 		style_box_flat->set_content_margin(SIDE_TOP, 16 * theme_cache.base_scale);
 		style_box_flat->set_content_margin(SIDE_TOP, 16 * theme_cache.base_scale);
 		style_box_flat->set_bg_color(Color(0.2, 0.23, 0.31).lerp(Color(0, 0, 0, 1), 0.3).clamp());
 		style_box_flat->set_bg_color(Color(0.2, 0.23, 0.31).lerp(Color(0, 0, 0, 1), 0.3).clamp());
 
 
-		if (!slider_theme_modified) {
-			for (int i = 0; i < SLIDER_COUNT; i++) {
-				sliders[i]->add_theme_style_override("slider", style_box_flat);
-			}
+		for (int i = 0; i < SLIDER_COUNT; i++) {
+			sliders[i]->add_theme_style_override("slider", style_box_flat);
 		}
 		}
+
 		alpha_slider->add_theme_style_override("slider", style_box_flat);
 		alpha_slider->add_theme_style_override("slider", style_box_flat);
 	}
 	}
 }
 }
@@ -1292,25 +1375,21 @@ bool ColorPicker::is_deferred_mode() const {
 }
 }
 
 
 void ColorPicker::_update_text_value() {
 void ColorPicker::_update_text_value() {
-	bool text_visible = true;
-	if (text_is_constructor) {
-		String t = "Color(" + String::num(color.r, 3) + ", " + String::num(color.g, 3) + ", " + String::num(color.b, 3);
-		if (edit_alpha && color.a < 1) {
-			t += ", " + String::num(color.a, 3) + ")";
-		} else {
-			t += ")";
-		}
-		c_text->set_text(t);
-	}
+	if (text_is_constructor || !is_color_valid_hex(color)) {
+		String t = "Color" + color_to_string(color, edit_alpha && color.a < 1, true);
 
 
-	if (color.r > 1 || color.g > 1 || color.b > 1 || color.r < 0 || color.g < 0 || color.b < 0) {
-		text_visible = false;
-	} else if (!text_is_constructor) {
+		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);
+	} else {
+		text_type->set_text("#");
+		text_type->set_button_icon(nullptr);
+		text_type->set_disabled(false);
+		hex_label->set_text(ETR("Hex"));
 		c_text->set_text(color.to_html(edit_alpha && color.a < 1));
 		c_text->set_text(color.to_html(edit_alpha && color.a < 1));
 	}
 	}
-
-	text_type->set_visible(text_visible);
-	c_text->set_visible(text_visible);
 }
 }
 
 
 void ColorPicker::_sample_input(const Ref<InputEvent> &p_event) {
 void ColorPicker::_sample_input(const Ref<InputEvent> &p_event) {
@@ -1366,7 +1445,7 @@ void ColorPicker::_sample_draw() {
 			sample->set_focus_mode(FOCUS_NONE);
 			sample->set_focus_mode(FOCUS_NONE);
 		}
 		}
 
 
-		if (old_color.r > 1 || old_color.g > 1 || old_color.b > 1) {
+		if (is_color_overbright(color)) {
 			// Draw an indicator to denote that the old color is "overbright" and can't be displayed accurately in the preview.
 			// Draw an indicator to denote that the old color is "overbright" and can't be displayed accurately in the preview.
 			sample->draw_texture(theme_cache.overbright_indicator, Point2());
 			sample->draw_texture(theme_cache.overbright_indicator, Point2());
 		}
 		}
@@ -1385,7 +1464,7 @@ void ColorPicker::_sample_draw() {
 		theme_cache.sample_focus->draw(ci, rect_old);
 		theme_cache.sample_focus->draw(ci, rect_old);
 	}
 	}
 
 
-	if (color.r > 1 || color.g > 1 || color.b > 1) {
+	if (is_color_overbright(color)) {
 		// Draw an indicator to denote that the new color is "overbright" and can't be displayed accurately in the preview.
 		// Draw an indicator to denote that the new color is "overbright" and can't be displayed accurately in the preview.
 		sample->draw_texture(theme_cache.overbright_indicator, Point2(sample->get_size().width * 0.5, 0));
 		sample->draw_texture(theme_cache.overbright_indicator, Point2(sample->get_size().width * 0.5, 0));
 	}
 	}
@@ -1397,6 +1476,37 @@ void ColorPicker::_slider_draw(int p_which) {
 	}
 	}
 }
 }
 
 
+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);
+}
+
 void ColorPicker::_slider_or_spin_input(const Ref<InputEvent> &p_event) {
 void ColorPicker::_slider_or_spin_input(const Ref<InputEvent> &p_event) {
 	if (line_edit_mouse_release) {
 	if (line_edit_mouse_release) {
 		line_edit_mouse_release = false;
 		line_edit_mouse_release = false;
@@ -1443,7 +1553,11 @@ void ColorPicker::_recent_preset_pressed(const bool p_pressed, ColorPresetButton
 	if (!p_pressed) {
 	if (!p_pressed) {
 		return;
 		return;
 	}
 	}
-	set_pick_color(p_preset->get_preset_color());
+
+	// 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());
+	}
 
 
 	recent_presets.move_to_back(recent_presets.find(p_preset->get_preset_color()));
 	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());
 	List<Color>::Element *e = recent_preset_cache.find(p_preset->get_preset_color());
@@ -1820,7 +1934,6 @@ void ColorPicker::_html_focus_exit() {
 	} else {
 	} else {
 		_update_text_value();
 		_update_text_value();
 	}
 	}
-	circle_keyboard_joypad_picker_cursor_position = Vector2i();
 }
 }
 
 
 void ColorPicker::set_can_add_swatches(bool p_enabled) {
 void ColorPicker::set_can_add_swatches(bool p_enabled) {
@@ -1910,6 +2023,8 @@ void ColorPicker::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("get_color_mode"), &ColorPicker::get_color_mode);
 	ClassDB::bind_method(D_METHOD("get_color_mode"), &ColorPicker::get_color_mode);
 	ClassDB::bind_method(D_METHOD("set_edit_alpha", "show"), &ColorPicker::set_edit_alpha);
 	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);
 	ClassDB::bind_method(D_METHOD("is_editing_alpha"), &ColorPicker::is_editing_alpha);
+	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);
 	ClassDB::bind_method(D_METHOD("set_can_add_swatches", "enabled"), &ColorPicker::set_can_add_swatches);
 	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);
 	ClassDB::bind_method(D_METHOD("are_swatches_enabled"), &ColorPicker::are_swatches_enabled);
 	ClassDB::bind_method(D_METHOD("set_presets_visible", "visible"), &ColorPicker::set_presets_visible);
 	ClassDB::bind_method(D_METHOD("set_presets_visible", "visible"), &ColorPicker::set_presets_visible);
@@ -1933,7 +2048,8 @@ void ColorPicker::_bind_methods() {
 
 
 	ADD_PROPERTY(PropertyInfo(Variant::COLOR, "color"), "set_pick_color", "get_pick_color");
 	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");
 	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "edit_alpha"), "set_edit_alpha", "is_editing_alpha");
-	ADD_PROPERTY(PropertyInfo(Variant::INT, "color_mode", PROPERTY_HINT_ENUM, "RGB,HSV,RAW,OKHSL"), "set_color_mode", "get_color_mode");
+	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");
 	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "deferred_mode"), "set_deferred_mode", "is_deferred_mode");
 	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "deferred_mode"), "set_deferred_mode", "is_deferred_mode");
 	ADD_PROPERTY(PropertyInfo(Variant::INT, "picker_shape", PROPERTY_HINT_ENUM, "HSV Rectangle,HSV Rectangle Wheel,VHS Circle,OKHSL Circle,None"), "set_picker_shape", "get_picker_shape");
 	ADD_PROPERTY(PropertyInfo(Variant::INT, "picker_shape", PROPERTY_HINT_ENUM, "HSV Rectangle,HSV Rectangle Wheel,VHS Circle,OKHSL Circle,None"), "set_picker_shape", "get_picker_shape");
 	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "can_add_swatches"), "set_can_add_swatches", "are_swatches_enabled");
 	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "can_add_swatches"), "set_can_add_swatches", "are_swatches_enabled");
@@ -1950,7 +2066,10 @@ void ColorPicker::_bind_methods() {
 
 
 	BIND_ENUM_CONSTANT(MODE_RGB);
 	BIND_ENUM_CONSTANT(MODE_RGB);
 	BIND_ENUM_CONSTANT(MODE_HSV);
 	BIND_ENUM_CONSTANT(MODE_HSV);
+#ifndef DISABLE_DEPRECATED
 	BIND_ENUM_CONSTANT(MODE_RAW);
 	BIND_ENUM_CONSTANT(MODE_RAW);
+#endif
+	BIND_ENUM_CONSTANT(MODE_LINEAR);
 	BIND_ENUM_CONSTANT(MODE_OKHSL);
 	BIND_ENUM_CONSTANT(MODE_OKHSL);
 
 
 	BIND_ENUM_CONSTANT(SHAPE_HSV_RECTANGLE);
 	BIND_ENUM_CONSTANT(SHAPE_HSV_RECTANGLE);
@@ -1990,6 +2109,8 @@ void ColorPicker::_bind_methods() {
 	BIND_THEME_ITEM(Theme::DATA_TYPE_ICON, ColorPicker, picker_cursor_bg);
 	BIND_THEME_ITEM(Theme::DATA_TYPE_ICON, ColorPicker, picker_cursor_bg);
 	BIND_THEME_ITEM(Theme::DATA_TYPE_ICON, ColorPicker, color_hue);
 	BIND_THEME_ITEM(Theme::DATA_TYPE_ICON, ColorPicker, color_hue);
 
 
+	BIND_THEME_ITEM(Theme::DATA_TYPE_ICON, ColorPicker, color_script);
+
 	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_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_pressed, "tab_selected", "TabContainer");
 	BIND_THEME_ITEM_EXT(Theme::DATA_TYPE_STYLEBOX, ColorPicker, mode_button_hover, "tab_selected", "TabContainer");
 	BIND_THEME_ITEM_EXT(Theme::DATA_TYPE_STYLEBOX, ColorPicker, mode_button_hover, "tab_selected", "TabContainer");
@@ -2049,7 +2170,7 @@ ColorPicker::ColorPicker() {
 
 
 	add_mode(memnew(ColorModeRGB(this)));
 	add_mode(memnew(ColorModeRGB(this)));
 	add_mode(memnew(ColorModeHSV(this)));
 	add_mode(memnew(ColorModeHSV(this)));
-	add_mode(memnew(ColorModeRAW(this)));
+	add_mode(memnew(ColorModeLinear(this)));
 	add_mode(memnew(ColorModeOKHSL(this)));
 	add_mode(memnew(ColorModeOKHSL(this)));
 
 
 	mode_hbc = memnew(HBoxContainer);
 	mode_hbc = memnew(HBoxContainer);
@@ -2099,17 +2220,23 @@ ColorPicker::ColorPicker() {
 	slider_gc->set_h_size_flags(SIZE_EXPAND_FILL);
 	slider_gc->set_h_size_flags(SIZE_EXPAND_FILL);
 	slider_gc->set_columns(3);
 	slider_gc->set_columns(3);
 
 
-	for (int i = 0; i < SLIDER_COUNT + 1; i++) {
+	for (int i = 0; i < SLIDER_MAX; i++) {
 		create_slider(slider_gc, i);
 		create_slider(slider_gc, i);
 	}
 	}
-
 	alpha_label->set_text("A");
 	alpha_label->set_text("A");
 
 
+	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);
+
 	hex_hbc = memnew(HBoxContainer);
 	hex_hbc = memnew(HBoxContainer);
 	hex_hbc->set_alignment(ALIGNMENT_BEGIN);
 	hex_hbc->set_alignment(ALIGNMENT_BEGIN);
 	real_vbox->add_child(hex_hbc);
 	real_vbox->add_child(hex_hbc);
-
-	hex_hbc->add_child(memnew(Label(ETR("Hex"))));
+	hex_label = memnew(Label(ETR("Hex")));
+	hex_hbc->add_child(hex_label);
 
 
 	text_type = memnew(Button);
 	text_type = memnew(Button);
 	hex_hbc->add_child(text_type);
 	hex_hbc->add_child(text_type);
@@ -2128,8 +2255,6 @@ ColorPicker::ColorPicker() {
 		text_type->set_accessibility_name(ETR("Hexadecimal Values"));
 		text_type->set_accessibility_name(ETR("Hexadecimal Values"));
 #endif // TOOLS_ENABLED
 #endif // TOOLS_ENABLED
 		text_type->set_flat(true);
 		text_type->set_flat(true);
-		text_type->set_focus_mode(FOCUS_NONE);
-		text_type->set_mouse_filter(MOUSE_FILTER_IGNORE);
 	}
 	}
 
 
 	c_text = memnew(LineEdit);
 	c_text = memnew(LineEdit);
@@ -2376,6 +2501,20 @@ bool ColorPickerButton::is_editing_alpha() const {
 	return edit_alpha;
 	return edit_alpha;
 }
 }
 
 
+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;
+}
+
 ColorPicker *ColorPickerButton::get_picker() {
 ColorPicker *ColorPickerButton::get_picker() {
 	_update_picker();
 	_update_picker();
 	return picker;
 	return picker;
@@ -2400,6 +2539,7 @@ void ColorPickerButton::_update_picker() {
 		picker->connect(SceneStringName(minimum_size_changed), callable_mp((Window *)popup, &Window::reset_size));
 		picker->connect(SceneStringName(minimum_size_changed), callable_mp((Window *)popup, &Window::reset_size));
 		picker->set_pick_color(color);
 		picker->set_pick_color(color);
 		picker->set_edit_alpha(edit_alpha);
 		picker->set_edit_alpha(edit_alpha);
+		picker->set_edit_intensity(edit_intensity);
 		picker->set_display_old_color(true);
 		picker->set_display_old_color(true);
 		emit_signal(SNAME("picker_created"));
 		emit_signal(SNAME("picker_created"));
 	}
 	}
@@ -2412,6 +2552,8 @@ void ColorPickerButton::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("get_popup"), &ColorPickerButton::get_popup);
 	ClassDB::bind_method(D_METHOD("get_popup"), &ColorPickerButton::get_popup);
 	ClassDB::bind_method(D_METHOD("set_edit_alpha", "show"), &ColorPickerButton::set_edit_alpha);
 	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);
 	ClassDB::bind_method(D_METHOD("is_editing_alpha"), &ColorPickerButton::is_editing_alpha);
+	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);
 	ClassDB::bind_method(D_METHOD("_about_to_popup"), &ColorPickerButton::_about_to_popup);
 	ClassDB::bind_method(D_METHOD("_about_to_popup"), &ColorPickerButton::_about_to_popup);
 
 
 	ADD_SIGNAL(MethodInfo("color_changed", PropertyInfo(Variant::COLOR, "color")));
 	ADD_SIGNAL(MethodInfo("color_changed", PropertyInfo(Variant::COLOR, "color")));
@@ -2419,6 +2561,7 @@ void ColorPickerButton::_bind_methods() {
 	ADD_SIGNAL(MethodInfo("picker_created"));
 	ADD_SIGNAL(MethodInfo("picker_created"));
 	ADD_PROPERTY(PropertyInfo(Variant::COLOR, "color"), "set_pick_color", "get_pick_color");
 	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");
 	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "edit_alpha"), "set_edit_alpha", "is_editing_alpha");
+	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "edit_intensity"), "set_edit_intensity", "is_editing_intensity");
 
 
 	BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_STYLEBOX, ColorPickerButton, normal_style, "normal");
 	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_CUSTOM(Theme::DATA_TYPE_ICON, ColorPickerButton, background_icon, "bg");
@@ -2488,7 +2631,7 @@ void ColorPresetButton::_notification(int p_what) {
 				theme_cache.focus_style->draw(ci, Rect2(Point2(), get_size()));
 				theme_cache.focus_style->draw(ci, Rect2(Point2(), get_size()));
 			}
 			}
 
 
-			if (preset_color.r > 1 || preset_color.g > 1 || preset_color.b > 1) {
+			if (is_color_overbright(preset_color)) {
 				// Draw an indicator to denote that the color is "overbright" and can't be displayed accurately in the preview
 				// Draw an indicator to denote that the color is "overbright" and can't be displayed accurately in the preview
 				draw_texture(theme_cache.overbright_indicator, Vector2(0, 0));
 				draw_texture(theme_cache.overbright_indicator, Vector2(0, 0));
 			}
 			}
@@ -2509,9 +2652,9 @@ Color ColorPresetButton::get_preset_color() const {
 String ColorPresetButton::get_tooltip(const Point2 &p_pos) const {
 String ColorPresetButton::get_tooltip(const Point2 &p_pos) const {
 	Color color = get_preset_color();
 	Color color = get_preset_color();
 	if (recent) {
 	if (recent) {
-		return vformat(atr(ETR("Color: #%s\nLMB: Apply color")), color.to_html(color.a < 1));
+		return vformat(atr(ETR("Color: %s\nLMB: Apply color")), color_to_string(color, color.a < 1));
 	}
 	}
-	return vformat(atr(ETR("Color: #%s\nLMB: Apply color\nRMB: Remove preset")), color.to_html(color.a < 1));
+	return vformat(atr(ETR("Color: %s\nLMB: Apply color\nRMB: Remove preset")), color_to_string(color, color.a < 1));
 }
 }
 
 
 void ColorPresetButton::_bind_methods() {
 void ColorPresetButton::_bind_methods() {
@@ -2526,7 +2669,7 @@ ColorPresetButton::ColorPresetButton(Color p_color, int p_size, bool p_recent) {
 	recent = p_recent;
 	recent = p_recent;
 	set_toggle_mode(true);
 	set_toggle_mode(true);
 	set_custom_minimum_size(Size2(p_size, p_size));
 	set_custom_minimum_size(Size2(p_size, p_size));
-	set_accessibility_name(vformat(atr(ETR("Color: #%s")), p_color.to_html(p_color.a < 1)));
+	set_accessibility_name(vformat(atr(ETR("Color: %s")), color_to_string(p_color, p_color.a < 1)));
 	set_tooltip_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED);
 	set_tooltip_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED);
 }
 }
 
 

+ 45 - 10
scene/gui/color_picker.h

@@ -91,14 +91,17 @@ class ColorPicker : public VBoxContainer {
 
 
 	friend class ColorModeRGB;
 	friend class ColorModeRGB;
 	friend class ColorModeHSV;
 	friend class ColorModeHSV;
-	friend class ColorModeRAW;
+	friend class ColorModeLinear;
 	friend class ColorModeOKHSL;
 	friend class ColorModeOKHSL;
 
 
 public:
 public:
 	enum ColorModeType {
 	enum ColorModeType {
 		MODE_RGB,
 		MODE_RGB,
 		MODE_HSV,
 		MODE_HSV,
-		MODE_RAW,
+#ifndef DISABLE_DEPRECATED
+		MODE_RAW = 2,
+#endif
+		MODE_LINEAR = 2,
 		MODE_OKHSL,
 		MODE_OKHSL,
 
 
 		MODE_MAX
 		MODE_MAX
@@ -115,6 +118,12 @@ public:
 	};
 	};
 
 
 	static const int SLIDER_COUNT = 3;
 	static const int SLIDER_COUNT = 3;
+	enum SLIDER_EXTRA {
+		SLIDER_INTENSITY = 3,
+		SLIDER_ALPHA,
+
+		SLIDER_MAX
+	};
 
 
 private:
 private:
 	enum class MenuOption {
 	enum class MenuOption {
@@ -136,7 +145,6 @@ private:
 #endif
 #endif
 
 
 	int current_slider_count = SLIDER_COUNT;
 	int current_slider_count = SLIDER_COUNT;
-	Vector2i circle_keyboard_joypad_picker_cursor_position;
 
 
 	const float DEFAULT_GAMEPAD_EVENT_DELAY_MS = 1.0 / 2;
 	const float DEFAULT_GAMEPAD_EVENT_DELAY_MS = 1.0 / 2;
 	const float GAMEPAD_EVENT_REPEAT_RATE_MS = 1.0 / 30;
 	const float GAMEPAD_EVENT_REPEAT_RATE_MS = 1.0 / 30;
@@ -182,6 +190,7 @@ private:
 	HBoxContainer *sample_hbc = nullptr;
 	HBoxContainer *sample_hbc = nullptr;
 	GridContainer *slider_gc = nullptr;
 	GridContainer *slider_gc = nullptr;
 	HBoxContainer *hex_hbc = nullptr;
 	HBoxContainer *hex_hbc = nullptr;
+	Label *hex_label = nullptr;
 	MenuButton *btn_mode = nullptr;
 	MenuButton *btn_mode = nullptr;
 	Button *mode_btns[MODE_BUTTON_COUNT];
 	Button *mode_btns[MODE_BUTTON_COUNT];
 	Ref<ButtonGroup> mode_group;
 	Ref<ButtonGroup> mode_group;
@@ -199,9 +208,10 @@ private:
 
 
 	OptionButton *mode_option_button = nullptr;
 	OptionButton *mode_option_button = nullptr;
 
 
-	HSlider *sliders[SLIDER_COUNT];
-	SpinBox *values[SLIDER_COUNT];
-	Label *labels[SLIDER_COUNT];
+	HSlider *sliders[SLIDER_MAX];
+	SpinBox *values[SLIDER_MAX];
+	Label *labels[SLIDER_MAX];
+
 	Button *text_type = nullptr;
 	Button *text_type = nullptr;
 	LineEdit *c_text = nullptr;
 	LineEdit *c_text = nullptr;
 
 
@@ -210,6 +220,13 @@ private:
 	Label *alpha_label = nullptr;
 	Label *alpha_label = nullptr;
 
 
 	bool edit_alpha = true;
 	bool edit_alpha = true;
+
+	HSlider *intensity_slider = nullptr;
+	SpinBox *intensity_value = nullptr;
+	Label *intensity_label = nullptr;
+
+	bool edit_intensity = true;
+
 	Size2i ms;
 	Size2i ms;
 	bool text_is_constructor = false;
 	bool text_is_constructor = false;
 	PickerShapeType current_shape = SHAPE_HSV_RECTANGLE;
 	PickerShapeType current_shape = SHAPE_HSV_RECTANGLE;
@@ -223,6 +240,7 @@ private:
 	List<Color> recent_presets;
 	List<Color> recent_presets;
 
 
 	Color color;
 	Color color;
+	Color color_normalized;
 	Color old_color;
 	Color old_color;
 	Color pre_picking_color;
 	Color pre_picking_color;
 	bool is_picking_color = false;
 	bool is_picking_color = false;
@@ -250,7 +268,10 @@ private:
 	float ok_hsl_s = 0.0;
 	float ok_hsl_s = 0.0;
 	float ok_hsl_l = 0.0;
 	float ok_hsl_l = 0.0;
 
 
-	Color last_color;
+	bool hsv_cached = false;
+	bool okhsl_cached = false;
+
+	float intensity = 0.0;
 
 
 	struct ThemeCache {
 	struct ThemeCache {
 		float base_scale = 1.0;
 		float base_scale = 1.0;
@@ -286,14 +307,20 @@ private:
 		Ref<Texture2D> picker_cursor_bg;
 		Ref<Texture2D> picker_cursor_bg;
 		Ref<Texture2D> color_hue;
 		Ref<Texture2D> color_hue;
 
 
+		Ref<Texture2D> color_script;
+
 		/* Mode buttons */
 		/* Mode buttons */
 		Ref<StyleBox> mode_button_normal;
 		Ref<StyleBox> mode_button_normal;
 		Ref<StyleBox> mode_button_pressed;
 		Ref<StyleBox> mode_button_pressed;
 		Ref<StyleBox> mode_button_hover;
 		Ref<StyleBox> mode_button_hover;
 	} theme_cache;
 	} theme_cache;
 
 
-	void _copy_color_to_hsv();
-	void _copy_hsv_to_color();
+	void _copy_normalized_to_hsv_okhsl();
+	void _copy_hsv_okhsl_to_normalized();
+
+	Color _color_apply_intensity(const Color &col) const;
+	void _normalized_apply_intensity_to_color();
+	void _copy_color_to_normalized_and_intensity();
 
 
 	void create_slider(GridContainer *gc, int idx);
 	void create_slider(GridContainer *gc, int idx);
 	void _reset_sliders_theme();
 	void _reset_sliders_theme();
@@ -310,6 +337,7 @@ private:
 	void _sample_input(const Ref<InputEvent> &p_event);
 	void _sample_input(const Ref<InputEvent> &p_event);
 	void _sample_draw();
 	void _sample_draw();
 	void _slider_draw(int p_which);
 	void _slider_draw(int p_which);
+	void _alpha_slider_draw();
 
 
 	void _slider_or_spin_input(const Ref<InputEvent> &p_event);
 	void _slider_or_spin_input(const Ref<InputEvent> &p_event);
 	void _line_edit_input(const Ref<InputEvent> &p_event);
 	void _line_edit_input(const Ref<InputEvent> &p_event);
@@ -378,7 +406,10 @@ public:
 	void set_edit_alpha(bool p_show);
 	void set_edit_alpha(bool p_show);
 	bool is_editing_alpha() const;
 	bool is_editing_alpha() const;
 
 
-	void _set_pick_color(const Color &p_color, bool p_update_sliders);
+	void set_edit_intensity(bool p_show);
+	bool is_editing_intensity() const;
+
+	void _set_pick_color(const Color &p_color, bool p_update_sliders, bool p_calc_intensity);
 	void set_pick_color(const Color &p_color);
 	void set_pick_color(const Color &p_color);
 	Color get_pick_color() const;
 	Color get_pick_color() const;
 	void set_old_color(const Color &p_color);
 	void set_old_color(const Color &p_color);
@@ -453,6 +484,7 @@ class ColorPickerButton : public Button {
 	ColorPicker *picker = nullptr;
 	ColorPicker *picker = nullptr;
 	Color color;
 	Color color;
 	bool edit_alpha = true;
 	bool edit_alpha = true;
+	bool edit_intensity = true;
 
 
 	struct ThemeCache {
 	struct ThemeCache {
 		Ref<StyleBox> normal_style;
 		Ref<StyleBox> normal_style;
@@ -480,6 +512,9 @@ public:
 	void set_edit_alpha(bool p_show);
 	void set_edit_alpha(bool p_show);
 	bool is_editing_alpha() const;
 	bool is_editing_alpha() const;
 
 
+	void set_edit_intensity(bool p_show);
+	bool is_editing_intensity() const;
+
 	ColorPicker *get_picker();
 	ColorPicker *get_picker();
 	PopupPanel *get_popup();
 	PopupPanel *get_popup();
 
 

+ 7 - 7
scene/gui/color_picker_shape.cpp

@@ -68,9 +68,11 @@ bool ColorPickerShape::can_handle(const Ref<InputEvent> &p_event, Vector2 &r_pos
 }
 }
 
 
 void ColorPickerShape::apply_color() {
 void ColorPickerShape::apply_color() {
-	color_picker->_copy_hsv_to_color();
-	color_picker->last_color = color_picker->color;
-	color_picker->set_pick_color(color_picker->color);
+	color_picker->_copy_hsv_okhsl_to_normalized();
+	color_picker->_normalized_apply_intensity_to_color();
+	color_picker->hsv_cached = true;
+	color_picker->okhsl_cached = true;
+	color_picker->_set_pick_color(color_picker->color, true, false);
 
 
 	if (!color_picker->deferred_mode_enabled) {
 	if (!color_picker->deferred_mode_enabled) {
 		_emit_color_changed();
 		_emit_color_changed();
@@ -122,10 +124,8 @@ void ColorPickerShape::draw_sv_square(Control *p_control, const Rect2 &p_square,
 		Vector2(p_square.position.x, end.y),
 		Vector2(p_square.position.x, end.y),
 	};
 	};
 
 
-	Color color1 = color_picker->color;
-	color1.set_hsv(color_picker->h, 1, 1);
-	Color color2 = color1;
-	color2.set_hsv(color_picker->h, 1, 0);
+	Color color1 = Color::from_hsv(color_picker->h, 1, 1);
+	Color color2 = Color::from_hsv(color_picker->h, 1, 0);
 
 
 	PackedColorArray colors = {
 	PackedColorArray colors = {
 		Color(1, 1, 1, 1),
 		Color(1, 1, 1, 1),

+ 1 - 0
scene/theme/default_theme.cpp

@@ -1055,6 +1055,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
 	theme->set_icon("bar_arrow", "ColorPicker", icons["color_picker_bar_arrow"]);
 	theme->set_icon("bar_arrow", "ColorPicker", icons["color_picker_bar_arrow"]);
 	theme->set_icon("picker_cursor", "ColorPicker", icons["color_picker_cursor"]);
 	theme->set_icon("picker_cursor", "ColorPicker", icons["color_picker_cursor"]);
 	theme->set_icon("picker_cursor_bg", "ColorPicker", icons["color_picker_cursor_bg"]);
 	theme->set_icon("picker_cursor_bg", "ColorPicker", icons["color_picker_cursor_bg"]);
+	theme->set_icon("color_script", "ColorPicker", icons["script"]);
 
 
 	{
 	{
 		const int precision = 7;
 		const int precision = 7;

+ 1 - 0
scene/theme/icons/script.svg

@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><path fill="#e0e0e0" d="M6 1a2 2 0 0 0-2 2v7H1v3a2 2 0 0 0 2 2h7a2 2 0 0 0 2-2V5h3V3a2 2 0 0 0-2-2z"/><path fill-opacity=".2" d="M6 1a2 2 0 0 0-2 2v7H1v3a2 2 0 1 0 4 0V3a1 1 0 0 1 2 0v3h5V5H8V3a2 2 0 0 0-2-2zM2 11h2v2a1 1 0 0 1-2 0z"/></svg>