Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve ColorPicker presets [3.x] #54439

Merged
merged 1 commit into from
Jan 17, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions editor/editor_themes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1279,6 +1279,14 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {

theme->set_icon("bg", "ColorPickerButton", theme->get_icon("GuiMiniCheckerboard", "EditorIcons"));

// ColorPresetButton
Ref<StyleBoxFlat> preset_sb = make_flat_stylebox(Color(1, 1, 1), 2, 2, 2, 2);

preset_sb->set_anti_aliased(false);
theme->set_stylebox("preset_fg", "ColorPresetButton", preset_sb);
theme->set_icon("preset_bg_icon", "ColorPresetButton", theme->get_icon("GuiMiniCheckerboard", "EditorIcons"));
theme->set_icon("overbright_indicator", "ColorPresetButton", theme->get_icon("OverbrightIndicator", "EditorIcons"));

// Information on 3D viewport
Ref<StyleBoxFlat> style_info_3d_viewport = style_default->duplicate();
style_info_3d_viewport->set_bg_color(style_info_3d_viewport->get_bg_color() * Color(1, 1, 1, 0.5));
Expand Down
186 changes: 121 additions & 65 deletions scene/gui/color_picker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,13 +46,13 @@ void ColorPicker::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_THEME_CHANGED: {
btn_pick->set_icon(get_icon("screen_picker", "ColorPicker"));
bt_add_preset->set_icon(get_icon("add_preset"));

btn_add_preset->set_icon(get_icon("add_preset"));
_update_presets();
_update_controls();
} break;
case NOTIFICATION_ENTER_TREE: {
btn_pick->set_icon(get_icon("screen_picker", "ColorPicker"));
bt_add_preset->set_icon(get_icon("add_preset"));
btn_add_preset->set_icon(get_icon("add_preset"));

_update_controls();
_update_color();
Expand All @@ -69,7 +69,6 @@ void ColorPicker::_notification(int p_what) {
for (int i = 0; i < preset_cache.size(); i++) {
presets.push_back(preset_cache[i]);
}
preset->update();
}
#endif
} break;
Expand Down Expand Up @@ -255,19 +254,15 @@ void ColorPicker::_update_color(bool p_update_sliders) {
}

void ColorPicker::_update_presets() {
presets_per_row = 10;
Size2 size = bt_add_preset->get_size();
Size2 preset_size = Size2(MIN(size.width * presets.size(), presets_per_row * size.width), size.height * (Math::ceil((float)presets.size() / presets_per_row)));
preset->set_custom_minimum_size(preset_size);
preset_container->set_custom_minimum_size(preset_size);
preset->draw_rect(Rect2(Point2(), preset_size), Color(1, 1, 1, 0));

for (int i = 0; i < presets.size(); i++) {
int x = (i % presets_per_row) * size.width;
int y = (Math::floor((float)i / presets_per_row)) * size.height;
preset->draw_rect(Rect2(Point2(x, y), size), presets[i]);
// Only load preset buttons when the only child is the add-preset button.
int preset_size = _get_preset_size();
btn_add_preset->set_custom_minimum_size(Size2(preset_size, preset_size));
if (preset_container->get_child_count() == 1) {
for (int i = 0; i < preset_cache.size(); i++) {
_add_preset_button(preset_size, preset_cache[i]);
}
_notification(NOTIFICATION_VISIBILITY_CHANGED);
}
_notification(NOTIFICATION_VISIBILITY_CHANGED);
}

void ColorPicker::_text_type_toggled() {
Expand All @@ -290,14 +285,38 @@ Color ColorPicker::get_pick_color() const {
return color;
}

inline int ColorPicker::_get_preset_size() {
return (int(get_size().width) - (preset_container->get_constant("hseparation") * (preset_column_count - 1))) / preset_column_count;
}

void ColorPicker::_add_preset_button(int p_size, const Color &p_color) {
ColorPresetButton *btn_preset = memnew(ColorPresetButton(p_color));
btn_preset->set_preset_color(p_color);
btn_preset->set_custom_minimum_size(Size2(p_size, p_size));
btn_preset->connect("gui_input", this, "_preset_input", varray(p_color));
btn_preset->set_tooltip(vformat(RTR("Color: #%s\nLMB: Apply color\nRMB: Remove preset"), p_color.to_html(p_color.a < 1)));
preset_container->add_child(btn_preset);
}

void ColorPicker::add_preset(const Color &p_color) {
if (presets.find(p_color)) {
presets.move_to_back(presets.find(p_color));

// Find button to move to the end.
for (int i = 1; i < preset_container->get_child_count(); i++) {
ColorPresetButton *current_btn = Object::cast_to<ColorPresetButton>(preset_container->get_child(i));
if (current_btn && p_color == current_btn->get_preset_color()) {
preset_container->move_child(current_btn, preset_container->get_child_count() - 1);
break;
}
}
} else {
presets.push_back(p_color);
preset_cache.push_back(p_color);

_add_preset_button(_get_preset_size(), p_color);
_notification(NOTIFICATION_VISIBILITY_CHANGED);
}
preset->update();

#ifdef TOOLS_ENABLED
if (Engine::get_singleton()->is_editor_hint()) {
Expand All @@ -311,7 +330,15 @@ void ColorPicker::erase_preset(const Color &p_color) {
if (presets.find(p_color)) {
presets.erase(presets.find(p_color));
preset_cache.erase(preset_cache.find(p_color));
preset->update();

// Find preset button to remove.
for (int i = 1; i < preset_container->get_child_count(); i++) {
ColorPresetButton *current_btn = Object::cast_to<ColorPresetButton>(preset_container->get_child(i));
if (current_btn && p_color == current_btn->get_preset_color()) {
current_btn->queue_delete();
break;
}
}

#ifdef TOOLS_ENABLED
if (Engine::get_singleton()->is_editor_hint()) {
Expand Down Expand Up @@ -585,42 +612,18 @@ void ColorPicker::_w_input(const Ref<InputEvent> &p_event) {
}
}

void ColorPicker::_preset_input(const Ref<InputEvent> &p_event) {
void ColorPicker::_preset_input(const Ref<InputEvent> &p_event, const Color &p_color) {
Ref<InputEventMouseButton> bev = p_event;

if (bev.is_valid()) {
int index = 0;
if (bev->is_pressed() && bev->get_button_index() == BUTTON_LEFT) {
for (int i = 0; i < presets.size(); i++) {
int x = (i % presets_per_row) * bt_add_preset->get_size().x;
int y = (Math::floor((float)i / presets_per_row)) * bt_add_preset->get_size().y;
if (bev->get_position().x > x && bev->get_position().x < x + preset->get_size().x && bev->get_position().y > y && bev->get_position().y < y + preset->get_size().y) {
index = i;
}
}
set_pick_color(presets[index]);
set_pick_color(p_color);
_update_color();
emit_signal("color_changed", color);
emit_signal("color_changed", p_color);
} else if (bev->is_pressed() && bev->get_button_index() == BUTTON_RIGHT && presets_enabled) {
index = bev->get_position().x / (preset->get_size().x / presets.size());
Color clicked_preset = presets[index];
erase_preset(clicked_preset);
emit_signal("preset_removed", clicked_preset);
bt_add_preset->show();
}
}

Ref<InputEventMouseMotion> mev = p_event;

if (mev.is_valid()) {
int index = mev->get_position().x * presets.size();
if (preset->get_size().x != 0) {
index /= preset->get_size().x;
erase_preset(p_color);
emit_signal("preset_removed", p_color);
}
if (index < 0 || index >= presets.size()) {
return;
}
preset->set_tooltip(vformat(RTR("Color: #%s\nLMB: Set color\nRMB: Remove preset"), presets[index].to_html(presets[index].a < 1)));
}
}

Expand Down Expand Up @@ -715,11 +718,11 @@ void ColorPicker::_html_focus_exit() {
void ColorPicker::set_presets_enabled(bool p_enabled) {
presets_enabled = p_enabled;
if (!p_enabled) {
bt_add_preset->set_disabled(true);
bt_add_preset->set_focus_mode(FOCUS_NONE);
btn_add_preset->set_disabled(true);
btn_add_preset->set_focus_mode(FOCUS_NONE);
} else {
bt_add_preset->set_disabled(false);
bt_add_preset->set_focus_mode(FOCUS_ALL);
btn_add_preset->set_disabled(false);
btn_add_preset->set_focus_mode(FOCUS_ALL);
}
}

Expand All @@ -731,7 +734,6 @@ void ColorPicker::set_presets_visible(bool p_visible) {
presets_visible = p_visible;
preset_separator->set_visible(p_visible);
preset_container->set_visible(p_visible);
preset_container2->set_visible(p_visible);
}

bool ColorPicker::are_presets_visible() const {
Expand Down Expand Up @@ -915,22 +917,14 @@ ColorPicker::ColorPicker() :
preset_separator = memnew(HSeparator);
add_child(preset_separator);

preset_container = memnew(HBoxContainer);
preset_container->set_h_size_flags(SIZE_EXPAND_FILL);
preset_container->set_columns(preset_column_count);
add_child(preset_container);

preset = memnew(TextureRect);
preset_container->add_child(preset);
preset->connect("gui_input", this, "_preset_input");
preset->connect("draw", this, "_update_presets");

preset_container2 = memnew(HBoxContainer);
preset_container2->set_h_size_flags(SIZE_EXPAND_FILL);
add_child(preset_container2);
bt_add_preset = memnew(Button);
preset_container2->add_child(bt_add_preset);
bt_add_preset->set_tooltip(RTR("Add current color as a preset."));
bt_add_preset->connect("pressed", this, "_add_preset_pressed");
btn_add_preset = memnew(Button);
btn_add_preset->connect("pressed", this, "_add_preset_pressed");
btn_add_preset->set_tooltip(RTR("Add current color as a preset."));
preset_container->add_child(btn_add_preset);
}

/////////////////
Expand All @@ -954,6 +948,7 @@ void ColorPickerButton::_modal_closed() {

void ColorPickerButton::pressed() {
_update_picker();
picker->_update_presets();
popup->set_position(get_global_position() - picker->get_combined_minimum_size() * get_global_transform().get_scale());
popup->set_scale(get_global_transform().get_scale());
popup->popup();
Expand Down Expand Up @@ -1077,3 +1072,64 @@ ColorPickerButton::ColorPickerButton() {

set_toggle_mode(true);
}

/////////////////

void ColorPresetButton::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_DRAW: {
const Rect2 r = Rect2(Point2(0, 0), get_size());
Ref<StyleBox> sb_raw = get_stylebox("preset_fg", "ColorPresetButton")->duplicate();
Ref<StyleBoxFlat> sb_flat = sb_raw;
Ref<StyleBoxTexture> sb_texture = sb_raw;

if (sb_raw->get_class_name() == "StyleBoxFlat") {
if (preset_color.a < 1) {
// Draw a background pattern when the color is transparent.
sb_flat->set_bg_color(Color(1, 1, 1));
sb_flat->draw(get_canvas_item(), r);

Rect2 bg_texture_rect = r.grow_margin(MARGIN_LEFT, -sb_flat->get_margin(MARGIN_LEFT));
bg_texture_rect = bg_texture_rect.grow_margin(MARGIN_RIGHT, -sb_flat->get_margin(MARGIN_RIGHT));
bg_texture_rect = bg_texture_rect.grow_margin(MARGIN_TOP, -sb_flat->get_margin(MARGIN_TOP));
bg_texture_rect = bg_texture_rect.grow_margin(MARGIN_BOTTOM, -sb_flat->get_margin(MARGIN_BOTTOM));

draw_texture_rect(get_icon("preset_bg_icon", "ColorPresetButton"), bg_texture_rect, true);
sb_flat->set_bg_color(preset_color);
}
sb_flat->set_bg_color(preset_color);
sb_flat->draw(get_canvas_item(), r);
} else if (sb_raw->get_class_name() == "StyleBoxTexture") {
if (preset_color.a < 1) {
// Draw a background pattern when the color is transparent.
bool use_tile_texture = (sb_texture->get_h_axis_stretch_mode() == StyleBoxTexture::AxisStretchMode::AXIS_STRETCH_MODE_TILE) || (sb_texture->get_h_axis_stretch_mode() == StyleBoxTexture::AxisStretchMode::AXIS_STRETCH_MODE_TILE_FIT);
draw_texture_rect(get_icon("preset_bg_icon", "ColorPresetButton"), r, use_tile_texture);
}
sb_texture->set_modulate(preset_color);
sb_texture->draw(get_canvas_item(), r);
} else {
WARN_PRINT("Unsupported StyleBox used for ColorPresetButton. Use StyleBoxFlat and StyleBoxTexture instead.");
}
if (preset_color.r > 1 || preset_color.g > 1 || preset_color.b > 1) {
// Draw an indicator to denote that the color is "overbright" and can't be displayed accurately in the preview.
draw_texture(Control::get_icon("overbright_indicator", "ColorPresetButton"), Vector2(0, 0));
}

} break;
}
}

void ColorPresetButton::set_preset_color(const Color &p_color) {
preset_color = p_color;
}

Color ColorPresetButton::get_preset_color() const {
return preset_color;
}

ColorPresetButton::ColorPresetButton(Color p_color) {
preset_color = p_color;
}

ColorPresetButton::~ColorPresetButton() {
}
Loading