From 525e473fb5369712fe7da9f5b2f618029bd7a91b Mon Sep 17 00:00:00 2001 From: David Capello Date: Sun, 10 May 2015 22:53:36 -0300 Subject: [PATCH] Add relative mode in Palette Editor --- src/app/commands/cmd_palette_editor.cpp | 234 ++++++++++++++++++------ src/app/ui/color_selector.cpp | 4 +- src/app/ui/color_sliders.cpp | 112 ++++++++---- src/app/ui/color_sliders.h | 46 +++-- 4 files changed, 279 insertions(+), 117 deletions(-) diff --git a/src/app/commands/cmd_palette_editor.cpp b/src/app/commands/cmd_palette_editor.cpp index 67dca1ba9..b5d0e5bfc 100644 --- a/src/app/commands/cmd_palette_editor.cpp +++ b/src/app/commands/cmd_palette_editor.cpp @@ -72,16 +72,21 @@ protected: void onColorSlidersChange(ColorSlidersChangeEvent& ev); void onColorHexEntryChange(const app::Color& color); void onColorTypeButtonClick(Event& ev); + void onAbsoluteButtonClick(Event& ev); + void onRelativeButtonClick(Event& ev); private: void selectColorType(app::Color::Type type); void setPaletteEntry(const app::Color& color); - void setPaletteEntryChannel(const app::Color& color, ColorSliders::Channel channel); + void setAbsolutePaletteEntryChannel(ColorSliders::Channel channel, const app::Color& color); + void setRelativePaletteEntryChannel(ColorSliders::Channel channel, int delta); void setNewPalette(Palette* palette, const char* operationName); void updateCurrentSpritePalette(const char* operationName); void updateColorBar(); void onPalChange(); + void resetRelativeInfo(); + app::Color::Type m_type; Box m_vbox; Box m_topBox; Box m_bottomBox; @@ -89,6 +94,8 @@ private: RadioButton m_hsvButton; HexColorEntry m_hexColorEntry; Label m_entryLabel; + RadioButton m_absButton; + RadioButton m_relButton; RgbSliders m_rgbSliders; HsvSliders m_hsvSliders; @@ -111,6 +118,10 @@ private: bool m_selfPalChange; ScopedConnection m_palChangeConn; + + // Palette used for relative changes. + Palette m_fromPalette; + std::map m_relDeltas; }; static PaletteEntryEditor* g_window = NULL; @@ -227,17 +238,21 @@ bool PaletteEditorCommand::onChecked(Context* context) PaletteEntryEditor::PaletteEntryEditor() : Window(WithTitleBar, "Palette Editor (F4)") + , m_type(app::Color::MaskType) , m_vbox(JI_VERTICAL) , m_topBox(JI_HORIZONTAL) , m_bottomBox(JI_HORIZONTAL) , m_rgbButton("RGB", 1, kButtonWidget) , m_hsvButton("HSB", 1, kButtonWidget) , m_entryLabel("") + , m_absButton("Abs", 2, kButtonWidget) + , m_relButton("Rel", 2, kButtonWidget) , m_disableHexUpdate(false) , m_redrawTimer(250, this) , m_redrawAll(false) , m_implantChange(false) , m_selfPalChange(false) + , m_fromPalette(0, Palette::MaxColors) { m_topBox.setBorder(gfx::Border(0)); m_topBox.child_spacing = 0; @@ -245,12 +260,17 @@ PaletteEntryEditor::PaletteEntryEditor() setup_mini_look(&m_rgbButton); setup_mini_look(&m_hsvButton); + setup_mini_look(&m_absButton); + setup_mini_look(&m_relButton); // Top box m_topBox.addChild(&m_rgbButton); m_topBox.addChild(&m_hsvButton); m_topBox.addChild(&m_hexColorEntry); m_topBox.addChild(&m_entryLabel); + m_topBox.addChild(new BoxFiller); + m_topBox.addChild(&m_absButton); + m_topBox.addChild(&m_relButton); // Main vertical box m_vbox.addChild(&m_topBox); @@ -261,11 +281,14 @@ PaletteEntryEditor::PaletteEntryEditor() m_rgbButton.Click.connect(&PaletteEntryEditor::onColorTypeButtonClick, this); m_hsvButton.Click.connect(&PaletteEntryEditor::onColorTypeButtonClick, this); + m_absButton.Click.connect(&PaletteEntryEditor::onAbsoluteButtonClick, this); + m_relButton.Click.connect(&PaletteEntryEditor::onRelativeButtonClick, this); m_rgbSliders.ColorChange.connect(&PaletteEntryEditor::onColorSlidersChange, this); m_hsvSliders.ColorChange.connect(&PaletteEntryEditor::onColorSlidersChange, this); m_hexColorEntry.ColorChange.connect(&PaletteEntryEditor::onColorHexEntryChange, this); + m_absButton.setSelected(true); selectColorType(app::Color::RgbType); // We hook fg/bg color changes (by eyedropper mainly) to update the selected entry color @@ -382,13 +405,19 @@ void PaletteEntryEditor::onFgBgColorChange(const app::Color& color) { if (color.isValid() && color.getType() == app::Color::IndexType) { setColor(color); + resetRelativeInfo(); } } void PaletteEntryEditor::onColorSlidersChange(ColorSlidersChangeEvent& ev) { - setColor(ev.getColor()); - setPaletteEntryChannel(ev.getColor(), ev.getModifiedChannel()); + setColor(ev.color()); + + if (ev.mode() == ColorSliders::Absolute) + setAbsolutePaletteEntryChannel(ev.channel(), ev.color()); + else + setRelativePaletteEntryChannel(ev.channel(), ev.delta()); + updateCurrentSpritePalette("Color Change"); updateColorBar(); } @@ -415,6 +444,19 @@ void PaletteEntryEditor::onColorTypeButtonClick(Event& ev) else if (source == &m_hsvButton) selectColorType(app::Color::HsvType); } +void PaletteEntryEditor::onAbsoluteButtonClick(Event& ev) +{ + m_rgbSliders.setMode(ColorSliders::Absolute); + m_hsvSliders.setMode(ColorSliders::Absolute); +} + +void PaletteEntryEditor::onRelativeButtonClick(Event& ev) +{ + m_rgbSliders.setMode(ColorSliders::Relative); + m_hsvSliders.setMode(ColorSliders::Relative); + resetRelativeInfo(); +} + void PaletteEntryEditor::setPaletteEntry(const app::Color& color) { PaletteView* palView = ColorBar::instance()->getPaletteView(); @@ -422,8 +464,8 @@ void PaletteEntryEditor::setPaletteEntry(const app::Color& color) palView->getSelectedEntries(entries); color_t new_pal_color = doc::rgba(color.getRed(), - color.getGreen(), - color.getBlue(), 255); + color.getGreen(), + color.getBlue(), 255); Palette* palette = get_current_palette(); for (int c=0; csize(); c++) { @@ -432,7 +474,7 @@ void PaletteEntryEditor::setPaletteEntry(const app::Color& color) } } -void PaletteEntryEditor::setPaletteEntryChannel(const app::Color& color, ColorSliders::Channel channel) +void PaletteEntryEditor::setAbsolutePaletteEntryChannel(ColorSliders::Channel channel, const app::Color& color) { PaletteView* palView = ColorBar::instance()->getPaletteView(); PalettePicks entries; @@ -447,86 +489,150 @@ void PaletteEntryEditor::setPaletteEntryChannel(const app::Color& color, ColorSl Palette* palette = get_current_palette(); for (int c=0; csize(); c++) { - if (entries[c]) { - // Get the current RGB values of the palette entry - src_color = palette->getEntry(c); - r = rgba_getr(src_color); - g = rgba_getg(src_color); - b = rgba_getb(src_color); + if (!entries[c]) + continue; - switch (color.getType()) { + // Get the current RGB values of the palette entry + src_color = palette->getEntry(c); + r = rgba_getr(src_color); + g = rgba_getg(src_color); + b = rgba_getb(src_color); + + switch (m_type) { + + case app::Color::RgbType: + // Modify one entry + if (begSel == endSel) { + r = color.getRed(); + g = color.getGreen(); + b = color.getBlue(); + } + // Modify one channel a set of entries + else { + // Setup the new RGB values depending of the modified channel. + switch (channel) { + case ColorSliders::Red: + r = color.getRed(); + case ColorSliders::Green: + g = color.getGreen(); + break; + case ColorSliders::Blue: + b = color.getBlue(); + break; + } + } + break; + + case app::Color::HsvType: + { + Hsv hsv; - case app::Color::RgbType: // Modify one entry if (begSel == endSel) { - r = color.getRed(); - g = color.getGreen(); - b = color.getBlue(); + hsv.hue(color.getHue()); + hsv.saturation(double(color.getSaturation()) / 100.0); + hsv.value(double(color.getValue()) / 100.0); } // Modify one channel a set of entries else { - // Setup the new RGB values depending of the modified channel. + // Convert RGB to HSV + hsv = Hsv(Rgb(r, g, b)); + + // Only modify the desired HSV channel switch (channel) { - case ColorSliders::Red: - r = color.getRed(); - case ColorSliders::Green: - g = color.getGreen(); + case ColorSliders::Hue: + hsv.hue(color.getHue()); break; - case ColorSliders::Blue: - b = color.getBlue(); + case ColorSliders::Saturation: + hsv.saturation(double(color.getSaturation()) / 100.0); + break; + case ColorSliders::Value: + hsv.value(double(color.getValue()) / 100.0); break; } } - break; - case app::Color::HsvType: - { - Hsv hsv; + // Convert HSV back to RGB + Rgb rgb(hsv); + r = rgb.red(); + g = rgb.green(); + b = rgb.blue(); + } + break; + } - // Modify one entry - if (begSel == endSel) { - hsv.hue(color.getHue()); - hsv.saturation(double(color.getSaturation()) / 100.0); - hsv.value(double(color.getValue()) / 100.0); - } - // Modify one channel a set of entries - else { - // Convert RGB to HSV - hsv = Hsv(Rgb(r, g, b)); + palette->setEntry(c, doc::rgba(r, g, b, 255)); + } +} - // Only modify the desired HSV channel - switch (channel) { - case ColorSliders::Hue: - hsv.hue(color.getHue()); - break; - case ColorSliders::Saturation: - hsv.saturation(double(color.getSaturation()) / 100.0); - break; - case ColorSliders::Value: - hsv.value(double(color.getValue()) / 100.0); - break; - } - } +void PaletteEntryEditor::setRelativePaletteEntryChannel(ColorSliders::Channel channel, int delta) +{ + PaletteView* palView = ColorBar::instance()->getPaletteView(); + PalettePicks entries; + palView->getSelectedEntries(entries); - // Convert HSV back to RGB - Rgb rgb(hsv); - r = rgb.red(); - g = rgb.green(); - b = rgb.blue(); - } - break; + // Update modified delta + m_relDeltas[channel] = delta; + + uint32_t src_color; + int r, g, b; + + Palette* palette = get_current_palette(); + for (int c=0; csize(); c++) { + if (!entries[c]) + continue; + + // Get the current RGB values of the palette entry + src_color = m_fromPalette.getEntry(c); + r = rgba_getr(src_color); + g = rgba_getg(src_color); + b = rgba_getb(src_color); + + 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); + break; + + case app::Color::HsvType: { + // Convert RGB to HSV + Hsv hsv(Rgb(r, g, b)); + + double h = hsv.hue()+m_relDeltas[ColorSliders::Hue]; + double s = 100.0*hsv.saturation()+m_relDeltas[ColorSliders::Saturation]; + double v = 100.0*hsv.value()+m_relDeltas[ColorSliders::Value]; + + if (h < 0.0) h += 360.0; + else if (h > 360.0) h -= 360.0; + + hsv.hue (MID(0.0, h, 360.0)); + hsv.saturation(MID(0.0, s, 100.0) / 100.0); + hsv.value (MID(0.0, v, 100.0) / 100.0); + + // Convert HSV back to RGB + Rgb rgb(hsv); + r = rgb.red(); + g = rgb.green(); + b = rgb.blue(); + break; } - palette->setEntry(c, doc::rgba(r, g, b, 255)); } + + palette->setEntry(c, doc::rgba(r, g, b, 255)); } } void PaletteEntryEditor::selectColorType(app::Color::Type type) { + m_type = type; m_rgbSliders.setVisible(type == app::Color::RgbType); m_hsvSliders.setVisible(type == app::Color::HsvType); + resetRelativeInfo(); + switch (type) { case app::Color::RgbType: m_rgbButton.setSelected(true); break; case app::Color::HsvType: m_hsvButton.setSelected(true); break; @@ -602,11 +708,21 @@ void PaletteEntryEditor::onPalChange() if (index >= 0) setColor(app::Color::fromIndex(index)); + resetRelativeInfo(); + // Redraw the window invalidate(); } } +void PaletteEntryEditor::resetRelativeInfo() +{ + m_rgbSliders.resetRelativeSliders(); + m_hsvSliders.resetRelativeSliders(); + get_current_palette()->copyColorsTo(&m_fromPalette); + m_relDeltas.clear(); +} + Command* CommandFactory::createPaletteEditorCommand() { return new PaletteEditorCommand; diff --git a/src/app/ui/color_selector.cpp b/src/app/ui/color_selector.cpp index 1fd1cd445..e57256cdf 100644 --- a/src/app/ui/color_selector.cpp +++ b/src/app/ui/color_selector.cpp @@ -166,8 +166,8 @@ void ColorSelector::onPaletteViewIndexChange(int index, ui::MouseButtons buttons void ColorSelector::onColorSlidersChange(ColorSlidersChangeEvent& ev) { - setColorWithSignal(ev.getColor()); - findBestfitIndex(ev.getColor()); + setColorWithSignal(ev.color()); + findBestfitIndex(ev.color()); } void ColorSelector::onColorHexEntryChange(const app::Color& color) diff --git a/src/app/ui/color_sliders.cpp b/src/app/ui/color_sliders.cpp index f24418eb4..06dab39f8 100644 --- a/src/app/ui/color_sliders.cpp +++ b/src/app/ui/color_sliders.cpp @@ -83,6 +83,7 @@ namespace { ColorSliders::ColorSliders() : Widget(kGenericWidget) , m_grid(3, false) + , m_mode(Absolute) { addChild(&m_grid); } @@ -98,46 +99,77 @@ void ColorSliders::setColor(const app::Color& color) updateSlidersBgColor(color); } -void ColorSliders:: onPreferredSize(PreferredSizeEvent& ev) +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); + + resetRelativeSliders(); + layout(); +} + +void ColorSliders::resetRelativeSliders() +{ + for (Slider* slider : m_relSlider) + slider->setValue(0); +} + +void ColorSliders::onPreferredSize(PreferredSizeEvent& ev) { ev.setPreferredSize(m_grid.getPreferredSize()); } void ColorSliders::addSlider(Channel channel, const char* labelText, int min, int max) { - Label* label = new Label(labelText); - Slider* slider = new Slider(min, max, 0); - Entry* entry = new Entry(3, "0"); + Label* label = new Label(labelText); + Slider* absSlider = new Slider(min, max, 0); + Slider* relSlider = new Slider(min-max, max-min, 0); + Entry* entry = new Entry(4, "0"); m_label.push_back(label); - m_slider.push_back(slider); + m_absSlider.push_back(absSlider); + m_relSlider.push_back(relSlider); m_entry.push_back(entry); m_channel.push_back(channel); - slider->setProperty(SkinSliderPropertyPtr(new SkinSliderProperty(new ColorSliderBgPainter(channel)))); - slider->setDoubleBuffered(true); + absSlider->setProperty(SkinSliderPropertyPtr(new SkinSliderProperty(new ColorSliderBgPainter(channel)))); + absSlider->setDoubleBuffered(true); - slider->Change.connect(Bind(&ColorSliders::onSliderChange, this, m_slider.size()-1)); + absSlider->Change.connect(Bind(&ColorSliders::onSliderChange, this, m_absSlider.size()-1)); + relSlider->Change.connect(Bind(&ColorSliders::onSliderChange, this, m_relSlider.size()-1)); entry->EntryChange.connect(Bind(&ColorSliders::onEntryChange, this, m_entry.size()-1)); + HBox* box = new HBox(); + box->addChild(absSlider); + box->addChild(relSlider); + absSlider->setExpansive(true); + relSlider->setExpansive(true); + relSlider->setVisible(false); + m_grid.addChildInCell(label, 1, 1, JI_LEFT | JI_MIDDLE); - m_grid.addChildInCell(slider, 1, 1, JI_HORIZONTAL | JI_VERTICAL | JI_EXPANSIVE); + m_grid.addChildInCell(box, 1, 1, JI_HORIZONTAL | JI_VERTICAL | JI_EXPANSIVE); m_grid.addChildInCell(entry, 1, 1, JI_LEFT | JI_MIDDLE); } -void ColorSliders::setSliderValue(int sliderIndex, int value) +void ColorSliders::setAbsSliderValue(int sliderIndex, int value) { - Slider* slider = m_slider[sliderIndex]; - slider->setValue(value); - + m_absSlider[sliderIndex]->setValue(value); updateEntryText(sliderIndex); } -int ColorSliders::getSliderValue(int sliderIndex) const +int ColorSliders::getAbsSliderValue(int sliderIndex) const { - Slider* slider = m_slider[sliderIndex]; + return m_absSlider[sliderIndex]->getValue(); +} - return slider->getValue(); +int ColorSliders::getRelSliderValue(int sliderIndex) const +{ + return m_relSlider[sliderIndex]->getValue(); } void ColorSliders::onSliderChange(int i) @@ -151,11 +183,9 @@ void ColorSliders::onEntryChange(int i) // Update the slider related to the changed entry widget. int value = m_entry[i]->getTextInt(); - value = MID(m_slider[i]->getMinValue(), - value, - m_slider[i]->getMaxValue()); - - m_slider[i]->setValue(value); + Slider* slider = (m_mode == Absolute ? m_absSlider[i]: m_relSlider[i]); + value = MID(slider->getMinValue(), value, slider->getMaxValue()); + slider->setValue(value); onControlChange(i); } @@ -169,20 +199,24 @@ void ColorSliders::onControlChange(int i) updateSlidersBgColor(color); // Fire ColorChange() signal - ColorSlidersChangeEvent ev(color, m_channel[i], this); + ColorSlidersChangeEvent ev(m_channel[i], m_mode, + color, m_relSlider[i]->getValue(), this); ColorChange(ev); } // Updates the entry related to the changed slider widget. void ColorSliders::updateEntryText(int entryIndex) { - m_entry[entryIndex]->setTextf("%d", m_slider[entryIndex]->getValue()); + Slider* slider = (m_mode == Absolute ? m_absSlider[entryIndex]: + m_relSlider[entryIndex]); + + m_entry[entryIndex]->setTextf("%d", slider->getValue()); } void ColorSliders::updateSlidersBgColor(const app::Color& color) { - for (size_t i = 0; i < m_slider.size(); ++i) - updateSliderBgColor(m_slider[i], color); + for (size_t i = 0; i < m_absSlider.size(); ++i) + updateSliderBgColor(m_absSlider[i], color); } void ColorSliders::updateSliderBgColor(Slider* slider, const app::Color& color) @@ -207,16 +241,16 @@ RgbSliders::RgbSliders() void RgbSliders::onSetColor(const app::Color& color) { - setSliderValue(0, color.getRed()); - setSliderValue(1, color.getGreen()); - setSliderValue(2, color.getBlue()); + setAbsSliderValue(0, color.getRed()); + setAbsSliderValue(1, color.getGreen()); + setAbsSliderValue(2, color.getBlue()); } app::Color RgbSliders::getColorFromSliders() { - return app::Color::fromRgb(getSliderValue(0), - getSliderValue(1), - getSliderValue(2)); + return app::Color::fromRgb(getAbsSliderValue(0), + getAbsSliderValue(1), + getAbsSliderValue(2)); } ////////////////////////////////////////////////////////////////////// @@ -232,16 +266,16 @@ HsvSliders::HsvSliders() void HsvSliders::onSetColor(const app::Color& color) { - setSliderValue(0, color.getHue()); - setSliderValue(1, color.getSaturation()); - setSliderValue(2, color.getValue()); + setAbsSliderValue(0, color.getHue()); + setAbsSliderValue(1, color.getSaturation()); + setAbsSliderValue(2, color.getValue()); } app::Color HsvSliders::getColorFromSliders() { - return app::Color::fromHsv(getSliderValue(0), - getSliderValue(1), - getSliderValue(2)); + return app::Color::fromHsv(getAbsSliderValue(0), + getAbsSliderValue(1), + getAbsSliderValue(2)); } ////////////////////////////////////////////////////////////////////// @@ -255,13 +289,13 @@ GraySlider::GraySlider() void GraySlider::onSetColor(const app::Color& color) { - setSliderValue(0, color.getGray()); + setAbsSliderValue(0, color.getGray()); } app::Color GraySlider::getColorFromSliders() { - return app::Color::fromGray(getSliderValue(0)); + return app::Color::fromGray(getAbsSliderValue(0)); } } // namespace app diff --git a/src/app/ui/color_sliders.h b/src/app/ui/color_sliders.h index 5af95a4d5..c60817df8 100644 --- a/src/app/ui/color_sliders.h +++ b/src/app/ui/color_sliders.h @@ -32,11 +32,14 @@ namespace app { enum Channel { Red, Green, Blue, Hue, Saturation, Value, Gray }; + enum Mode { Absolute, Relative }; ColorSliders(); ~ColorSliders(); void setColor(const app::Color& color); + void setMode(Mode mode); + void resetRelativeSliders(); // Signals Signal1 ColorChange; @@ -46,8 +49,9 @@ namespace app { // For derived classes void addSlider(Channel channel, const char* labelText, int min, int max); - void setSliderValue(int sliderIndex, int value); - int getSliderValue(int sliderIndex) const; + void setAbsSliderValue(int sliderIndex, int value); + int getAbsSliderValue(int sliderIndex) const; + int getRelSliderValue(int sliderIndex) const; virtual void onSetColor(const app::Color& color) = 0; virtual app::Color getColorFromSliders() = 0; @@ -62,17 +66,18 @@ namespace app { void updateSliderBgColor(ui::Slider* slider, const app::Color& color); std::vector m_label; - std::vector m_slider; + std::vector m_absSlider; + std::vector m_relSlider; std::vector m_entry; std::vector m_channel; ui::Grid m_grid; + Mode m_mode; }; ////////////////////////////////////////////////////////////////////// // Derived-classes - class RgbSliders : public ColorSliders - { + class RgbSliders : public ColorSliders { public: RgbSliders(); @@ -81,8 +86,7 @@ namespace app { virtual app::Color getColorFromSliders() override; }; - class HsvSliders : public ColorSliders - { + class HsvSliders : public ColorSliders { public: HsvSliders(); @@ -91,8 +95,7 @@ namespace app { virtual app::Color getColorFromSliders() override; }; - class GraySlider : public ColorSliders - { + class GraySlider : public ColorSliders { public: GraySlider(); @@ -104,21 +107,30 @@ namespace app { ////////////////////////////////////////////////////////////////////// // Events - class ColorSlidersChangeEvent : public ui::Event - { + class ColorSlidersChangeEvent : public ui::Event { public: - ColorSlidersChangeEvent(const app::Color& color, ColorSliders::Channel channel, ui::Component* source) + ColorSlidersChangeEvent(ColorSliders::Channel channel, + ColorSliders::Mode mode, + const app::Color& color, + int delta, + ui::Component* source) : Event(source) + , m_channel(channel) + , m_mode(mode) , m_color(color) - , m_channel(channel) { } + , m_delta(delta) { + } - app::Color getColor() const { return m_color; } - - ColorSliders::Channel getModifiedChannel() const { return m_channel; } + ColorSliders::Channel channel() const { return m_channel; } + ColorSliders::Mode mode() const { return m_mode; } + app::Color color() const { return m_color; } + int delta() const { return m_delta; } private: - app::Color m_color; ColorSliders::Channel m_channel; + ColorSliders::Mode m_mode; + app::Color m_color; + int m_delta; }; } // namespace app