diff --git a/src/app/commands/cmd_palette_editor.cpp b/src/app/commands/cmd_palette_editor.cpp index 3ad4be05b..760c455bf 100644 --- a/src/app/commands/cmd_palette_editor.cpp +++ b/src/app/commands/cmd_palette_editor.cpp @@ -96,9 +96,7 @@ private: ButtonSet m_changeMode; HexColorEntry m_hexColorEntry; Label m_entryLabel; - RgbSliders m_rgbSliders; - HsvSliders m_hsvSliders; - HslSliders m_hslSliders; + ColorSliders m_sliders; // This variable is used to avoid updating the m_hexColorEntry text // when the color change is generated from a @@ -274,18 +272,14 @@ PaletteEntryEditor::PaletteEntryEditor() // Main vertical box m_vbox.addChild(&m_topBox); - m_vbox.addChild(&m_rgbSliders); - m_vbox.addChild(&m_hsvSliders); - m_vbox.addChild(&m_hslSliders); + m_vbox.addChild(&m_sliders); m_vbox.addChild(&m_bottomBox); addChild(&m_vbox); m_colorType.ItemChange.connect(base::Bind(&PaletteEntryEditor::onColorTypeClick, this)); m_changeMode.ItemChange.connect(base::Bind(&PaletteEntryEditor::onChangeModeClick, this)); - m_rgbSliders.ColorChange.connect(&PaletteEntryEditor::onColorSlidersChange, this); - m_hsvSliders.ColorChange.connect(&PaletteEntryEditor::onColorSlidersChange, this); - m_hslSliders.ColorChange.connect(&PaletteEntryEditor::onColorSlidersChange, this); + m_sliders.ColorChange.connect(&PaletteEntryEditor::onColorSlidersChange, this); m_hexColorEntry.ColorChange.connect(&PaletteEntryEditor::onColorHexEntryChange, this); m_changeMode.setSelectedItem(ABS_MODE); @@ -312,9 +306,7 @@ PaletteEntryEditor::PaletteEntryEditor() void PaletteEntryEditor::setColor(const app::Color& color) { - m_rgbSliders.setColor(color); - m_hsvSliders.setColor(color); - m_hslSliders.setColor(color); + m_sliders.setColor(color); if (!m_disableHexUpdate) m_hexColorEntry.setColor(color); @@ -429,7 +421,7 @@ void PaletteEntryEditor::onColorSlidersChange(ColorSlidersChangeEvent& ev) { setColor(ev.color()); - if (ev.mode() == ColorSliders::Absolute) + if (ev.mode() == ColorSliders::Mode::Absolute) setAbsolutePaletteEntryChannel(ev.channel(), ev.color()); else setRelativePaletteEntryChannel(ev.channel(), ev.delta()); @@ -471,14 +463,10 @@ void PaletteEntryEditor::onChangeModeClick() { switch (m_changeMode.selectedItem()) { case ABS_MODE: - m_rgbSliders.setMode(ColorSliders::Absolute); - m_hsvSliders.setMode(ColorSliders::Absolute); - m_hslSliders.setMode(ColorSliders::Absolute); + m_sliders.setMode(ColorSliders::Mode::Absolute); break; case REL_MODE: - m_rgbSliders.setMode(ColorSliders::Relative); - m_hsvSliders.setMode(ColorSliders::Relative); - m_hslSliders.setMode(ColorSliders::Relative); + m_sliders.setMode(ColorSliders::Mode::Relative); break; } @@ -537,15 +525,15 @@ void PaletteEntryEditor::setAbsolutePaletteEntryChannel(ColorSliders::Channel ch else { // Setup the new RGB values depending of the modified channel. switch (channel) { - case ColorSliders::Red: + case ColorSliders::Channel::Red: r = color.getRed(); - case ColorSliders::Green: + case ColorSliders::Channel::Green: g = color.getGreen(); break; - case ColorSliders::Blue: + case ColorSliders::Channel::Blue: b = color.getBlue(); break; - case ColorSliders::Alpha: + case ColorSliders::Channel::Alpha: a = color.getAlpha(); break; } @@ -569,16 +557,16 @@ void PaletteEntryEditor::setAbsolutePaletteEntryChannel(ColorSliders::Channel ch // Only modify the desired HSV channel switch (channel) { - case ColorSliders::HsvHue: + case ColorSliders::Channel::HsvHue: hsv.hue(color.getHsvHue()); break; - case ColorSliders::HsvSaturation: + case ColorSliders::Channel::HsvSaturation: hsv.saturation(color.getHsvSaturation()); break; - case ColorSliders::HsvValue: + case ColorSliders::Channel::HsvValue: hsv.value(color.getHsvValue()); break; - case ColorSliders::Alpha: + case ColorSliders::Channel::Alpha: a = color.getAlpha(); break; } @@ -609,16 +597,16 @@ void PaletteEntryEditor::setAbsolutePaletteEntryChannel(ColorSliders::Channel ch // Only modify the desired HSL channel switch (channel) { - case ColorSliders::HslHue: + case ColorSliders::Channel::HslHue: hsl.hue(color.getHslHue()); break; - case ColorSliders::HslSaturation: + case ColorSliders::Channel::HslSaturation: hsl.saturation(color.getHslSaturation()); break; - case ColorSliders::HslLightness: + case ColorSliders::Channel::HslLightness: hsl.lightness(color.getHslLightness()); break; - case ColorSliders::Alpha: + case ColorSliders::Channel::Alpha: a = color.getAlpha(); break; } @@ -664,19 +652,19 @@ void PaletteEntryEditor::setRelativePaletteEntryChannel(ColorSliders::Channel ch switch (m_type) { case app::Color::RgbType: - r = MID(0, r+m_relDeltas[ColorSliders::Red], 255); - g = MID(0, g+m_relDeltas[ColorSliders::Green], 255); - b = MID(0, b+m_relDeltas[ColorSliders::Blue], 255); - a = MID(0, a+m_relDeltas[ColorSliders::Alpha], 255); + r = MID(0, r+m_relDeltas[ColorSliders::Channel::Red], 255); + g = MID(0, g+m_relDeltas[ColorSliders::Channel::Green], 255); + b = MID(0, b+m_relDeltas[ColorSliders::Channel::Blue], 255); + a = MID(0, a+m_relDeltas[ColorSliders::Channel::Alpha], 255); break; case app::Color::HsvType: { // Convert RGB to HSV Hsv hsv(Rgb(r, g, b)); - double h = hsv.hue() +m_relDeltas[ColorSliders::HsvHue]; - double s = hsv.saturation()+m_relDeltas[ColorSliders::HsvSaturation]/100.0; - double v = hsv.value() +m_relDeltas[ColorSliders::HsvValue] /100.0; + double h = hsv.hue() +m_relDeltas[ColorSliders::Channel::HsvHue]; + double s = hsv.saturation()+m_relDeltas[ColorSliders::Channel::HsvSaturation]/100.0; + double v = hsv.value() +m_relDeltas[ColorSliders::Channel::HsvValue] /100.0; if (h < 0.0) h += 360.0; else if (h > 360.0) h -= 360.0; @@ -690,7 +678,7 @@ void PaletteEntryEditor::setRelativePaletteEntryChannel(ColorSliders::Channel ch r = rgb.red(); g = rgb.green(); b = rgb.blue(); - a = MID(0, a+m_relDeltas[ColorSliders::Alpha], 255); + a = MID(0, a+m_relDeltas[ColorSliders::Channel::Alpha], 255); break; } @@ -698,9 +686,9 @@ void PaletteEntryEditor::setRelativePaletteEntryChannel(ColorSliders::Channel ch // Convert RGB to HSL Hsl hsl(Rgb(r, g, b)); - double h = hsl.hue() +m_relDeltas[ColorSliders::HslHue]; - double s = hsl.saturation()+m_relDeltas[ColorSliders::HslSaturation]/100.0; - double l = hsl.lightness() +m_relDeltas[ColorSliders::HslLightness] /100.0; + double h = hsl.hue() +m_relDeltas[ColorSliders::Channel::HslHue]; + double s = hsl.saturation()+m_relDeltas[ColorSliders::Channel::HslSaturation]/100.0; + double l = hsl.lightness() +m_relDeltas[ColorSliders::Channel::HslLightness] /100.0; if (h < 0.0) h += 360.0; else if (h > 360.0) h -= 360.0; @@ -727,9 +715,7 @@ void PaletteEntryEditor::setRelativePaletteEntryChannel(ColorSliders::Channel ch void PaletteEntryEditor::selectColorType(app::Color::Type type) { m_type = type; - m_rgbSliders.setVisible(type == app::Color::RgbType); - m_hsvSliders.setVisible(type == app::Color::HsvType); - m_hslSliders.setVisible(type == app::Color::HslType); + m_sliders.setColorType(type); resetRelativeInfo(); @@ -822,9 +808,7 @@ void PaletteEntryEditor::onPalChange() void PaletteEntryEditor::resetRelativeInfo() { - m_rgbSliders.resetRelativeSliders(); - m_hsvSliders.resetRelativeSliders(); - m_hslSliders.resetRelativeSliders(); + m_sliders.resetRelativeSliders(); get_current_palette()->copyColorsTo(&m_fromPalette); m_relDeltas.clear(); } diff --git a/src/app/commands/filters/cmd_hue_saturation.cpp b/src/app/commands/filters/cmd_hue_saturation.cpp index c07b69197..3189a0ee8 100644 --- a/src/app/commands/filters/cmd_hue_saturation.cpp +++ b/src/app/commands/filters/cmd_hue_saturation.cpp @@ -42,23 +42,31 @@ public: , m_filter(filter) { getContainer()->addChild(&m_sliders); - m_sliders.setMode(ColorSliders::Relative); + m_sliders.setColorType(app::Color::HslType); + m_sliders.setMode(ColorSliders::Mode::Relative); m_sliders.ColorChange.connect(base::Bind(&HueSaturationWindow::onChangeControls, this)); } private: void onChangeControls() { - m_filter.setHue(double(m_sliders.getRelSliderValue(0))); - m_filter.setSaturation(m_sliders.getRelSliderValue(1) / 100.0); - m_filter.setLightness(m_sliders.getRelSliderValue(2) / 100.0); - m_filter.setAlpha(m_sliders.getRelSliderValue(3)); + m_filter.setHue( + double(m_sliders.getRelSliderValue(ColorSliders::Channel::HslHue))); + + m_filter.setSaturation( + m_sliders.getRelSliderValue(ColorSliders::Channel::HslSaturation) / 100.0); + + m_filter.setLightness( + m_sliders.getRelSliderValue(ColorSliders::Channel::HslLightness) / 100.0); + + m_filter.setAlpha( + m_sliders.getRelSliderValue(ColorSliders::Channel::Alpha)); restartPreview(); } HueSaturationFilter& m_filter; - HslSliders m_sliders; + ColorSliders m_sliders; }; class HueSaturationCommand : public Command { diff --git a/src/app/ui/button_set.cpp b/src/app/ui/button_set.cpp index 03b537bd1..9f678b8e7 100644 --- a/src/app/ui/button_set.cpp +++ b/src/app/ui/button_set.cpp @@ -162,7 +162,7 @@ bool ButtonSet::Item::onProcessMessage(ui::Message* msg) if (mnemonicPressed || (hasFocus() && keymsg->scancode() == kKeySpace)) { - buttonSet()->setSelectedItem(this); + buttonSet()->onSelectItem(this, true, msg); onClick(); } } @@ -179,7 +179,7 @@ bool ButtonSet::Item::onProcessMessage(ui::Message* msg) } captureMouse(); - buttonSet()->setSelectedItem(this); + buttonSet()->onSelectItem(this, true, msg); invalidate(); if (static_cast(msg)->left() && @@ -213,10 +213,15 @@ bool ButtonSet::Item::onProcessMessage(ui::Message* msg) // Only for ButtonSets trigerred on mouse up. if (buttonSet()->m_triggerOnMouseUp && g_itemBeforeCapture >= 0) { - // As we never received a kMouseUpMessage (so we never - // called onClick()), we have to restore the selected - // item at the point when we received the mouse capture. - buttonSet()->setSelectedItem(g_itemBeforeCapture); + if (g_itemBeforeCapture < (int)children().size()) { + Item* item = dynamic_cast(at(g_itemBeforeCapture)); + ASSERT(item); + + // As we never received a kMouseUpMessage (so we never + // called onClick()), we have to restore the selected + // item at the point when we received the mouse capture. + buttonSet()->onSelectItem(item, true, msg); + } g_itemBeforeCapture = -1; } } @@ -304,6 +309,17 @@ ButtonSet::Item* ButtonSet::getItem(int index) return dynamic_cast(at(index)); } +int ButtonSet::getItemIndex(const Item* item) const +{ + int index = 0; + for (Widget* child : children()) { + if (child == item) + return index; + ++index; + } + return -1; +} + int ButtonSet::selectedItem() const { int index = 0; @@ -324,6 +340,11 @@ void ButtonSet::setSelectedItem(int index, bool focusItem) } void ButtonSet::setSelectedItem(Item* item, bool focusItem) +{ + onSelectItem(item, focusItem, nullptr); +} + +void ButtonSet::onSelectItem(Item* item, bool focusItem, ui::Message* msg) { if (!m_multipleSelection) { if (item && item->isSelected()) diff --git a/src/app/ui/button_set.h b/src/app/ui/button_set.h index 20d0fb31f..3e92d0e65 100644 --- a/src/app/ui/button_set.h +++ b/src/app/ui/button_set.h @@ -1,5 +1,5 @@ // Aseprite -// Copyright (C) 2001-2016 David Capello +// Copyright (C) 2001-2017 David Capello // // This program is distributed under the terms of // the End-User License Agreement for Aseprite. @@ -41,8 +41,10 @@ namespace app { Item* addItem(const skin::SkinPartPtr& icon, int hspan = 1, int vspan = 1); Item* addItem(Item* item, int hspan = 1, int vspan = 1); Item* getItem(int index); + int getItemIndex(const Item* item) const; int selectedItem() const; + Item* findSelectedItem() const; void setSelectedItem(int index, bool focusItem = true); void setSelectedItem(Item* item, bool focusItem = true); void deselectItems(); @@ -57,10 +59,9 @@ namespace app { protected: virtual void onItemChange(Item* item); virtual void onRightClick(Item* item); + virtual void onSelectItem(Item* item, bool focusItem, ui::Message* msg); private: - Item* findSelectedItem() const; - bool m_offerCapture; bool m_triggerOnMouseUp; bool m_multipleSelection; diff --git a/src/app/ui/color_popup.cpp b/src/app/ui/color_popup.cpp index 7e8deeb70..d3766c902 100644 --- a/src/app/ui/color_popup.cpp +++ b/src/app/ui/color_popup.cpp @@ -116,6 +116,54 @@ public: } }; +ColorPopup::CustomButtonSet::CustomButtonSet() + : ButtonSet(COLOR_MODES) +{ +} + +int ColorPopup::CustomButtonSet::countSelectedItems() +{ + int count = 0; + for (int i=0; iisSelected()) + ++count; + return count; +} + +void ColorPopup::CustomButtonSet::onSelectItem(Item* item, bool focusItem, ui::Message* msg) +{ + int count = countSelectedItems(); + int itemIndex = getItemIndex(item); + + if (itemIndex == INDEX_MODE || + itemIndex == MASK_MODE || + !msg || + // Any key modifier will act as multiple selection + (!msg->shiftPressed() && + !msg->altPressed() && + !msg->ctrlPressed() && + !msg->cmdPressed())) { + if (item && + item->isSelected() && + count == 1) + return; + + for (int i=0; iisSelected()) + getItem(i)->setSelected(false); + } + + if (item) { + // Item already selected + if (count == 1 && item == findSelectedItem()) + return; + + item->setSelected(!item->isSelected()); + if (focusItem) + item->requestFocus(); + } +} + ColorPopup::ColorPopup(const bool canPin, bool showSimpleColors) : PopupWindowPin(" ", // Non-empty to create title-bar and close button @@ -126,7 +174,6 @@ ColorPopup::ColorPopup(const bool canPin, , m_color(app::Color::fromMask()) , m_colorPalette(false, PaletteView::SelectOneColor, this, 7*guiscale()) , m_simpleColors(nullptr) - , m_colorType(COLOR_MODES) , m_maskLabel("Transparent Color Selected") , m_canPin(canPin) , m_disableHexUpdate(false) @@ -157,10 +204,7 @@ ColorPopup::ColorPopup(const bool canPin, m_colorPaletteContainer.attachToView(&m_colorPalette); m_colorPaletteContainer.setExpansive(true); - m_rgbSliders.setExpansive(true); - m_hsvSliders.setExpansive(true); - m_hslSliders.setExpansive(true); - m_graySlider.setExpansive(true); + m_sliders.setExpansive(true); m_topBox.addChild(&m_colorType); m_topBox.addChild(new Separator("", VERTICAL)); @@ -192,19 +236,13 @@ ColorPopup::ColorPopup(const bool canPin, m_vbox.addChild(m_simpleColors); m_vbox.addChild(&m_topBox); m_vbox.addChild(&m_colorPaletteContainer); - m_vbox.addChild(&m_rgbSliders); - m_vbox.addChild(&m_hsvSliders); - m_vbox.addChild(&m_hslSliders); - m_vbox.addChild(&m_graySlider); + m_vbox.addChild(&m_sliders); m_vbox.addChild(&m_maskLabel); addChild(&m_vbox); m_colorType.ItemChange.connect(base::Bind(&ColorPopup::onColorTypeClick, this)); - m_rgbSliders.ColorChange.connect(&ColorPopup::onColorSlidersChange, this); - m_hsvSliders.ColorChange.connect(&ColorPopup::onColorSlidersChange, this); - m_hslSliders.ColorChange.connect(&ColorPopup::onColorSlidersChange, this); - m_graySlider.ColorChange.connect(&ColorPopup::onColorSlidersChange, this); + m_sliders.ColorChange.connect(&ColorPopup::onColorSlidersChange, this); m_hexColorEntry.ColorChange.connect(&ColorPopup::onColorHexEntryChange, this); // Set RGB just for the sizeHint(), and then deselect the color type @@ -244,10 +282,7 @@ void ColorPopup::setColor(const app::Color& color, SetColorOptions options) m_colorPalette.selectColor(color.getIndex()); } - m_rgbSliders.setColor(m_color); - m_hsvSliders.setColor(m_color); - m_hslSliders.setColor(m_color); - m_graySlider.setColor(m_color); + m_sliders.setColor(m_color); if (!m_disableHexUpdate) m_hexColorEntry.setColor(m_color); @@ -404,21 +439,31 @@ void ColorPopup::setColorWithSignal(const app::Color& color) void ColorPopup::selectColorType(app::Color::Type type) { m_colorPaletteContainer.setVisible(type == app::Color::IndexType); - m_rgbSliders.setVisible(type == app::Color::RgbType); - m_hsvSliders.setVisible(type == app::Color::HsvType); - m_hslSliders.setVisible(type == app::Color::HslType); - m_graySlider.setVisible(type == app::Color::GrayType); m_maskLabel.setVisible(type == app::Color::MaskType); - switch (type) { - case app::Color::IndexType: m_colorType.setSelectedItem(INDEX_MODE); break; - case app::Color::RgbType: m_colorType.setSelectedItem(RGB_MODE); break; - case app::Color::HsvType: m_colorType.setSelectedItem(HSV_MODE); break; - case app::Color::HslType: m_colorType.setSelectedItem(HSL_MODE); break; - case app::Color::GrayType: m_colorType.setSelectedItem(GRAY_MODE); break; - case app::Color::MaskType: m_colorType.setSelectedItem(MASK_MODE); break; + // Count selected items. + if (m_colorType.countSelectedItems() < 2) { + switch (type) { + case app::Color::IndexType: m_colorType.setSelectedItem(INDEX_MODE); break; + case app::Color::RgbType: m_colorType.setSelectedItem(RGB_MODE); break; + case app::Color::HsvType: m_colorType.setSelectedItem(HSV_MODE); break; + case app::Color::HslType: m_colorType.setSelectedItem(HSL_MODE); break; + case app::Color::GrayType: m_colorType.setSelectedItem(GRAY_MODE); break; + case app::Color::MaskType: m_colorType.setSelectedItem(MASK_MODE); break; + } } + std::vector types; + if (m_colorType.getItem(RGB_MODE)->isSelected()) + types.push_back(app::Color::RgbType); + if (m_colorType.getItem(HSV_MODE)->isSelected()) + types.push_back(app::Color::HsvType); + if (m_colorType.getItem(HSL_MODE)->isSelected()) + types.push_back(app::Color::HslType); + if (m_colorType.getItem(GRAY_MODE)->isSelected()) + types.push_back(app::Color::GrayType); + m_sliders.setColorTypes(types); + // Remove focus from hidden RGB/HSV/HSL text entries auto widget = manager()->getFocus(); if (widget && !widget->isVisible()) { diff --git a/src/app/ui/color_popup.h b/src/app/ui/color_popup.h index 9435e3eec..ef1266fb2 100644 --- a/src/app/ui/color_popup.h +++ b/src/app/ui/color_popup.h @@ -59,6 +59,13 @@ namespace app { void findBestfitIndex(const app::Color& color); class SimpleColors; + class CustomButtonSet : public ButtonSet { + public: + CustomButtonSet(); + int countSelectedItems(); + private: + void onSelectItem(Item* item, bool focusItem, ui::Message* msg) override; + }; ui::Box m_vbox; ui::TooltipManager m_tooltips; @@ -67,12 +74,9 @@ namespace app { ui::View m_colorPaletteContainer; PaletteView m_colorPalette; SimpleColors* m_simpleColors; - ButtonSet m_colorType; + CustomButtonSet m_colorType; HexColorEntry m_hexColorEntry; - RgbSliders m_rgbSliders; - HsvSliders m_hsvSliders; - HslSliders m_hslSliders; - GraySlider m_graySlider; + ColorSliders m_sliders; ui::Label m_maskLabel; obs::scoped_connection m_onPaletteChangeConn; bool m_canPin; diff --git a/src/app/ui/color_sliders.cpp b/src/app/ui/color_sliders.cpp index e874d0679..721ab9294 100644 --- a/src/app/ui/color_sliders.cpp +++ b/src/app/ui/color_sliders.cpp @@ -50,7 +50,7 @@ namespace { void paint(Slider* slider, Graphics* g, const gfx::Rect& rc) { // Special alpha bar (with two vertical lines) - if (m_channel == ColorSliders::Alpha) { + if (m_channel == ColorSliders::Channel::Alpha) { draw_alpha_slider(g, rc, m_color); return; } @@ -60,55 +60,55 @@ namespace { for (int x=0; x <= w; ++x) { switch (m_channel) { - case ColorSliders::Red: + case ColorSliders::Channel::Red: color = gfx::rgba(255 * x / w, m_color.getGreen(), m_color.getBlue()); break; - case ColorSliders::Green: + case ColorSliders::Channel::Green: color = gfx::rgba(m_color.getRed(), 255 * x / w, m_color.getBlue()); break; - case ColorSliders::Blue: + case ColorSliders::Channel::Blue: color = gfx::rgba(m_color.getRed(), m_color.getGreen(), 255 * x / w); break; - case ColorSliders::HsvHue: + case ColorSliders::Channel::HsvHue: color = color_utils::color_for_ui( app::Color::fromHsv(360.0 * x / w, m_color.getHsvSaturation(), m_color.getHsvValue())); break; - case ColorSliders::HsvSaturation: + case ColorSliders::Channel::HsvSaturation: color = color_utils::color_for_ui( app::Color::fromHsv(m_color.getHsvHue(), double(x) / double(w), m_color.getHsvValue())); break; - case ColorSliders::HsvValue: + case ColorSliders::Channel::HsvValue: color = color_utils::color_for_ui( app::Color::fromHsv(m_color.getHsvHue(), m_color.getHsvSaturation(), double(x) / double(w))); break; - case ColorSliders::HslHue: + case ColorSliders::Channel::HslHue: color = color_utils::color_for_ui( app::Color::fromHsl(360.0 * x / w, m_color.getHslSaturation(), m_color.getHslLightness())); break; - case ColorSliders::HslSaturation: + case ColorSliders::Channel::HslSaturation: color = color_utils::color_for_ui( app::Color::fromHsl(m_color.getHslHue(), double(x) / double(w), m_color.getHslLightness())); break; - case ColorSliders::HslLightness: + case ColorSliders::Channel::HslLightness: color = color_utils::color_for_ui( app::Color::fromHsl(m_color.getHslHue(), m_color.getHslSaturation(), double(x) / double(w))); break; - case ColorSliders::Gray: + case ColorSliders::Channel::Gray: color = color_utils::color_for_ui( app::Color::fromGray(255 * x / w)); break; @@ -227,43 +227,117 @@ namespace { ColorSliders::ColorSliders() : Widget(kGenericWidget) + , m_items(int(Channel::Channels)) , m_grid(3, false) - , m_mode(Absolute) + , m_mode(Mode::Absolute) , m_lockEntry(-1) + , m_color(app::Color::fromMask()) { addChild(&m_grid); m_grid.setChildSpacing(0); -} -ColorSliders::~ColorSliders() -{ + // Same order as in Channel enum + static_assert(Channel::Red == (Channel)0, ""); + static_assert(Channel::Alpha == (Channel)10, ""); + addSlider(Channel::Red, "R", 0, 255, -255, 255); + addSlider(Channel::Green, "G", 0, 255, -255, 255); + addSlider(Channel::Blue, "B", 0, 255, -255, 255); + addSlider(Channel::HsvHue, "H", 0, 360, -180, 180); + addSlider(Channel::HsvSaturation, "S", 0, 100, -100, 100); + addSlider(Channel::HsvValue, "V", 0, 100, -100, 100); + addSlider(Channel::HslHue, "H", 0, 360, -180, 180); + addSlider(Channel::HslSaturation, "S", 0, 100, -100, 100); + addSlider(Channel::HslLightness, "L", 0, 100, -100, 100); + addSlider(Channel::Gray, "V", 0, 255, -255, 255); + addSlider(Channel::Alpha, "A", 0, 255, -255, 255); } void ColorSliders::setColor(const app::Color& color) { + m_color = color; onSetColor(color); + updateSlidersBgColor(); +} - updateSlidersBgColor(color); +void ColorSliders::setColorType(const app::Color::Type type) +{ + std::vector types(1, type); + setColorTypes(types); +} + +void ColorSliders::setColorTypes(const std::vector& types) +{ + for (Item& item : m_items) + item.show = false; + + bool visible = false; + for (auto type : types) { + switch (type) { + case app::Color::RgbType: + m_items[Channel::Red].show = true; + m_items[Channel::Green].show = true; + m_items[Channel::Blue].show = true; + m_items[Channel::Alpha].show = true; + visible = true; + break; + case app::Color::HsvType: + m_items[Channel::HsvHue].show = true; + m_items[Channel::HsvSaturation].show = true; + m_items[Channel::HsvValue].show = true; + m_items[Channel::Alpha].show = true; + visible = true; + break; + case app::Color::HslType: + m_items[Channel::HslHue].show = true; + m_items[Channel::HslSaturation].show = true; + m_items[Channel::HslLightness].show = true; + m_items[Channel::Alpha].show = true; + visible = true; + break; + case app::Color::GrayType: + m_items[Channel::Gray].show = true; + m_items[Channel::Alpha].show = true; + visible = true; + break; + case app::Color::MaskType: + case app::Color::IndexType: + // Do nothing + break; + } + } + + setVisible(visible); + + updateSlidersVisibility(); + updateSlidersBgColor(); + layout(); } void ColorSliders::setMode(Mode mode) { m_mode = mode; - for (Slider* slider : m_absSlider) - slider->setVisible(mode == Absolute); - - for (Slider* slider : m_relSlider) - slider->setVisible(mode == Relative); - + updateSlidersVisibility(); resetRelativeSliders(); layout(); } +void ColorSliders::updateSlidersVisibility() +{ + for (auto& item : m_items) { + bool v = item.show; + item.label->setVisible(v); + item.box->setVisible(v); + item.entry->setVisible(v); + item.absSlider->setVisible(v && m_mode == Mode::Absolute); + item.relSlider->setVisible(v && m_mode == Mode::Relative); + } +} + void ColorSliders::resetRelativeSliders() { - for (Slider* slider : m_relSlider) - slider->setValue(0); + for (Item& item : m_items) + item.relSlider->setValue(0); } void ColorSliders::onSizeHint(SizeHintEvent& ev) @@ -276,112 +350,107 @@ void ColorSliders::addSlider(const Channel channel, const int absMin, const int absMax, const int relMin, const int relMax) { - Label* label = new Label(labelText); - Slider* absSlider = new Slider(absMin, absMax, 0); - Slider* relSlider = new Slider(relMin, relMax, 0); - Entry* entry = new ColorEntry(absSlider, relSlider); + Item& item = m_items[channel]; + ASSERT(!item.label); + item.label = new Label(labelText); + item.box = new HBox(); + item.absSlider = new Slider(absMin, absMax, 0); + item.relSlider = new Slider(relMin, relMax, 0); + item.entry = new ColorEntry(item.absSlider, item.relSlider); - m_label.push_back(label); - m_absSlider.push_back(absSlider); - m_relSlider.push_back(relSlider); - m_entry.push_back(entry); - m_channel.push_back(channel); + item.absSlider->setProperty(SkinSliderPropertyPtr(new SkinSliderProperty(new ColorSliderBgPainter(channel)))); + item.absSlider->setDoubleBuffered(true); + get_skin_property(item.entry)->setLook(MiniLook); - absSlider->setProperty(SkinSliderPropertyPtr(new SkinSliderProperty(new ColorSliderBgPainter(channel)))); - absSlider->setDoubleBuffered(true); - get_skin_property(entry)->setLook(MiniLook); + item.absSlider->Change.connect(base::Bind(&ColorSliders::onSliderChange, this, channel)); + item.relSlider->Change.connect(base::Bind(&ColorSliders::onSliderChange, this, channel)); + item.entry->Change.connect(base::Bind(&ColorSliders::onEntryChange, this, channel)); - absSlider->Change.connect(base::Bind(&ColorSliders::onSliderChange, this, m_absSlider.size()-1)); - relSlider->Change.connect(base::Bind(&ColorSliders::onSliderChange, this, m_relSlider.size()-1)); - entry->Change.connect(base::Bind(&ColorSliders::onEntryChange, this, m_entry.size()-1)); - - HBox* box = new HBox(); - box->addChild(absSlider); - box->addChild(relSlider); - absSlider->setFocusStop(false); - relSlider->setFocusStop(false); - absSlider->setExpansive(true); - relSlider->setExpansive(true); - relSlider->setVisible(false); + item.box->addChild(item.absSlider); + item.box->addChild(item.relSlider); + item.absSlider->setFocusStop(false); + item.relSlider->setFocusStop(false); + item.absSlider->setExpansive(true); + item.relSlider->setExpansive(true); + item.relSlider->setVisible(false); gfx::Size sz(INT_MAX, SkinTheme::instance()->dimensions.colorSliderHeight()); - label->setMaxSize(sz); - box->setMaxSize(sz); - entry->setMaxSize(sz); + item.label->setMaxSize(sz); + item.box->setMaxSize(sz); + item.entry->setMaxSize(sz); - m_grid.addChildInCell(label, 1, 1, LEFT | MIDDLE); - m_grid.addChildInCell(box, 1, 1, HORIZONTAL | VERTICAL); - m_grid.addChildInCell(entry, 1, 1, LEFT | MIDDLE); + m_grid.addChildInCell(item.label, 1, 1, LEFT | MIDDLE); + m_grid.addChildInCell(item.box, 1, 1, HORIZONTAL | VERTICAL); + m_grid.addChildInCell(item.entry, 1, 1, LEFT | MIDDLE); } -void ColorSliders::setAbsSliderValue(int sliderIndex, int value) +void ColorSliders::setAbsSliderValue(const Channel i, int value) { - m_absSlider[sliderIndex]->setValue(value); - updateEntryText(sliderIndex); + m_items[i].absSlider->setValue(value); + updateEntryText(i); } -int ColorSliders::getAbsSliderValue(int sliderIndex) const +int ColorSliders::getAbsSliderValue(const Channel i) const { - return m_absSlider[sliderIndex]->getValue(); + return m_items[i].absSlider->getValue(); } -int ColorSliders::getRelSliderValue(int sliderIndex) const +int ColorSliders::getRelSliderValue(const Channel i) const { - return m_relSlider[sliderIndex]->getValue(); + return m_items[i].relSlider->getValue(); } -void ColorSliders::onSliderChange(int i) +void ColorSliders::onSliderChange(const Channel i) { updateEntryText(i); onControlChange(i); } -void ColorSliders::onEntryChange(int i) +void ColorSliders::onEntryChange(const Channel i) { base::ScopedValue lock(m_lockEntry, i, m_lockEntry); // Update the slider related to the changed entry widget. - int value = m_entry[i]->textInt(); + int value = m_items[i].entry->textInt(); - Slider* slider = (m_mode == Absolute ? m_absSlider[i]: m_relSlider[i]); + Slider* slider = (m_mode == Mode::Absolute ? + m_items[i].absSlider: + m_items[i].relSlider); value = MID(slider->getMinValue(), value, slider->getMaxValue()); slider->setValue(value); onControlChange(i); } -void ColorSliders::onControlChange(int i) +void ColorSliders::onControlChange(const Channel i) { - // Call derived class impl of getColorFromSliders() to update the - // background color of sliders. - app::Color color = getColorFromSliders(); - - updateSlidersBgColor(color); + m_color = getColorFromSliders(i); + updateSlidersBgColor(); // Fire ColorChange() signal - ColorSlidersChangeEvent ev(m_channel[i], m_mode, - color, m_relSlider[i]->getValue(), this); + ColorSlidersChangeEvent ev(i, m_mode, m_color, + m_items[i].relSlider->getValue(), this); ColorChange(ev); } // Updates the entry related to the changed slider widget. -void ColorSliders::updateEntryText(int entryIndex) +void ColorSliders::updateEntryText(const Channel i) { - if (m_lockEntry == entryIndex) + if (m_lockEntry == i) return; - Slider* slider = (m_mode == Absolute ? m_absSlider[entryIndex]: - m_relSlider[entryIndex]); + Slider* slider = (m_mode == Mode::Absolute ? m_items[i].absSlider: + m_items[i].relSlider); - m_entry[entryIndex]->setTextf("%d", slider->getValue()); - if (m_entry[entryIndex]->hasFocus()) - m_entry[entryIndex]->selectAllText(); + m_items[i].entry->setTextf("%d", slider->getValue()); + if (m_items[i].entry->hasFocus()) + m_items[i].entry->selectAllText(); } -void ColorSliders::updateSlidersBgColor(const app::Color& color) +void ColorSliders::updateSlidersBgColor() { - for (size_t i = 0; i < m_absSlider.size(); ++i) - updateSliderBgColor(m_absSlider[i], color); + for (auto& item : m_items) + updateSliderBgColor(item.absSlider, m_color); } void ColorSliders::updateSliderBgColor(Slider* slider, const app::Color& color) @@ -393,110 +462,60 @@ void ColorSliders::updateSliderBgColor(Slider* slider, const app::Color& color) slider->invalidate(); } -////////////////////////////////////////////////////////////////////// -// RgbSliders - -RgbSliders::RgbSliders() - : ColorSliders() +void ColorSliders::onSetColor(const app::Color& color) { - addSlider(Red, "R", 0, 255, -255, 255); - addSlider(Green, "G", 0, 255, -255, 255); - addSlider(Blue, "B", 0, 255, -255, 255); - addSlider(Alpha, "A", 0, 255, -255, 255); + setAbsSliderValue(Channel::Red, color.getRed()); + setAbsSliderValue(Channel::Green, color.getGreen()); + setAbsSliderValue(Channel::Blue, color.getBlue()); + setAbsSliderValue(Channel::HsvHue, int(color.getHsvHue())); + setAbsSliderValue(Channel::HsvSaturation, int(color.getHsvSaturation() * 100.0)); + setAbsSliderValue(Channel::HsvValue, int(color.getHsvValue() * 100.0)); + setAbsSliderValue(Channel::HslHue, int(color.getHslHue())); + setAbsSliderValue(Channel::HslSaturation, int(color.getHslSaturation() * 100.0)); + setAbsSliderValue(Channel::HslLightness, int(color.getHslLightness() * 100.0)); + setAbsSliderValue(Channel::Gray, color.getGray()); + setAbsSliderValue(Channel::Alpha, color.getAlpha()); } -void RgbSliders::onSetColor(const app::Color& color) +app::Color ColorSliders::getColorFromSliders(const Channel channel) const { - setAbsSliderValue(0, color.getRed()); - setAbsSliderValue(1, color.getGreen()); - setAbsSliderValue(2, color.getBlue()); - setAbsSliderValue(3, color.getAlpha()); -} - -app::Color RgbSliders::getColorFromSliders() -{ - return app::Color::fromRgb(getAbsSliderValue(0), - getAbsSliderValue(1), - getAbsSliderValue(2), - getAbsSliderValue(3)); -} - -////////////////////////////////////////////////////////////////////// -// HsvSliders - -HsvSliders::HsvSliders() - : ColorSliders() -{ - addSlider(HsvHue, "H", 0, 360, -180, 180); - addSlider(HsvSaturation, "S", 0, 100, -100, 100); - addSlider(HsvValue, "V", 0, 100, -100, 100); - addSlider(Alpha, "A", 0, 255, -255, 255); -} - -void HsvSliders::onSetColor(const app::Color& color) -{ - setAbsSliderValue(0, int(color.getHsvHue())); - setAbsSliderValue(1, int(color.getHsvSaturation() * 100.0)); - setAbsSliderValue(2, int(color.getHsvValue() * 100.0)); - setAbsSliderValue(3, color.getAlpha()); -} - -app::Color HsvSliders::getColorFromSliders() -{ - return app::Color::fromHsv(getAbsSliderValue(0), - getAbsSliderValue(1) / 100.0, - getAbsSliderValue(2) / 100.0, - getAbsSliderValue(3)); -} - -////////////////////////////////////////////////////////////////////// -// HslSliders - -HslSliders::HslSliders() - : ColorSliders() -{ - addSlider(HslHue, "H", 0, 360, -180, 180); - addSlider(HslSaturation, "S", 0, 100, -100, 100); - addSlider(HslLightness, "L", 0, 100, -100, 100); - addSlider(Alpha, "A", 0, 255, -255, 255); -} - -void HslSliders::onSetColor(const app::Color& color) -{ - setAbsSliderValue(0, int(color.getHslHue())); - setAbsSliderValue(1, int(color.getHslSaturation() * 100.0)); - setAbsSliderValue(2, int(color.getHslLightness() * 100.0)); - setAbsSliderValue(3, color.getAlpha()); -} - -app::Color HslSliders::getColorFromSliders() -{ - return app::Color::fromHsl(getAbsSliderValue(0), - getAbsSliderValue(1) / 100.0, - getAbsSliderValue(2) / 100.0, - getAbsSliderValue(3)); -} - -////////////////////////////////////////////////////////////////////// -// GraySlider - -GraySlider::GraySlider() - : ColorSliders() -{ - addSlider(Gray, "V", 0, 255, -255, 255); - addSlider(Alpha, "A", 0, 255, -255, 255); -} - -void GraySlider::onSetColor(const app::Color& color) -{ - setAbsSliderValue(0, color.getGray()); - setAbsSliderValue(1, color.getAlpha()); -} - -app::Color GraySlider::getColorFromSliders() -{ - return app::Color::fromGray(getAbsSliderValue(0), - getAbsSliderValue(1)); + // Get the color from sliders. + switch (channel) { + case Channel::Red: + case Channel::Green: + case Channel::Blue: + return app::Color::fromRgb( + getAbsSliderValue(Channel::Red), + getAbsSliderValue(Channel::Green), + getAbsSliderValue(Channel::Blue), + getAbsSliderValue(Channel::Alpha)); + case Channel::HsvHue: + case Channel::HsvSaturation: + case Channel::HsvValue: + return app::Color::fromHsv( + getAbsSliderValue(Channel::HsvHue), + getAbsSliderValue(Channel::HsvSaturation) / 100.0, + getAbsSliderValue(Channel::HsvValue) / 100.0, + getAbsSliderValue(Channel::Alpha)); + case Channel::HslHue: + case Channel::HslSaturation: + case Channel::HslLightness: + return app::Color::fromHsl( + getAbsSliderValue(Channel::HslHue), + getAbsSliderValue(Channel::HslSaturation) / 100.0, + getAbsSliderValue(Channel::HslLightness) / 100.0, + getAbsSliderValue(Channel::Alpha)); + case Channel::Gray: + return app::Color::fromGray( + getAbsSliderValue(Channel::Gray), + getAbsSliderValue(Channel::Alpha)); + case Channel::Alpha: { + app::Color color = m_color; + color.setAlpha(getAbsSliderValue(Channel::Alpha)); + return color; + } + } + return app::Color::fromMask(); } } // namespace app diff --git a/src/app/ui/color_sliders.h b/src/app/ui/color_sliders.h index 8027f378e..3978ae494 100644 --- a/src/app/ui/color_sliders.h +++ b/src/app/ui/color_sliders.h @@ -17,6 +17,7 @@ #include namespace ui { + class Box; class Label; class Slider; class Entry; @@ -31,23 +32,25 @@ namespace app { enum Channel { Red, Green, Blue, HsvHue, HsvSaturation, HsvValue, HslHue, HslSaturation, HslLightness, - Gray, Alpha }; + Gray, Alpha, + Channels }; enum Mode { Absolute, Relative }; ColorSliders(); - ~ColorSliders(); void setColor(const app::Color& color); + void setColorType(const app::Color::Type type); + void setColorTypes(const std::vector& types); void setMode(Mode mode); void resetRelativeSliders(); - int getAbsSliderValue(int sliderIndex) const; - int getRelSliderValue(int sliderIndex) const; + int getAbsSliderValue(const Channel i) const; + int getRelSliderValue(const Channel i) const; // Signals obs::signal ColorChange; - protected: + private: void onSizeHint(ui::SizeHintEvent& ev) override; // For derived classes @@ -55,67 +58,33 @@ namespace app { const char* labelText, const int absMin, const int absMax, const int relMin, const int relMax); - void setAbsSliderValue(int sliderIndex, int value); + void setAbsSliderValue(const Channel i, int value); - virtual void onSetColor(const app::Color& color) = 0; - virtual app::Color getColorFromSliders() = 0; + void updateSlidersVisibility(); + void onSetColor(const app::Color& color); + app::Color getColorFromSliders(const Channel channel) const; + void onSliderChange(const Channel i); + void onEntryChange(const Channel i); + void onControlChange(const Channel i); - private: - void onSliderChange(int i); - void onEntryChange(int i); - void onControlChange(int i); - - void updateEntryText(int entryIndex); - void updateSlidersBgColor(const app::Color& color); + void updateEntryText(const Channel i); + void updateSlidersBgColor(); void updateSliderBgColor(ui::Slider* slider, const app::Color& color); - std::vector m_label; - std::vector m_absSlider; - std::vector m_relSlider; - std::vector m_entry; - std::vector m_channel; + struct Item { + bool show = false; + ui::Label* label = nullptr; + ui::Box* box = nullptr; + ui::Slider* absSlider = nullptr; + ui::Slider* relSlider = nullptr; + ui::Entry* entry = nullptr; + }; + + std::vector m_items; ui::Grid m_grid; Mode m_mode; int m_lockEntry; - }; - - ////////////////////////////////////////////////////////////////////// - // Derived-classes - - class RgbSliders : public ColorSliders { - public: - RgbSliders(); - - private: - virtual void onSetColor(const app::Color& color) override; - virtual app::Color getColorFromSliders() override; - }; - - class HsvSliders : public ColorSliders { - public: - HsvSliders(); - - private: - virtual void onSetColor(const app::Color& color) override; - virtual app::Color getColorFromSliders() override; - }; - - class HslSliders : public ColorSliders { - public: - HslSliders(); - - private: - virtual void onSetColor(const app::Color& color) override; - virtual app::Color getColorFromSliders() override; - }; - - class GraySlider : public ColorSliders { - public: - GraySlider(); - - private: - virtual void onSetColor(const app::Color& color) override; - virtual app::Color getColorFromSliders() override; + app::Color m_color; }; //////////////////////////////////////////////////////////////////////