diff --git a/data/extensions/aseprite-theme/theme.xml b/data/extensions/aseprite-theme/theme.xml index e78dd19e2..722dab115 100644 --- a/data/extensions/aseprite-theme/theme.xml +++ b/data/extensions/aseprite-theme/theme.xml @@ -518,6 +518,7 @@ diff --git a/src/app/color.cpp b/src/app/color.cpp index cbd42ad1e..9922dd7b9 100644 --- a/src/app/color.cpp +++ b/src/app/color.cpp @@ -1,5 +1,5 @@ // Aseprite -// Copyright (C) 2001-2017 David Capello +// Copyright (C) 2001-2018 David Capello // // This program is distributed under the terms of // the End-User License Agreement for Aseprite. @@ -173,6 +173,11 @@ Color Color::fromString(const std::string& str) return color; } +Color Color::toRgb() const +{ + return Color::fromRgb(getRed(), getGreen(), getBlue(), getAlpha()); +} + std::string Color::toString() const { std::stringstream result; diff --git a/src/app/color.h b/src/app/color.h index be57a32fe..705363871 100644 --- a/src/app/color.h +++ b/src/app/color.h @@ -1,5 +1,5 @@ // Aseprite -// Copyright (C) 2001-2017 David Capello +// Copyright (C) 2001-2018 David Capello // // This program is distributed under the terms of // the End-User License Agreement for Aseprite. @@ -52,6 +52,7 @@ namespace app { static Color fromImageGetPixel(Image* image, int x, int y); static Color fromString(const std::string& str); + Color toRgb() const; std::string toString() const; std::string toHumanReadableString(PixelFormat format, HumanReadableString type) const; diff --git a/src/app/ui/color_popup.cpp b/src/app/ui/color_popup.cpp index ec54a40ca..7450e1e9c 100644 --- a/src/app/ui/color_popup.cpp +++ b/src/app/ui/color_popup.cpp @@ -187,8 +187,10 @@ ColorPopup::ColorPopup(const ColorButtonOptions& options) new PaletteView(false, PaletteView::SelectOneColor, this, 7*guiscale()): nullptr) , m_simpleColors(nullptr) + , m_oldAndNew(Shade(2), ColorShades::ClickEntries) , m_maskLabel("Transparent Color Selected") , m_canPin(options.canPinSelector) + , m_insideChange(false) , m_disableHexUpdate(false) { if (options.showSimpleColors) { @@ -226,6 +228,7 @@ ColorPopup::ColorPopup(const ColorButtonOptions& options) m_topBox.addChild(&m_colorType); m_topBox.addChild(new Separator("", VERTICAL)); m_topBox.addChild(&m_hexColorEntry); + m_topBox.addChild(&m_oldAndNew); // TODO fix this hack for close button in popup window // Move close button (decorative widget) inside the m_topBox @@ -261,6 +264,7 @@ ColorPopup::ColorPopup(const ColorButtonOptions& options) m_sliders.ColorChange.connect(&ColorPopup::onColorSlidersChange, this); m_hexColorEntry.ColorChange.connect(&ColorPopup::onColorHexEntryChange, this); + m_oldAndNew.Click.connect(&ColorPopup::onSelectOldColor, this); // Set RGB just for the sizeHint(), and then deselect the color type // (the first setColor() call will setup it correctly.) @@ -311,6 +315,14 @@ void ColorPopup::setColor(const app::Color& color, if (options == ChangeType) selectColorType(m_color.getType()); + + // Set the new color + Shade shade = m_oldAndNew.getShade(); + shade.resize(2); + shade[1] = (color.getType() == app::Color::IndexType ? color.toRgb(): color); + if (!m_insideChange) + shade[0] = shade[1]; + m_oldAndNew.setShade(shade); } app::Color ColorPopup::getColor() const @@ -370,17 +382,26 @@ void ColorPopup::onMakeFixed() void ColorPopup::onPaletteViewIndexChange(int index, ui::MouseButtons buttons) { + base::ScopedValue restore(m_insideChange, true, + m_insideChange); + setColorWithSignal(app::Color::fromIndex(index), ChangeType); } void ColorPopup::onColorSlidersChange(ColorSlidersChangeEvent& ev) { + base::ScopedValue restore(m_insideChange, true, + m_insideChange); + setColorWithSignal(ev.color(), DontChangeType); findBestfitIndex(ev.color()); } void ColorPopup::onColorHexEntryChange(const app::Color& color) { + base::ScopedValue restore(m_insideChange, true, + m_insideChange); + // Disable updating the hex entry so we don't override what the user // is writting in the text field. m_disableHexUpdate = true; @@ -396,6 +417,16 @@ void ColorPopup::onColorHexEntryChange(const app::Color& color) m_disableHexUpdate = false; } +void ColorPopup::onSelectOldColor() +{ + Shade shade = m_oldAndNew.getShade(); + int hot = m_oldAndNew.getHotEntry(); + if (hot >= 0 && + hot < int(shade.size())) { + setColorWithSignal(shade[hot], DontChangeType); + } +} + void ColorPopup::onSimpleColorClick() { m_colorType.deselectItems(); @@ -425,6 +456,9 @@ void ColorPopup::onSimpleColorClick() void ColorPopup::onColorTypeClick() { + base::ScopedValue restore(m_insideChange, true, + m_insideChange); + if (m_simpleColors) m_simpleColors->deselect(); @@ -466,6 +500,9 @@ void ColorPopup::onColorTypeClick() void ColorPopup::onPaletteChange() { + base::ScopedValue restore(m_insideChange, inEditMode(), + m_insideChange); + setColor(getColor(), DontChangeType); invalidate(); @@ -495,8 +532,14 @@ void ColorPopup::findBestfitIndex(const app::Color& color) void ColorPopup::setColorWithSignal(const app::Color& color, const SetColorOptions options) { + Shade shade = m_oldAndNew.getShade(); + setColor(color, options); + shade.resize(2); + shade[1] = color; + m_oldAndNew.setShade(shade); + // Fire ColorChange signal ColorChange(color); } diff --git a/src/app/ui/color_popup.h b/src/app/ui/color_popup.h index 0e7e2af9b..c3bca521f 100644 --- a/src/app/ui/color_popup.h +++ b/src/app/ui/color_popup.h @@ -9,8 +9,10 @@ #pragma once #include "app/color.h" +#include "app/shade.h" #include "app/ui/button_set.h" #include "app/ui/color_button_options.h" +#include "app/ui/color_shades.h" #include "app/ui/color_sliders.h" #include "app/ui/hex_color_entry.h" #include "app/ui/palette_view.h" @@ -50,6 +52,7 @@ namespace app { void onMakeFixed() override; void onColorSlidersChange(ColorSlidersChangeEvent& ev); void onColorHexEntryChange(const app::Color& color); + void onSelectOldColor(); void onSimpleColorClick(); void onColorTypeClick(); void onPaletteChange(); @@ -83,10 +86,12 @@ namespace app { SimpleColors* m_simpleColors; CustomButtonSet m_colorType; HexColorEntry m_hexColorEntry; + ColorShades m_oldAndNew; ColorSliders m_sliders; ui::Label m_maskLabel; obs::scoped_connection m_onPaletteChangeConn; bool m_canPin; + bool m_insideChange; // This variable is used to avoid updating the m_hexColorEntry text // when the color change is generated from a diff --git a/src/app/ui/color_shades.cpp b/src/app/ui/color_shades.cpp index 14318ab3b..2af28ac81 100644 --- a/src/app/ui/color_shades.cpp +++ b/src/app/ui/color_shades.cpp @@ -81,7 +81,7 @@ int ColorShades::size() const for (const auto& color : m_shade) { if ((color.getIndex() >= 0 && color.getIndex() < get_current_palette()->size()) || - (m_click == Select)) { + (m_click == ClickWholeShade)) { ++colors; } } @@ -94,9 +94,11 @@ Shade ColorShades::getShade() const for (const auto& color : m_shade) { if ((color.getIndex() >= 0 && color.getIndex() < get_current_palette()->size()) || - (m_click == Select)) { + (m_click == ClickWholeShade)) { colors.push_back(color); } + else if (m_click == ClickEntries) + colors.push_back(color); } return colors; } @@ -123,7 +125,18 @@ void ColorShades::updateShadeFromColorBarPicks() void ColorShades::onInitTheme(ui::InitThemeEvent& ev) { Widget::onInitTheme(ev); - setStyle(skin::SkinTheme::instance()->styles.menuShadeView()); + + auto theme = skin::SkinTheme::instance(); + + switch (m_click) { + case ClickEntries: + case DragAndDropEntries: + setStyle(theme->styles.normalShadeView()); + break; + case ClickWholeShade: + setStyle(theme->styles.menuShadeView()); + break; + } } bool ColorShades::onProcessMessage(ui::Message* msg) @@ -131,7 +144,8 @@ bool ColorShades::onProcessMessage(ui::Message* msg) switch (msg->type()) { case ui::kOpenMessage: - if (m_click == DragAndDrop) { + if (m_click == DragAndDropEntries) { + // TODO This connection should be in the ContextBar m_conn = ColorBar::instance()->ChangeSelection.connect( base::Bind(&ColorShades::onChangeColorBarSelection, this)); } @@ -142,27 +156,42 @@ bool ColorShades::onProcessMessage(ui::Message* msg) ui::set_mouse_cursor(ui::kMoveCursor); return true; } + else if (m_click == ClickEntries && + m_hotIndex >= 0 && + m_hotIndex < int(m_shade.size())) { + ui::set_mouse_cursor(ui::kHandCursor); + return true; + } break; case ui::kMouseEnterMessage: case ui::kMouseLeaveMessage: + if (!hasCapture()) + m_hotIndex = -1; + invalidate(); break; - case ui::kMouseDownMessage: { - if (m_click == DragAndDrop) { - if (m_hotIndex >= 0 && - m_hotIndex < int(m_shade.size())) { - m_dragIndex = m_hotIndex; - m_dropBefore = false; - captureMouse(); + case ui::kMouseDownMessage: + if (m_hotIndex >= 0 && + m_hotIndex < int(m_shade.size())) { + switch (m_click) { + case ClickEntries: + Click(); + m_hotIndex = -1; + invalidate(); + break; + case DragAndDropEntries: + m_dragIndex = m_hotIndex; + m_dropBefore = false; + captureMouse(); + break; } } break; - } case ui::kMouseUpMessage: { - if (m_click == Select) { + if (m_click == ClickWholeShade) { setSelected(true); Click(); closeWindow(); @@ -226,7 +255,7 @@ void ColorShades::onSizeHint(ui::SizeHintEvent& ev) if (size < 2) ev.setSizeHint(gfx::Size((16+m_boxSize)*ui::guiscale()+textWidth(), 18*ui::guiscale())); else { - if (m_click == Select && size > 16) + if (m_click == ClickWholeShade && size > 16) size = 16; ev.setSizeHint(gfx::Size(6+m_boxSize*size, 18)*ui::guiscale()); } @@ -280,7 +309,8 @@ void ColorShades::onPaint(ui::PaintEvent& ev) hotBounds = box; } - if (!hotBounds.isEmpty() && m_click == DragAndDrop) { + if (!hotBounds.isEmpty() && + isHotEntryVisible()) { hotBounds.enlarge(3*ui::guiscale()); ui::PaintWidgetPartInfo info; diff --git a/src/app/ui/color_shades.h b/src/app/ui/color_shades.h index 8f35227fc..b96f67a42 100644 --- a/src/app/ui/color_shades.h +++ b/src/app/ui/color_shades.h @@ -20,7 +20,11 @@ namespace app { class ColorShades : public ui::Widget { public: - enum ClickType { DragAndDrop, Select }; + enum ClickType { + ClickEntries, + DragAndDropEntries, + ClickWholeShade + }; ColorShades(const Shade& colors, ClickType click); @@ -33,6 +37,8 @@ namespace app { void updateShadeFromColorBarPicks(); + int getHotEntry() const { return m_hotIndex; } + obs::signal Click; private: @@ -41,6 +47,9 @@ namespace app { void onSizeHint(ui::SizeHintEvent& ev) override; void onPaint(ui::PaintEvent& ev) override; void onChangeColorBarSelection(); + bool isHotEntryVisible() const { + return m_click != ClickWholeShade; + } ClickType m_click; Shade m_shade; diff --git a/src/app/ui/context_bar.cpp b/src/app/ui/context_bar.cpp index d17accf0a..0d33c0832 100644 --- a/src/app/ui/context_bar.cpp +++ b/src/app/ui/context_bar.cpp @@ -462,7 +462,7 @@ class ContextBar::InkShadesField : public HBox { public: InkShadesField() : m_button(SkinTheme::instance()->parts.iconArrowDown()) - , m_shade(Shade(), ColorShades::DragAndDrop) + , m_shade(Shade(), ColorShades::DragAndDropEntries) , m_loaded(false) { addChild(&m_button); addChild(&m_shade); @@ -530,7 +530,7 @@ private: int i = 0; for (const Shade& shade : m_shades) { - auto shadeWidget = new ColorShades(shade, ColorShades::Select); + auto shadeWidget = new ColorShades(shade, ColorShades::ClickWholeShade); shadeWidget->setExpansive(true); shadeWidget->Click.connect( [&]{