Add RYB color wheel (related to #707)

This commit is contained in:
David Capello 2016-02-12 10:49:33 -03:00
parent a77ae98fd0
commit c1ae065c2c
7 changed files with 119 additions and 20 deletions

View File

@ -381,7 +381,10 @@
<param name="type" value="spectrum" />
</key>
<key command="SetColorSelector">
<param name="type" value="wheel" />
<param name="type" value="rgb-wheel" />
</key>
<key command="SetColorSelector">
<param name="type" value="ryb-wheel" />
</key>
</commands>
@ -855,8 +858,11 @@
<item command="SetColorSelector" text="Color Spectrum">
<param name="type" value="spectrum" />
</item>
<item command="SetColorSelector" text="Color Wheel">
<param name="type" value="wheel" />
<item command="SetColorSelector" text="RGB Color Wheel">
<param name="type" value="rgb-wheel" />
</item>
<item command="SetColorSelector" text="RYB Color Wheel">
<param name="type" value="ryb-wheel" />
</item>
<separator />
<item command="LoadPalette" text="L&amp;oad Palette" />

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Aseprite -->
<!-- Copyright (C) 2014-2015 by David Capello -->
<!-- Copyright (C) 2014-2016 by David Capello -->
<preferences>
<types>
@ -114,6 +114,7 @@
<option id="bg_color" type="app::Color" default="app::Color::fromRgb(0, 0, 0)" />
<option id="selector" type="app::ColorBar::ColorSelector" default="app::ColorBar::ColorSelector::SPECTRUM" />
<option id="discrete_wheel" type="bool" default="false" />
<option id="wheel_model" type="int" default="0" />
<option id="harmony" type="int" default="0" />
</section>
<section id="tool_box">

View File

@ -46,8 +46,12 @@ void SetColorSelectorCommand::onLoadParams(const Params& params)
if (type == "spectrum") {
m_type = ColorBar::ColorSelector::SPECTRUM;
}
else if (type == "wheel") {
m_type = ColorBar::ColorSelector::WHEEL;
else if (type == "wheel" ||
type == "rgb-wheel") {
m_type = ColorBar::ColorSelector::RGB_WHEEL;
}
else if (type == "ryb-wheel") {
m_type = ColorBar::ColorSelector::RYB_WHEEL;
}
}
@ -69,8 +73,11 @@ std::string SetColorSelectorCommand::onGetFriendlyName() const
case ColorBar::ColorSelector::SPECTRUM:
result += "Color Spectrum";
break;
case ColorBar::ColorSelector::WHEEL:
result += "Color Wheel";
case ColorBar::ColorSelector::RGB_WHEEL:
result += "RGB Color Wheel";
break;
case ColorBar::ColorSelector::RYB_WHEEL:
result += "RYB Color Wheel";
break;
default:
result += "Unknown";

View File

@ -1,5 +1,5 @@
// Aseprite
// Copyright (C) 2001-2015 David Capello
// Copyright (C) 2001-2016 David Capello
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License version 2 as
@ -325,7 +325,8 @@ void ColorBar::setColorSelector(ColorSelector selector)
m_spectrum->setVisible(true);
break;
case ColorSelector::WHEEL:
case ColorSelector::RGB_WHEEL:
case ColorSelector::RYB_WHEEL:
if (!m_wheel) {
m_wheel = new ColorWheel;
m_wheel->setExpansive(true);
@ -333,6 +334,10 @@ void ColorBar::setColorSelector(ColorSelector selector)
m_wheel->ColorChange.connect(&ColorBar::onPickSpectrum, this);
m_selectorPlaceholder.addChild(m_wheel);
}
m_wheel->setColorModel(
(m_selector == ColorSelector::RGB_WHEEL ?
ColorWheel::ColorModel::RGB:
ColorWheel::ColorModel::RYB));
m_wheel->setVisible(true);
break;

View File

@ -1,5 +1,5 @@
// Aseprite
// Copyright (C) 2001-2015 David Capello
// Copyright (C) 2001-2016 David Capello
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License version 2 as
@ -48,7 +48,8 @@ namespace app {
enum class ColorSelector {
NONE,
SPECTRUM,
WHEEL,
RGB_WHEEL,
RYB_WHEEL,
};
static ColorBar* instance() { return m_instance; }

View File

@ -1,5 +1,5 @@
// Aseprite
// Copyright (C) 2001-2015 David Capello
// Copyright (C) 2001-2016 David Capello
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License version 2 as
@ -19,13 +19,14 @@
#include "base/bind.h"
#include "base/pi.h"
#include "base/scoped_value.h"
#include "filters/color_curve.h"
#include "she/surface.h"
#include "ui/graphics.h"
#include "ui/menu.h"
#include "ui/message.h"
#include "ui/paint_event.h"
#include "ui/size_hint_event.h"
#include "ui/resize_event.h"
#include "ui/size_hint_event.h"
#include "ui/system.h"
namespace app {
@ -52,6 +53,7 @@ static struct {
ColorWheel::ColorWheel()
: Widget(kGenericWidget)
, m_discrete(Preferences::instance().colorBar.discreteWheel())
, m_colorModel((ColorModel)Preferences::instance().colorBar.wheelModel())
, m_harmony((Harmony)Preferences::instance().colorBar.harmony())
, m_options("", kButtonWidget, kButtonWidget, kCheckWidget)
, m_harmonyPicked(false)
@ -98,6 +100,7 @@ app::Color ColorWheel::pickColor(const gfx::Point& pos) const
hue *= 30;
}
hue %= 360; // To leave hue in [0,360) range
hue = convertHueAngle(hue, 1);
int sat;
if (m_discrete) {
@ -128,6 +131,10 @@ app::Color ColorWheel::pickColor(const gfx::Point& pos) const
rc.y+rc.h-boxsize,
boxsize, boxsize).contains(pos)) {
m_harmonyPicked = true;
color = app::Color::fromHsv(convertHueAngle(color.getHue(), 1),
color.getSaturation(),
color.getValue());
return color;
}
}
@ -153,6 +160,14 @@ void ColorWheel::setDiscrete(bool state)
invalidate();
}
void ColorWheel::setColorModel(ColorModel colorModel)
{
m_colorModel = colorModel;
Preferences::instance().colorBar.wheelModel((int)m_colorModel);
invalidate();
}
void ColorWheel::setHarmony(Harmony harmony)
{
m_harmony = harmony;
@ -171,7 +186,7 @@ app::Color ColorWheel::getColorInHarmony(int j) const
{
int i = MID(0, (int)m_harmony, (int)Harmony::LAST);
j = MID(0, j, harmonies[i].n-1);
int hue = m_mainColor.getHue() + harmonies[i].hues[j];
int hue = convertHueAngle(m_mainColor.getHue(), -1) + harmonies[i].hues[j];
int sat = m_mainColor.getSaturation() * harmonies[i].sats[j] / 100;
return app::Color::fromHsv(hue % 360,
MID(0, sat, 100),
@ -238,12 +253,17 @@ void ColorWheel::onPaint(ui::PaintEvent& ev)
for (int i=0; i<n; ++i) {
app::Color color = getColorInHarmony(i);
int hue = color.getHue()-30;
int sat = color.getSaturation();
int angle = color.getHue()-30;
int dist = color.getSaturation();
color = app::Color::fromHsv(convertHueAngle(color.getHue(), 1),
color.getSaturation(),
color.getValue());
gfx::Point pos =
m_wheelBounds.center() +
gfx::Point(int(+std::cos(PI*hue/180)*double(m_wheelRadius)*sat/100.0),
int(-std::sin(PI*hue/180)*double(m_wheelRadius)*sat/100.0));
gfx::Point(int(+std::cos(PI*angle/180)*double(m_wheelRadius)*dist/100.0),
int(-std::sin(PI*angle/180)*double(m_wheelRadius)*dist/100.0));
she::Surface* icon = theme->parts.colorWheelIndicator()->bitmap(0);
g->drawRgbaSurface(icon,
@ -358,4 +378,51 @@ void ColorWheel::onOptions()
menu.showPopup(gfx::Point(rc.x+rc.w, rc.y));
}
int ColorWheel::convertHueAngle(int hue, int dir) const
{
switch (m_colorModel) {
case ColorModel::RGB:
return hue;
case ColorModel::RYB: {
static std::vector<int> map1;
static std::vector<int> map2;
if (map2.empty()) {
filters::ColorCurve curve1(filters::ColorCurve::Linear);
curve1.addPoint(gfx::Point(0, 0));
curve1.addPoint(gfx::Point(60, 35));
curve1.addPoint(gfx::Point(122, 60));
curve1.addPoint(gfx::Point(165, 120));
curve1.addPoint(gfx::Point(218, 180));
curve1.addPoint(gfx::Point(275, 240));
curve1.addPoint(gfx::Point(330, 300));
curve1.addPoint(gfx::Point(360, 360));
filters::ColorCurve curve2(filters::ColorCurve::Linear);
for (const auto& pt : curve1)
curve2.addPoint(gfx::Point(pt.y, pt.x));
map1.resize(360);
map2.resize(360);
curve1.getValues(0, 359, map1);
curve2.getValues(0, 359, map2);
}
if (hue < 0)
hue += 360;
hue %= 360;
ASSERT(hue >= 0 && hue < 360);
if (dir > 0)
return map1[hue];
else if (dir < 0)
return map2[hue];
}
}
return hue;
}
} // namespace app

View File

@ -1,5 +1,5 @@
// Aseprite
// Copyright (C) 2001-2015 David Capello
// Copyright (C) 2001-2016 David Capello
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License version 2 as
@ -19,6 +19,11 @@ namespace app {
class ColorWheel : public ui::Widget {
public:
enum class ColorModel {
RGB,
RYB,
};
enum class Harmony {
NONE,
COMPLEMENTARY,
@ -40,6 +45,7 @@ namespace app {
bool isDiscrete() const { return m_discrete; }
void setDiscrete(bool state);
void setColorModel(ColorModel colorModel);
void setHarmony(Harmony harmony);
// Signals
@ -54,10 +60,16 @@ namespace app {
int getHarmonies() const;
app::Color getColorInHarmony(int i) const;
// Converts an hue angle from HSV <-> current color model hue.
// With dir == +1, the angle is from the color model and it's converted to HSV hue.
// With dir == -1, the angle came from HSV and is converted to the current color model.
int convertHueAngle(int angle, int dir) const;
gfx::Rect m_clientBounds;
gfx::Rect m_wheelBounds;
int m_wheelRadius;
bool m_discrete;
ColorModel m_colorModel;
Harmony m_harmony;
ui::ButtonBase m_options;
app::Color m_mainColor;