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(
[&]{