Skip to content

Commit

Permalink
ColorPicker: Add an intensity slider in raw mode for HDR
Browse files Browse the repository at this point in the history
When color is overbright, automatically switch the hex text to script text. Meanwhile, add the "script" icon to theme to ensure the icon is also visible at runtime.
  • Loading branch information
beicause committed Mar 6, 2025
1 parent ea4e641 commit 2bb6120
Show file tree
Hide file tree
Showing 8 changed files with 82 additions and 30 deletions.
3 changes: 3 additions & 0 deletions doc/classes/ColorPicker.xml
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,9 @@
<theme_item name="color_hue" data_type="icon" type="Texture2D">
Custom texture for the hue selection slider on the right.
</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">
The icon for color preset drop down menu when expanded.
</theme_item>
Expand Down
1 change: 1 addition & 0 deletions editor/themes/editor_theme_manager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1769,6 +1769,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("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("color_script", "ColorPicker", p_theme->get_icon(SNAME("Script"), EditorStringName(EditorIcons)));

// ColorPickerButton.
p_theme->set_icon("bg", "ColorPickerButton", p_theme->get_icon(SNAME("GuiMiniCheckerboard"), EditorStringName(EditorIcons)));
Expand Down
27 changes: 21 additions & 6 deletions scene/gui/color_mode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -204,26 +204,41 @@ 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.");
ERR_FAIL_INDEX_V_MSG(idx, 4, String(), "Couldn't get slider label.");
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.");
ERR_FAIL_INDEX_V_MSG(idx, 5, 0, "Couldn't get slider max value.");
return slider_max[idx];
}

float ColorModeRAW::get_slider_min(int idx) const {
ERR_FAIL_INDEX_V_MSG(idx, 5, 0, "Couldn't get slider min value.");
return idx == 3 ? intensity_min : 0;
}

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];
ERR_FAIL_INDEX_V_MSG(idx, 5, 0, "Couldn't get slider value.");
Color color = color_picker->get_pick_color();
float multiplier = MAX(1, MAX(MAX(color.r, color.g), color.b));
if (idx == 3) {
return Math::log2(multiplier);
} else if (idx == 4) {
return color.a;
} else {
return color.components[idx] / multiplier;
}
}

Color ColorModeRAW::get_color() const {
Vector<float> values = color_picker->get_active_slider_values();
Color color;
for (int i = 0; i < 4; i++) {
color.components[i] = values[i];
float multiplier = Math::pow(2, values[3]);
for (int i = 0; i < 3; i++) {
color.components[i] = values[i] * multiplier;
}
color.a = values[4];
return color;
}

Expand Down
8 changes: 6 additions & 2 deletions scene/gui/color_mode.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ class ColorMode {
virtual float get_spinbox_arrow_step() const { return get_slider_step(); }
virtual String get_slider_label(int idx) const = 0;
virtual float get_slider_max(int idx) const = 0;
virtual float get_slider_min(int idx) const { return 0; }
virtual bool get_allow_greater() const { return false; }
virtual float get_slider_value(int idx) const = 0;

Expand Down Expand Up @@ -107,15 +108,18 @@ class ColorModeRGB : public ColorMode {

class ColorModeRAW : public ColorMode {
public:
String labels[3] = { "R", "G", "B" };
float slider_max[4] = { 100, 100, 100, 1 };
String labels[4] = { "R", "G", "B", "I" };
float slider_max[5] = { 1, 1, 1, 4, 1 };
float intensity_min = -4;

virtual String get_name() const override { return "RAW"; }

virtual int get_slider_count() const override { return 4; }
virtual float get_slider_step() const override { return 0.001; }
virtual float get_spinbox_arrow_step() const override { return 0.01; }
virtual String get_slider_label(int idx) const override;
virtual float get_slider_max(int idx) const override;
virtual float get_slider_min(int idx) const override;
virtual bool get_allow_greater() const override { return true; }
virtual float get_slider_value(int idx) const override;

Expand Down
67 changes: 46 additions & 21 deletions scene/gui/color_picker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -137,10 +137,8 @@ void ColorPicker::_notification(int p_what) {

_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));
}
// Adjust for the width of the "script" icon.
text_type->set_custom_minimum_size(Size2(28 * theme_cache.base_scale, 0));

_update_presets();
_update_recent_presets();
Expand Down Expand Up @@ -432,6 +430,25 @@ void ColorPicker::_slider_value_changed() {
s = color.get_s();
v = color.get_v();
last_color = color;
} else if (current_mode == MODE_RAW) {
// If any of rgb sliders exceeds 1, set the color component as is.
bool is_rgb_exceeds = false;
for (int i = 0; i < 3; i++) {
if (sliders[i]->get_value() >= 1 + CMP_EPSILON) {
color.components[i] = sliders[i]->get_value();
is_rgb_exceeds = true;
}
}
// Then recalculate intensity and keep rgb sliders within 1.
if (is_rgb_exceeds) {
float multiplier = MAX(1, MAX(MAX(color.r, color.g), color.b));
sliders[0]->set_value_no_signal(color.r / multiplier);
sliders[1]->set_value_no_signal(color.g / multiplier);
sliders[2]->set_value_no_signal(color.b / multiplier);
sliders[3]->set_value_no_signal(Math::log2(multiplier));
}
// Set intensity spinbox prefix.
values[3]->set_prefix(sliders[3]->get_value() < 0 ? "" : "+");
}

_set_pick_color(color, false);
Expand Down Expand Up @@ -483,6 +500,10 @@ void ColorPicker::create_slider(GridContainer *gc, int idx) {
slider->connect(SceneStringName(gui_input), callable_mp(this, &ColorPicker::_slider_or_spin_input));

if (idx < SLIDER_COUNT) {
// Intensity slider
if (idx == 3) {
val->set_prefix("+");
}
sliders[idx] = slider;
values[idx] = val;
labels[idx] = lbl;
Expand Down Expand Up @@ -625,7 +646,7 @@ void ColorPicker::_reset_sliders_theme() {
}

void ColorPicker::_html_submitted(const String &p_html) {
if (updating || text_is_constructor || !c_text->is_visible()) {
if (updating || text_is_constructor || !c_text->is_editable()) {
return;
}

Expand Down Expand Up @@ -674,6 +695,7 @@ void ColorPicker::_update_color(bool p_update_sliders) {
float spinbox_arrow_step = modes[current_mode]->get_spinbox_arrow_step();
for (int i = 0; i < current_slider_count; i++) {
sliders[i]->set_max(modes[current_mode]->get_slider_max(i));
sliders[i]->set_min(modes[current_mode]->get_slider_min(i));
sliders[i]->set_step(step);
sliders[i]->set_value(modes[current_mode]->get_slider_value(i));
values[i]->set_custom_arrow_step(spinbox_arrow_step);
Expand Down Expand Up @@ -769,9 +791,7 @@ void ColorPicker::_text_type_toggled() {
text_is_constructor = !text_is_constructor;
if (text_is_constructor) {
text_type->set_text("");
#ifdef TOOLS_ENABLED
text_type->set_button_icon(get_editor_theme_icon(SNAME("Script")));
#endif
text_type->set_button_icon(theme_cache.color_script);

c_text->set_editable(false);
c_text->set_tooltip_text(RTR("Copy this constructor in a script."));
Expand Down Expand Up @@ -1237,25 +1257,29 @@ bool ColorPicker::is_deferred_mode() const {
}

void ColorPicker::_update_text_value() {
bool text_visible = true;
if (text_is_constructor) {
bool is_hex_valid = (color.r < 1.0 + CMP_EPSILON) && (color.g < 1.0 + CMP_EPSILON) && (color.b < 1.0 + CMP_EPSILON) && color.r >= 0 && color.g >= 0 && color.b >= 0;
if (text_is_constructor || !is_hex_valid) {
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 += ")";
}
text_type->set_text("");
text_type->set_button_icon(theme_cache.color_script);

text_type->set_disabled(!is_hex_valid);

c_text->set_text(t);
}
c_text->set_editable(false);
} else {
text_type->set_text("#");
text_type->set_button_icon(nullptr);
text_type->set_disabled(false);

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) {
c_text->set_text(color.to_html(edit_alpha && color.a < 1));
c_text->set_editable(true);
}

text_type->set_visible(text_visible);
c_text->set_visible(text_visible);
}

void ColorPicker::_sample_input(const Ref<InputEvent> &p_event) {
Expand Down Expand Up @@ -2191,6 +2215,8 @@ void ColorPicker::_bind_methods() {
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_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_pressed, "tab_selected", "TabContainer");
BIND_THEME_ITEM_EXT(Theme::DATA_TYPE_STYLEBOX, ColorPicker, mode_button_hover, "tab_selected", "TabContainer");
Expand Down Expand Up @@ -2306,13 +2332,12 @@ ColorPicker::ColorPicker() {

text_type = memnew(Button);
hex_hbc->add_child(text_type);
text_type->set_icon_alignment(HORIZONTAL_ALIGNMENT_CENTER);
text_type->set_text("#");
text_type->set_tooltip_text(RTR("Switch between hexadecimal and code values."));
if (Engine::get_singleton()->is_editor_hint()) {
text_type->connect(SceneStringName(pressed), callable_mp(this, &ColorPicker::_text_type_toggled));
} else {
text_type->connect(SceneStringName(pressed), callable_mp(this, &ColorPicker::_text_type_toggled));
if (!Engine::get_singleton()->is_editor_hint()) {
text_type->set_flat(true);
text_type->set_mouse_filter(MOUSE_FILTER_IGNORE);
}

c_text = memnew(LineEdit);
Expand Down
4 changes: 3 additions & 1 deletion scene/gui/color_picker.h
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ class ColorPicker : public VBoxContainer {
SHAPE_MAX
};

static const int SLIDER_COUNT = 3;
static const int SLIDER_COUNT = 4;

private:
enum class MenuOption {
Expand Down Expand Up @@ -269,6 +269,8 @@ class ColorPicker : public VBoxContainer {
Ref<Texture2D> picker_cursor_bg;
Ref<Texture2D> color_hue;

Ref<Texture2D> color_script;

/* Mode buttons */
Ref<StyleBox> mode_button_normal;
Ref<StyleBox> mode_button_pressed;
Expand Down
1 change: 1 addition & 0 deletions scene/theme/default_theme.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1056,6 +1056,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("picker_cursor", "ColorPicker", icons["color_picker_cursor"]);
theme->set_icon("picker_cursor_bg", "ColorPicker", icons["color_picker_cursor_bg"]);
theme->set_icon("color_script", "ColorPicker", icons["script"]);

{
const int precision = 7;
Expand Down
1 change: 1 addition & 0 deletions scene/theme/icons/script.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 2bb6120

Please sign in to comment.