Add HSL color selection (related to #707)

This commit is contained in:
David Capello 2017-05-29 14:20:42 -03:00
parent c297031152
commit 29a49ad7fa
24 changed files with 640 additions and 241 deletions

View File

@ -50,9 +50,11 @@
<value id="RGB" value="4" />
<value id="HSVA" value="5" />
<value id="HSV" value="6" />
<value id="GRAYA" value="7" />
<value id="GRAY" value="8" />
<value id="INDEX" value="9" />
<value id="HSLA" value="7" />
<value id="HSL" value="8" />
<value id="GRAYA" value="9" />
<value id="GRAY" value="10" />
<value id="INDEX" value="11" />
</enum>
<enum id="EyedropperSample">
<value id="ALL_LAYERS" value="0" />

View File

@ -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.
@ -12,11 +12,12 @@
#include "app/color_utils.h"
#include "app/modules/palettes.h"
#include "gfx/hsv.h"
#include "gfx/rgb.h"
#include "doc/image.h"
#include "doc/palette.h"
#include "doc/primitives.h"
#include "gfx/hsl.h"
#include "gfx/hsv.h"
#include "gfx/rgb.h"
#include <cmath>
#include <cstdlib>
@ -56,6 +57,17 @@ Color Color::fromHsv(double h, double s, double v, int a)
return color;
}
// static
Color Color::fromHsl(double h, double s, double l, int a)
{
Color color(Color::HslType);
color.m_value.hsl.h = h;
color.m_value.hsl.s = s;
color.m_value.hsl.l = l;
color.m_value.hsl.a = a;
return color;
}
// static
Color Color::fromGray(int g, int a)
{
@ -123,6 +135,7 @@ Color Color::fromString(const std::string& str)
if (str != "mask") {
if (str.find("rgb{") == 0 ||
str.find("hsv{") == 0 ||
str.find("hsl{") == 0 ||
str.find("gray{") == 0) {
int c = 0;
double table[4] = { 0.0, 0.0, 0.0, 255.0 };
@ -139,8 +152,16 @@ Color Color::fromString(const std::string& str)
if (str[0] == 'r')
color = Color::fromRgb(int(table[0]), int(table[1]), int(table[2]), int(table[3]));
else if (str[0] == 'h')
color = Color::fromHsv(table[0], table[1], table[2], int(table[3]));
else if (str[0] == 'h' && str[1] == 's' && str[2] == 'v')
color = Color::fromHsv(table[0],
table[1] / 100.0,
table[2] / 100.0,
int(table[3]));
else if (str[0] == 'h' && str[1] == 's' && str[2] == 'l')
color = Color::fromHsl(table[0],
table[1] / 100.0,
table[2] / 100.0,
int(table[3]));
else if (str[0] == 'g')
color = Color::fromGray(int(table[0]), (c >= 2 ? int(table[1]): 255));
}
@ -175,11 +196,21 @@ std::string Color::toString() const
<< std::setprecision(2)
<< std::fixed
<< m_value.hsv.h << ","
<< m_value.hsv.s << ","
<< m_value.hsv.v << ","
<< MID(0.0, m_value.hsv.s*100.0, 100.0) << ","
<< MID(0.0, m_value.hsv.v*100.0, 100.0) << ","
<< m_value.hsv.a << "}";
break;
case Color::HslType:
result << "hsl{"
<< std::setprecision(2)
<< std::fixed
<< m_value.hsl.h << ","
<< MID(0.0, m_value.hsl.s*100.0, 100.0) << ","
<< MID(0.0, m_value.hsl.l*100.0, 100.0) << ","
<< m_value.hsl.a << "}";
break;
case Color::GrayType:
result << "gray{"
<< m_value.gray.g << ","
@ -227,10 +258,30 @@ std::string Color::toHumanReadableString(PixelFormat pixelFormat, HumanReadableS
result << "Gray " << getGray();
}
else {
result << "HSB "
result << "HSV "
<< int(m_value.hsv.h) << "\xc2\xb0 "
<< int(m_value.hsv.s) << "% "
<< int(m_value.hsv.v) << "%";
<< MID(0, int(m_value.hsv.s*100.0), 100) << "% "
<< MID(0, int(m_value.hsv.v*100.0), 100) << "%";
if (pixelFormat == IMAGE_INDEXED)
result << " Index " << color_utils::color_for_image(*this, pixelFormat);
result << " (RGB "
<< getRed() << " "
<< getGreen() << " "
<< getBlue() << ")";
}
break;
case Color::HslType:
if (pixelFormat == IMAGE_GRAYSCALE) {
result << "Gray " << getGray();
}
else {
result << "HSL "
<< int(m_value.hsl.h) << "\xc2\xb0 "
<< MID(0, int(m_value.hsl.s*100.0), 100) << "% "
<< MID(0, int(m_value.hsl.l*100.0), 100) << "%";
if (pixelFormat == IMAGE_INDEXED)
result << " Index " << color_utils::color_for_image(*this, pixelFormat);
@ -299,8 +350,19 @@ std::string Color::toHumanReadableString(PixelFormat pixelFormat, HumanReadableS
}
else {
result << int(m_value.hsv.h) << "\xc2\xb0"
<< int(m_value.hsv.s) << ","
<< int(m_value.hsv.v);
<< MID(0, int(m_value.hsv.s*100.0), 100) << ","
<< MID(0, int(m_value.hsv.v*100.0), 100);
}
break;
case Color::HslType:
if (pixelFormat == IMAGE_GRAYSCALE) {
result << "Gry-" << getGray();
}
else {
result << int(m_value.hsl.h) << "\xc2\xb0"
<< MID(0, int(m_value.hsl.s*100.0), 100) << ","
<< MID(0, int(m_value.hsl.l*100.0), 100);
}
break;
@ -341,10 +403,17 @@ bool Color::operator==(const Color& other) const
case Color::HsvType:
return
(std::fabs(m_value.hsv.h - other.m_value.hsv.h) < 0.001) &&
(std::fabs(m_value.hsv.s - other.m_value.hsv.s) < 0.001) &&
(std::fabs(m_value.hsv.v - other.m_value.hsv.v) < 0.001) &&
(std::fabs(m_value.hsv.s - other.m_value.hsv.s) < 0.00001) &&
(std::fabs(m_value.hsv.v - other.m_value.hsv.v) < 0.00001) &&
(m_value.hsv.a == other.m_value.hsv.a);
case Color::HslType:
return
(std::fabs(m_value.hsl.h - other.m_value.hsl.h) < 0.001) &&
(std::fabs(m_value.hsl.s - other.m_value.hsl.s) < 0.00001) &&
(std::fabs(m_value.hsl.l - other.m_value.hsl.l) < 0.00001) &&
(m_value.hsl.a == other.m_value.hsl.a);
case Color::GrayType:
return
m_value.gray.g == other.m_value.gray.g &&
@ -387,8 +456,13 @@ int Color::getRed() const
case Color::HsvType:
return Rgb(Hsv(m_value.hsv.h,
m_value.hsv.s / 100.0,
m_value.hsv.v / 100.0)).red();
m_value.hsv.s,
m_value.hsv.v)).red();
case Color::HslType:
return Rgb(Hsl(m_value.hsl.h,
m_value.hsl.s,
m_value.hsl.l)).red();
case Color::GrayType:
return m_value.gray.g;
@ -419,8 +493,13 @@ int Color::getGreen() const
case Color::HsvType:
return Rgb(Hsv(m_value.hsv.h,
m_value.hsv.s / 100.0,
m_value.hsv.v / 100.0)).green();
m_value.hsv.s,
m_value.hsv.v)).green();
case Color::HslType:
return Rgb(Hsl(m_value.hsl.h,
m_value.hsl.s,
m_value.hsl.l)).green();
case Color::GrayType:
return m_value.gray.g;
@ -451,8 +530,13 @@ int Color::getBlue() const
case Color::HsvType:
return Rgb(Hsv(m_value.hsv.h,
m_value.hsv.s / 100.0,
m_value.hsv.v / 100.0)).blue();
m_value.hsv.s,
m_value.hsv.v)).blue();
case Color::HslType:
return Rgb(Hsl(m_value.hsl.h,
m_value.hsl.s,
m_value.hsl.l)).blue();
case Color::GrayType:
return m_value.gray.g;
@ -471,7 +555,7 @@ int Color::getBlue() const
return -1;
}
double Color::getHue() const
double Color::getHsvHue() const
{
switch (getType()) {
@ -486,6 +570,9 @@ double Color::getHue() const
case Color::HsvType:
return m_value.hsv.h;
case Color::HslType:
return m_value.hsl.h;
case Color::GrayType:
return 0.0;
@ -507,7 +594,7 @@ double Color::getHue() const
return -1.0;
}
double Color::getSaturation() const
double Color::getHsvSaturation() const
{
switch (getType()) {
@ -517,11 +604,16 @@ double Color::getSaturation() const
case Color::RgbType:
return Hsv(Rgb(m_value.rgb.r,
m_value.rgb.g,
m_value.rgb.b)).saturation() * 100.0;
m_value.rgb.b)).saturation();
case Color::HsvType:
return m_value.hsv.s;
case Color::HslType:
return Hsv(Rgb(getRed(),
getGreen(),
getBlue())).saturation();
case Color::GrayType:
return 0;
@ -531,7 +623,7 @@ double Color::getSaturation() const
uint32_t c = get_current_palette()->getEntry(i);
return Hsv(Rgb(rgba_getr(c),
rgba_getg(c),
rgba_getb(c))).saturation() * 100.0;
rgba_getb(c))).saturation();
}
else
return 0.0;
@ -543,7 +635,7 @@ double Color::getSaturation() const
return -1.0;
}
double Color::getValue() const
double Color::getHsvValue() const
{
switch (getType()) {
@ -553,13 +645,18 @@ double Color::getValue() const
case Color::RgbType:
return Hsv(Rgb(m_value.rgb.r,
m_value.rgb.g,
m_value.rgb.b)).value() * 100.0;
m_value.rgb.b)).value();
case Color::HsvType:
return m_value.hsv.v;
case Color::HslType:
return Hsv(Rgb(getRed(),
getGreen(),
getBlue())).value();
case Color::GrayType:
return 100.0 * m_value.gray.g / 255.0;
return m_value.gray.g / 255.0;
case Color::IndexType: {
int i = m_value.index;
@ -567,7 +664,128 @@ double Color::getValue() const
uint32_t c = get_current_palette()->getEntry(i);
return Hsv(Rgb(rgba_getr(c),
rgba_getg(c),
rgba_getb(c))).value() * 100.0;
rgba_getb(c))).value();
}
else
return 0.0;
}
}
ASSERT(false);
return -1.0;
}
double Color::getHslHue() const
{
switch (getType()) {
case Color::MaskType:
return 0.0;
case Color::RgbType:
return Hsl(Rgb(m_value.rgb.r,
m_value.rgb.g,
m_value.rgb.b)).hue();
case Color::HsvType:
return m_value.hsv.h;
case Color::HslType:
return m_value.hsl.h;
case Color::GrayType:
return 0.0;
case Color::IndexType: {
int i = m_value.index;
if (i >= 0 && i < get_current_palette()->size()) {
uint32_t c = get_current_palette()->getEntry(i);
return Hsl(Rgb(rgba_getr(c),
rgba_getg(c),
rgba_getb(c))).hue();
}
else
return 0.0;
}
}
ASSERT(false);
return -1.0;
}
double Color::getHslSaturation() const
{
switch (getType()) {
case Color::MaskType:
return 0;
case Color::RgbType:
return Hsl(Rgb(m_value.rgb.r,
m_value.rgb.g,
m_value.rgb.b)).saturation();
case Color::HsvType:
return Hsl(Rgb(getRed(),
getGreen(),
getBlue())).saturation();
case Color::HslType:
return m_value.hsl.s;
case Color::GrayType:
return 0;
case Color::IndexType: {
int i = m_value.index;
if (i >= 0 && i < get_current_palette()->size()) {
uint32_t c = get_current_palette()->getEntry(i);
return Hsl(Rgb(rgba_getr(c),
rgba_getg(c),
rgba_getb(c))).saturation();
}
else
return 0.0;
}
}
ASSERT(false);
return -1.0;
}
double Color::getHslLightness() const
{
switch (getType()) {
case Color::MaskType:
return 0.0;
case Color::RgbType:
return Hsl(Rgb(m_value.rgb.r,
m_value.rgb.g,
m_value.rgb.b)).lightness();
case Color::HsvType:
return Hsl(Rgb(getRed(),
getGreen(),
getBlue())).lightness();
case Color::HslType:
return m_value.hsl.l;
case Color::GrayType:
return m_value.gray.g / 255.0;
case Color::IndexType: {
int i = m_value.index;
if (i >= 0 && i < get_current_palette()->size()) {
uint32_t c = get_current_palette()->getEntry(i);
return Hsl(Rgb(rgba_getr(c),
rgba_getg(c),
rgba_getb(c))).lightness();
}
else
return 0.0;
@ -587,12 +805,17 @@ int Color::getGray() const
return 0;
case Color::RgbType:
return int(255.0 * Hsv(Rgb(m_value.rgb.r,
return int(255.0 * Hsl(Rgb(m_value.rgb.r,
m_value.rgb.g,
m_value.rgb.b)).value());
m_value.rgb.b)).lightness());
case Color::HsvType:
return int(255.0 * m_value.hsv.v / 100.0);
return int(255.0 * Hsl(Rgb(getRed(),
getGreen(),
getBlue())).lightness());
case Color::HslType:
return int(255.0 * m_value.hsl.l);
case Color::GrayType:
return m_value.gray.g;
@ -601,9 +824,9 @@ int Color::getGray() const
int i = m_value.index;
if (i >= 0 && i < get_current_palette()->size()) {
uint32_t c = get_current_palette()->getEntry(i);
return int(255.0 * Hsv(Rgb(rgba_getr(c),
return int(255.0 * Hsl(Rgb(rgba_getr(c),
rgba_getg(c),
rgba_getb(c))).value());
rgba_getb(c))).lightness());
}
else
return 0;
@ -624,6 +847,7 @@ int Color::getIndex() const
case Color::RgbType:
case Color::HsvType:
case Color::HslType:
case Color::GrayType: {
int i = get_current_palette()->findExactMatch(getRed(), getGreen(), getBlue(), getAlpha(), -1);
if (i >= 0)
@ -654,6 +878,9 @@ int Color::getAlpha() const
case Color::HsvType:
return m_value.hsv.a;
case Color::HslType:
return m_value.hsl.a;
case Color::GrayType:
return m_value.gray.a;

View File

@ -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.
@ -28,6 +28,7 @@ namespace app {
MaskType,
RgbType,
HsvType,
HslType,
GrayType,
IndexType,
};
@ -42,7 +43,8 @@ namespace app {
static Color fromMask();
static Color fromRgb(int r, int g, int b, int a = 255);
static Color fromHsv(double h, double s, double v, int a = 255); // h=[0,360], s=[0,100], v=[0,100]
static Color fromHsv(double h, double s, double v, int a = 255); // h=[0,360], s=[0,1], v=[0,1]
static Color fromHsl(double h, double s, double l, int a = 255); // h=[0,360], s=[0,1], v=[0,1]
static Color fromGray(int g, int a = 255);
static Color fromIndex(int index);
@ -68,9 +70,12 @@ namespace app {
int getRed() const;
int getGreen() const;
int getBlue() const;
double getHue() const;
double getSaturation() const;
double getValue() const;
double getHsvHue() const;
double getHsvSaturation() const;
double getHsvValue() const;
double getHslHue() const;
double getHslSaturation() const;
double getHslLightness() const;
int getGray() const;
int getIndex() const;
int getAlpha() const;
@ -90,6 +95,10 @@ namespace app {
double h, s, v;
int a;
} hsv;
struct {
double h, s, l;
int a;
} hsl;
struct {
int g, a;
} gray;

View File

@ -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.
@ -20,28 +20,37 @@ namespace app {
TEST(Color, fromRgb)
{
EXPECT_EQ(32, Color::fromRgb(32, 16, 255).getRed());
EXPECT_EQ(16, Color::fromRgb(32, 16, 255).getGreen());
EXPECT_EQ( 32, Color::fromRgb(32, 16, 255).getRed());
EXPECT_EQ( 16, Color::fromRgb(32, 16, 255).getGreen());
EXPECT_EQ(255, Color::fromRgb(32, 16, 255).getBlue());
}
TEST(Color, fromHsv)
{
EXPECT_EQ(60, Color::fromHsv(60, 5, 100).getHue());
EXPECT_EQ(5, Color::fromHsv(60, 5, 100).getSaturation());
EXPECT_EQ(100, Color::fromHsv(60, 5, 100).getValue());
EXPECT_EQ(60.0, Color::fromHsv(60, 0.05, 1.0).getHsvHue());
EXPECT_EQ(0.05, Color::fromHsv(60, 0.05, 1.0).getHsvSaturation());
EXPECT_EQ(1.00, Color::fromHsv(60, 0.05, 1.0).getHsvValue());
}
TEST(Color, fromHsl)
{
EXPECT_EQ(60.0, Color::fromHsl(60, 0.05, 1.0).getHslHue());
EXPECT_EQ(0.05, Color::fromHsl(60, 0.05, 1.0).getHslSaturation());
EXPECT_EQ(1.00, Color::fromHsl(60, 0.05, 1.0).getHslLightness());
}
TEST(Color, fromString)
{
EXPECT_EQ(Color::fromRgb(0, 0, 0), Color::fromString("rgb{0,0.0,0}"));
EXPECT_EQ(Color::fromRgb(32, 16, 255), Color::fromString("rgb{32,16,255}"));
EXPECT_EQ(Color::fromHsv(32, 64, 99), Color::fromString("hsv{32,64,99}"));
EXPECT_EQ(Color::fromHsv(32, 0.64, 0.99), Color::fromString("hsv{32,64,99}"));
EXPECT_EQ(Color::fromHsl(32, 0.64, 0.99), Color::fromString("hsl{32,64,99}"));
}
TEST(Color, toString)
{
EXPECT_EQ("rgb{0,0,0,255}", Color::fromRgb(0, 0, 0).toString());
EXPECT_EQ("rgb{32,16,255,255}", Color::fromRgb(32, 16, 255).toString());
EXPECT_EQ("hsv{32.00,64.00,99.00,255}", Color::fromHsv(32, 64, 99).toString());
EXPECT_EQ("hsv{32.00,64.00,99.00,255}", Color::fromHsv(32, 64/100.0, 99/100.0).toString());
EXPECT_EQ("hsl{32.00,64.00,99.00,255}", Color::fromHsl(32, 64/100.0, 99/100.0).toString());
}

View File

@ -1,5 +1,5 @@
// Aseprite
// Copyright (C) 2001-2015 David Capello
// Copyright (C) 2001-2017 David Capello
//
// This program is distributed under the terms of
// the End-User License Agreement for Aseprite.
@ -48,6 +48,7 @@ gfx::Color color_utils::color_for_ui(const app::Color& color)
case app::Color::RgbType:
case app::Color::HsvType:
case app::Color::HslType:
c = gfx::rgba(
color.getRed(),
color.getGreen(),

View File

@ -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.
@ -90,9 +90,16 @@ void EyedropperCommand::pickSample(const doc::Site& site,
break;
case app::Color::HsvType:
color = app::Color::fromHsv(color.getHue(),
color.getSaturation(),
color.getValue(),
color = app::Color::fromHsv(color.getHsvHue(),
color.getHsvSaturation(),
color.getHsvValue(),
picked.getAlpha());
break;
case app::Color::HslType:
color = app::Color::fromHsl(color.getHslHue(),
color.getHslSaturation(),
color.getHslLightness(),
picked.getAlpha());
break;
@ -123,16 +130,32 @@ void EyedropperCommand::pickSample(const doc::Site& site,
if (picked.getType() == app::Color::HsvType)
color = picked;
else
color = app::Color::fromHsv(picked.getHue(),
picked.getSaturation(),
picked.getValue(),
color = app::Color::fromHsv(picked.getHsvHue(),
picked.getHsvSaturation(),
picked.getHsvValue(),
picked.getAlpha());
break;
case app::gen::EyedropperChannel::HSV:
if (picked.getAlpha() > 0)
color = app::Color::fromHsv(picked.getHue(),
picked.getSaturation(),
picked.getValue(),
color = app::Color::fromHsv(picked.getHsvHue(),
picked.getHsvSaturation(),
picked.getHsvValue(),
color.getAlpha());
break;
case app::gen::EyedropperChannel::HSLA:
if (picked.getType() == app::Color::HslType)
color = picked;
else
color = app::Color::fromHsl(picked.getHslHue(),
picked.getHslSaturation(),
picked.getHslLightness(),
picked.getAlpha());
break;
case app::gen::EyedropperChannel::HSL:
if (picked.getAlpha() > 0)
color = app::Color::fromHsl(picked.getHslHue(),
picked.getHslSaturation(),
picked.getHslLightness(),
color.getAlpha());
break;
case app::gen::EyedropperChannel::GRAYA:

View File

@ -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.
@ -39,6 +39,7 @@
#include "doc/image.h"
#include "doc/palette.h"
#include "doc/sprite.h"
#include "gfx/hsl.h"
#include "gfx/hsv.h"
#include "gfx/rgb.h"
#include "gfx/size.h"
@ -54,7 +55,7 @@ namespace app {
using namespace gfx;
using namespace ui;
enum { RGB_MODE, HSV_MODE };
enum { RGB_MODE, HSV_MODE, HSL_MODE };
enum { ABS_MODE, REL_MODE };
class PaletteEntryEditor : public Window {
@ -97,6 +98,7 @@ private:
Label m_entryLabel;
RgbSliders m_rgbSliders;
HsvSliders m_hsvSliders;
HslSliders m_hslSliders;
// This variable is used to avoid updating the m_hexColorEntry text
// when the color change is generated from a
@ -241,7 +243,7 @@ PaletteEntryEditor::PaletteEntryEditor()
, m_vbox(VERTICAL)
, m_topBox(HORIZONTAL)
, m_bottomBox(HORIZONTAL)
, m_colorType(2)
, m_colorType(3)
, m_changeMode(2)
, m_entryLabel("")
, m_disableHexUpdate(false)
@ -252,7 +254,8 @@ PaletteEntryEditor::PaletteEntryEditor()
, m_fromPalette(0, 0)
{
m_colorType.addItem("RGB")->setFocusStop(false);
m_colorType.addItem("HSB")->setFocusStop(false);
m_colorType.addItem("HSV")->setFocusStop(false);
m_colorType.addItem("HSL")->setFocusStop(false);
m_changeMode.addItem("Abs")->setFocusStop(false);
m_changeMode.addItem("Rel")->setFocusStop(false);
@ -273,6 +276,7 @@ PaletteEntryEditor::PaletteEntryEditor()
m_vbox.addChild(&m_topBox);
m_vbox.addChild(&m_rgbSliders);
m_vbox.addChild(&m_hsvSliders);
m_vbox.addChild(&m_hslSliders);
m_vbox.addChild(&m_bottomBox);
addChild(&m_vbox);
@ -281,6 +285,7 @@ PaletteEntryEditor::PaletteEntryEditor()
m_rgbSliders.ColorChange.connect(&PaletteEntryEditor::onColorSlidersChange, this);
m_hsvSliders.ColorChange.connect(&PaletteEntryEditor::onColorSlidersChange, this);
m_hslSliders.ColorChange.connect(&PaletteEntryEditor::onColorSlidersChange, this);
m_hexColorEntry.ColorChange.connect(&PaletteEntryEditor::onColorHexEntryChange, this);
m_changeMode.setSelectedItem(ABS_MODE);
@ -309,6 +314,7 @@ void PaletteEntryEditor::setColor(const app::Color& color)
{
m_rgbSliders.setColor(color);
m_hsvSliders.setColor(color);
m_hslSliders.setColor(color);
if (!m_disableHexUpdate)
m_hexColorEntry.setColor(color);
@ -455,6 +461,9 @@ void PaletteEntryEditor::onColorTypeClick()
case HSV_MODE:
selectColorType(app::Color::HsvType);
break;
case HSL_MODE:
selectColorType(app::Color::HslType);
break;
}
}
@ -464,10 +473,12 @@ void PaletteEntryEditor::onChangeModeClick()
case ABS_MODE:
m_rgbSliders.setMode(ColorSliders::Absolute);
m_hsvSliders.setMode(ColorSliders::Absolute);
m_hslSliders.setMode(ColorSliders::Absolute);
break;
case REL_MODE:
m_rgbSliders.setMode(ColorSliders::Relative);
m_hsvSliders.setMode(ColorSliders::Relative);
m_hslSliders.setMode(ColorSliders::Relative);
break;
}
@ -541,46 +552,86 @@ void PaletteEntryEditor::setAbsolutePaletteEntryChannel(ColorSliders::Channel ch
}
break;
case app::Color::HsvType:
{
Hsv hsv;
case app::Color::HsvType: {
Hsv hsv;
// Modify one entry
if (picksCount == 1) {
hsv.hue(color.getHue());
hsv.saturation(double(color.getSaturation()) / 100.0);
hsv.value(double(color.getValue()) / 100.0);
a = color.getAlpha();
}
// Modify one channel a set of entries
else {
// Convert RGB to HSV
hsv = Hsv(Rgb(r, g, b));
// 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;
case ColorSliders::Alpha:
a = color.getAlpha();
break;
}
}
// Convert HSV back to RGB
Rgb rgb(hsv);
r = rgb.red();
g = rgb.green();
b = rgb.blue();
// Modify one entry
if (picksCount == 1) {
hsv.hue(color.getHsvHue());
hsv.saturation(color.getHsvSaturation());
hsv.value(color.getHsvValue());
a = color.getAlpha();
}
// Modify one channel a set of entries
else {
// Convert RGB to HSV
hsv = Hsv(Rgb(r, g, b));
// Only modify the desired HSV channel
switch (channel) {
case ColorSliders::HsvHue:
hsv.hue(color.getHsvHue());
break;
case ColorSliders::HsvSaturation:
hsv.saturation(color.getHsvSaturation());
break;
case ColorSliders::HsvValue:
hsv.value(color.getHsvValue());
break;
case ColorSliders::Alpha:
a = color.getAlpha();
break;
}
}
// Convert HSV back to RGB
Rgb rgb(hsv);
r = rgb.red();
g = rgb.green();
b = rgb.blue();
break;
}
case app::Color::HslType: {
Hsl hsl;
// Modify one entry
if (picksCount == 1) {
hsl.hue(color.getHslHue());
hsl.saturation(color.getHslSaturation());
hsl.lightness(color.getHslLightness());
a = color.getAlpha();
}
// Modify one channel a set of entries
else {
// Convert RGB to HSL
hsl = Hsl(Rgb(r, g, b));
// Only modify the desired HSL channel
switch (channel) {
case ColorSliders::HslHue:
hsl.hue(color.getHslHue());
break;
case ColorSliders::HslSaturation:
hsl.saturation(color.getHslSaturation());
break;
case ColorSliders::HslLightness:
hsl.lightness(color.getHslLightness());
break;
case ColorSliders::Alpha:
a = color.getAlpha();
break;
}
}
// Convert HSL back to RGB
Rgb rgb(hsl);
r = rgb.red();
g = rgb.green();
b = rgb.blue();
break;
}
}
palette->setEntry(c, doc::rgba(r, g, b, a));
@ -613,9 +664,9 @@ void PaletteEntryEditor::setRelativePaletteEntryChannel(ColorSliders::Channel ch
switch (m_type) {
case app::Color::RgbType:
r = MID(0, r+m_relDeltas[ColorSliders::Red], 255);
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);
b = MID(0, b+m_relDeltas[ColorSliders::Blue], 255);
a = MID(0, a+m_relDeltas[ColorSliders::Alpha], 255);
break;
@ -623,16 +674,16 @@ void PaletteEntryEditor::setRelativePaletteEntryChannel(ColorSliders::Channel ch
// 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];
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;
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);
hsv.saturation(MID(0.0, s, 1.0));
hsv.value (MID(0.0, v, 1.0));
// Convert HSV back to RGB
Rgb rgb(hsv);
@ -643,6 +694,30 @@ void PaletteEntryEditor::setRelativePaletteEntryChannel(ColorSliders::Channel ch
break;
}
case app::Color::HslType: {
// 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;
if (h < 0.0) h += 360.0;
else if (h > 360.0) h -= 360.0;
hsl.hue (h);
hsl.saturation(MID(0.0, s, 1.0));
hsl.lightness (MID(0.0, l, 1.0));
// Convert HSL back to RGB
Rgb rgb(hsl);
r = rgb.red();
g = rgb.green();
b = rgb.blue();
a = MID(0, a+m_relDeltas[ColorSliders::Alpha], 255);
break;
}
}
palette->setEntry(c, doc::rgba(r, g, b, a));
@ -654,12 +729,14 @@ 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);
resetRelativeInfo();
switch (type) {
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;
}
m_vbox.layout();
@ -747,6 +824,7 @@ void PaletteEntryEditor::resetRelativeInfo()
{
m_rgbSliders.resetRelativeSliders();
m_hsvSliders.resetRelativeSliders();
m_hslSliders.resetRelativeSliders();
get_current_palette()->copyColorsTo(&m_fromPalette);
m_relDeltas.clear();
}

View File

@ -52,6 +52,7 @@ private:
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));
restartPreview();
}
@ -90,7 +91,8 @@ void HueSaturationCommand::onExecute(Context* context)
filterMgr.setTarget(TARGET_RED_CHANNEL |
TARGET_GREEN_CHANNEL |
TARGET_BLUE_CHANNEL |
TARGET_GRAY_CHANNEL);
TARGET_GRAY_CHANNEL |
TARGET_ALPHA_CHANNEL);
HueSaturationWindow window(filter, filterMgr);
window.doModal();

View File

@ -44,9 +44,11 @@ using namespace doc;
enum {
INDEX_MODE,
RGB_MODE,
HSB_MODE,
HSV_MODE,
HSL_MODE,
GRAY_MODE,
MASK_MODE
MASK_MODE,
COLOR_MODES
};
static base::UniquePtr<doc::Palette> g_simplePal(nullptr);
@ -124,7 +126,7 @@ ColorPopup::ColorPopup(const bool canPin,
, m_color(app::Color::fromMask())
, m_colorPalette(false, PaletteView::SelectOneColor, this, 7*guiscale())
, m_simpleColors(nullptr)
, m_colorType(5)
, m_colorType(COLOR_MODES)
, m_maskLabel("Transparent Color Selected")
, m_canPin(canPin)
, m_disableHexUpdate(false)
@ -145,7 +147,8 @@ ColorPopup::ColorPopup(const bool canPin,
m_colorType.addItem("Index")->setFocusStop(false);
m_colorType.addItem("RGB")->setFocusStop(false);
m_colorType.addItem("HSB")->setFocusStop(false);
m_colorType.addItem("HSV")->setFocusStop(false);
m_colorType.addItem("HSL")->setFocusStop(false);
m_colorType.addItem("Gray")->setFocusStop(false);
m_colorType.addItem("Mask")->setFocusStop(false);
@ -156,6 +159,7 @@ ColorPopup::ColorPopup(const bool canPin,
m_colorPaletteContainer.setExpansive(true);
m_rgbSliders.setExpansive(true);
m_hsvSliders.setExpansive(true);
m_hslSliders.setExpansive(true);
m_graySlider.setExpansive(true);
m_topBox.addChild(&m_colorType);
@ -190,6 +194,7 @@ ColorPopup::ColorPopup(const bool canPin,
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_maskLabel);
addChild(&m_vbox);
@ -198,6 +203,7 @@ ColorPopup::ColorPopup(const bool canPin,
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_hexColorEntry.ColorChange.connect(&ColorPopup::onColorHexEntryChange, this);
@ -240,6 +246,7 @@ void ColorPopup::setColor(const app::Color& color, SetColorOptions options)
m_rgbSliders.setColor(m_color);
m_hsvSliders.setColor(m_color);
m_hslSliders.setColor(m_color);
m_graySlider.setColor(m_color);
if (!m_disableHexUpdate)
m_hexColorEntry.setColor(m_color);
@ -340,10 +347,16 @@ void ColorPopup::onColorTypeClick()
newColor.getBlue(),
newColor.getAlpha());
break;
case HSB_MODE:
newColor = app::Color::fromHsv(newColor.getHue(),
newColor.getSaturation(),
newColor.getValue(),
case HSV_MODE:
newColor = app::Color::fromHsv(newColor.getHsvHue(),
newColor.getHsvSaturation(),
newColor.getHsvValue(),
newColor.getAlpha());
break;
case HSL_MODE:
newColor = app::Color::fromHsl(newColor.getHslHue(),
newColor.getHslSaturation(),
newColor.getHslLightness(),
newColor.getAlpha());
break;
case GRAY_MODE:
@ -393,18 +406,20 @@ 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(HSB_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;
}
// Remove focus from hidden RGB/HSB text entries
// Remove focus from hidden RGB/HSV/HSL text entries
auto widget = manager()->getFocus();
if (widget && !widget->isVisible()) {
auto window = widget->window();

View File

@ -71,6 +71,7 @@ namespace app {
HexColorEntry m_hexColorEntry;
RgbSliders m_rgbSliders;
HsvSliders m_hsvSliders;
HslSliders m_hslSliders;
GraySlider m_graySlider;
ui::Label m_maskLabel;
obs::scoped_connection m_onPaletteChangeConn;

View File

@ -53,7 +53,7 @@ bool ColorSelector::onProcessMessage(ui::Message* msg)
scale = 15.0;
}
double newHue = m_color.getHue()
double newHue = m_color.getHsvHue()
+ scale*(+ static_cast<MouseMessage*>(msg)->wheelDelta().x
- static_cast<MouseMessage*>(msg)->wheelDelta().y);
@ -61,12 +61,12 @@ bool ColorSelector::onProcessMessage(ui::Message* msg)
newHue += 360.0;
newHue = std::fmod(newHue, 360.0);
if (newHue != m_color.getHue()) {
if (newHue != m_color.getHsvHue()) {
app::Color newColor =
app::Color::fromHsv(
newHue,
m_color.getSaturation(),
m_color.getValue());
m_color.getHsvSaturation(),
m_color.getHsvValue());
ColorChange(newColor, kButtonNone);
}

View File

@ -62,18 +62,49 @@ namespace {
case ColorSliders::Blue:
color = gfx::rgba(m_color.getRed(), m_color.getGreen(), 255 * x / w);
break;
case ColorSliders::Hue:
color = color_utils::color_for_ui(app::Color::fromHsv(360 * x / w, m_color.getSaturation(), m_color.getValue()));
case ColorSliders::HsvHue:
color = color_utils::color_for_ui(
app::Color::fromHsv(360.0 * x / w,
m_color.getHsvSaturation(),
m_color.getHsvValue()));
break;
case ColorSliders::Saturation:
color = color_utils::color_for_ui(app::Color::fromHsv(m_color.getHue(), 100 * x / w, m_color.getValue()));
case ColorSliders::HsvSaturation:
color = color_utils::color_for_ui(
app::Color::fromHsv(m_color.getHsvHue(),
double(x) / double(w),
m_color.getHsvValue()));
break;
case ColorSliders::Value:
color = color_utils::color_for_ui(app::Color::fromHsv(m_color.getHue(), m_color.getSaturation(), 100 * x / w));
case ColorSliders::HsvValue:
color = color_utils::color_for_ui(
app::Color::fromHsv(m_color.getHsvHue(),
m_color.getHsvSaturation(),
double(x) / double(w)));
break;
case ColorSliders::HslHue:
color = color_utils::color_for_ui(
app::Color::fromHsl(360.0 * x / w,
m_color.getHslSaturation(),
m_color.getHslLightness()));
break;
case ColorSliders::HslSaturation:
color = color_utils::color_for_ui(
app::Color::fromHsl(m_color.getHslHue(),
double(x) / double(w),
m_color.getHslLightness()));
break;
case ColorSliders::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::Alpha:
color = color_utils::color_for_ui(app::Color::fromGray(255 * x / w));
color = color_utils::color_for_ui(
app::Color::fromGray(255 * x / w));
break;
}
g->drawVLine(color, rc.x+x, rc.y, rc.h);
@ -390,25 +421,25 @@ app::Color RgbSliders::getColorFromSliders()
HsvSliders::HsvSliders()
: ColorSliders()
{
addSlider(Hue, "H", 0, 360, -180, 180);
addSlider(Saturation, "S", 0, 100, -100, 100);
addSlider(Value, "B", 0, 100, -100, 100);
addSlider(Alpha, "A", 0, 255, -255, 255);
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.getHue()));
setAbsSliderValue(1, int(color.getSaturation()));
setAbsSliderValue(2, int(color.getValue()));
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),
getAbsSliderValue(2),
getAbsSliderValue(1) / 100.0,
getAbsSliderValue(2) / 100.0,
getAbsSliderValue(3));
}
@ -418,31 +449,26 @@ app::Color HsvSliders::getColorFromSliders()
HslSliders::HslSliders()
: ColorSliders()
{
addSlider(Hue, "H", 0, 360, -180, 180);
addSlider(Saturation, "S", 0, 100, -100, 100);
addSlider(Value, "L", 0, 100, -100, 100);
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)
{
gfx::Hsl hsl(gfx::Rgb(color.getRed(),
color.getGreen(),
color.getBlue()));
setAbsSliderValue(0, hsl.hue());
setAbsSliderValue(1, hsl.saturation() * 100.0);
setAbsSliderValue(2, hsl.lightness() * 100.0);
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()
{
gfx::Hsl hsl(getAbsSliderValue(0),
getAbsSliderValue(1) / 100.0,
getAbsSliderValue(2) / 100.0);
gfx::Rgb rgb(hsl);
return app::Color::fromRgb(rgb.red(),
rgb.green(),
rgb.blue(), 255);
return app::Color::fromHsl(getAbsSliderValue(0),
getAbsSliderValue(1) / 100.0,
getAbsSliderValue(2) / 100.0,
getAbsSliderValue(3));
}
//////////////////////////////////////////////////////////////////////

View File

@ -29,9 +29,9 @@ namespace app {
class ColorSliders : public ui::Widget {
public:
enum Channel { Red, Green, Blue,
Hue, Saturation, Value,
Gray,
Alpha };
HsvHue, HsvSaturation, HsvValue,
HslHue, HslSaturation, HslLightness,
Gray, Alpha };
enum Mode { Absolute, Relative };
ColorSliders();

View File

@ -55,13 +55,13 @@ app::Color ColorSpectrum::getColorByPosition(const gfx::Point& pos)
}
double hue = 360.0 * u / umax;
double sat = (v < vmid ? 100.0 * v / vmid : 100.0);
double val = (v < vmid ? 100.0 : 100.0-(100.0 * (v-vmid) / vmid));
double sat = (v < vmid ? double(v) / double(vmid) : 1.0);
double val = (v < vmid ? 1.0 : 1.0-(double(v-vmid) / double(vmid)));
return app::Color::fromHsv(
MID(0.0, hue, 360.0),
MID(0.0, sat, 100.0),
MID(0.0, val, 100.0));
MID(0.0, sat, 1.0),
MID(0.0, val, 1.0));
}
void ColorSpectrum::onPaint(ui::PaintEvent& ev)
@ -95,31 +95,31 @@ void ColorSpectrum::onPaint(ui::PaintEvent& ev)
}
double hue = 360.0 * u / umax;
double sat = (v < vmid ? 100.0 * v / vmid : 100.0);
double val = (v < vmid ? 100.0 : 100.0-(100.0 * (v-vmid) / vmid));
double sat = (v < vmid ? double(v) / double(vmid) : 1.0);
double val = (v < vmid ? 1.0 : 1.0-(double(v-vmid) / double(vmid)));
gfx::Color color = color_utils::color_for_ui(
app::Color::fromHsv(
MID(0.0, hue, 360.0),
MID(0.0, sat, 100.0),
MID(0.0, val, 100.0)));
MID(0.0, sat, 1.0),
MID(0.0, val, 1.0)));
g->putPixel(color, rc.x+x, rc.y+y);
}
}
if (m_color.getType() != app::Color::MaskType) {
double hue = m_color.getHue();
double sat = m_color.getSaturation();
double val = m_color.getValue();
double lit = (200.0 - sat) * val / 200.0;
double hue = m_color.getHsvHue();
double sat = m_color.getHsvSaturation();
double val = m_color.getHsvValue();
double lit = (2.0 - sat) * val / 2.0;
gfx::Point pos(rc.x + int(hue * rc.w / 360.0),
rc.y + rc.h - int(lit * rc.h / 100.0));
rc.y + rc.h - int(lit * rc.h));
she::Surface* icon = theme->parts.colorWheelIndicator()->bitmap(0);
g->drawColoredRgbaSurface(
icon,
lit > 50.0 ? gfx::rgba(0, 0, 0): gfx::rgba(255, 255, 255),
lit > 0.5 ? gfx::rgba(0, 0, 0): gfx::rgba(255, 255, 255),
pos.x-icon->width()/2,
pos.y-icon->height()/2);
}

View File

@ -54,19 +54,19 @@ app::Color ColorTintShadeTone::getColorByPosition(const gfx::Point& pos)
if (inHue) {
hue = (360.0 * u / umax);
sat = m_color.getSaturation();
val = m_color.getValue();
sat = m_color.getHsvSaturation();
val = m_color.getHsvValue();
}
else {
hue = m_color.getHue();
sat = (100.0 * u / umax);
val = (100.0 - 100.0 * v / vmax);
hue = m_color.getHsvHue();
sat = (1.0 * u / umax);
val = (1.0 - double(v) / double(vmax));
}
return app::Color::fromHsv(
MID(0.0, hue, 360.0),
MID(0.0, sat, 100.0),
MID(0.0, val, 100.0));
MID(0.0, sat, 1.0),
MID(0.0, val, 1.0));
}
void ColorTintShadeTone::onPaint(ui::PaintEvent& ev)
@ -82,7 +82,7 @@ void ColorTintShadeTone::onPaint(ui::PaintEvent& ev)
if (rc.isEmpty())
return;
double hue = m_color.getHue();
double hue = m_color.getHsvHue();
int umax, vmax;
int huebar = getHueBarSize();
umax = MAX(1, rc.w-1);
@ -90,14 +90,14 @@ void ColorTintShadeTone::onPaint(ui::PaintEvent& ev)
for (int y=0; y<rc.h-huebar; ++y) {
for (int x=0; x<rc.w; ++x) {
double sat = (100.0 * x / umax);
double val = (100.0 - 100.0 * y / vmax);
double sat = double(x) / double(umax);
double val = 1.0 - double(y) / double(vmax);
gfx::Color color = color_utils::color_for_ui(
app::Color::fromHsv(
hue,
MID(0.0, sat, 100.0),
MID(0.0, val, 100.0)));
MID(0.0, sat, 1.0),
MID(0.0, val, 1.0)));
g->putPixel(color, rc.x+x, rc.y+y);
}
@ -108,7 +108,7 @@ void ColorTintShadeTone::onPaint(ui::PaintEvent& ev)
for (int x=0; x<rc.w; ++x) {
gfx::Color color = color_utils::color_for_ui(
app::Color::fromHsv(
(360.0 * x / rc.w), 100.0, 100.0));
(360.0 * x / rc.w), 1.0, 1.0));
g->putPixel(color, rc.x+x, rc.y+y);
}
@ -116,15 +116,15 @@ void ColorTintShadeTone::onPaint(ui::PaintEvent& ev)
}
if (m_color.getType() != app::Color::MaskType) {
double sat = m_color.getSaturation();
double val = m_color.getValue();
gfx::Point pos(rc.x + int(sat * rc.w / 100.0),
rc.y + int((100.0-val) * (rc.h-huebar) / 100.0));
double sat = m_color.getHsvSaturation();
double val = m_color.getHsvValue();
gfx::Point pos(rc.x + int(sat * rc.w),
rc.y + int((1.0-val) * (rc.h-huebar)));
she::Surface* icon = theme->parts.colorWheelIndicator()->bitmap(0);
g->drawColoredRgbaSurface(
icon,
val > 50.0 ? gfx::rgba(0, 0, 0): gfx::rgba(255, 255, 255),
val > 0.5 ? gfx::rgba(0, 0, 0): gfx::rgba(255, 255, 255),
pos.x-icon->width()/2,
pos.y-icon->height()/2);

View File

@ -105,8 +105,8 @@ app::Color ColorWheel::getColorInClientPos(const gfx::Point& pos)
return app::Color::fromHsv(
MID(0, hue, 360),
MID(0, sat, 100),
100);
MID(0, sat / 100.0, 1.0),
1.0);
}
// Pick harmonies
@ -123,9 +123,9 @@ app::Color ColorWheel::getColorInClientPos(const gfx::Point& pos)
boxsize, boxsize).contains(pos)) {
m_harmonyPicked = true;
color = app::Color::fromHsv(convertHueAngle(int(color.getHue()), 1),
color.getSaturation(),
color.getValue());
color = app::Color::fromHsv(convertHueAngle(int(color.getHsvHue()), 1),
color.getHsvSaturation(),
color.getHsvValue());
return color;
}
}
@ -168,11 +168,11 @@ 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);
double hue = convertHueAngle(int(m_color.getHue()), -1) + harmonies[i].hues[j];
double sat = m_color.getSaturation() * harmonies[i].sats[j] / 100.0;
double hue = convertHueAngle(int(m_color.getHsvHue()), -1) + harmonies[i].hues[j];
double sat = m_color.getHsvSaturation() * harmonies[i].sats[j] / 100.0;
return app::Color::fromHsv(std::fmod(hue, 360),
MID(0.0, sat, 100.0),
m_color.getValue());
MID(0.0, sat, 1.0),
m_color.getHsvValue());
}
void ColorWheel::onResize(ui::ResizeEvent& ev)
@ -230,17 +230,17 @@ void ColorWheel::onPaint(ui::PaintEvent& ev)
for (int i=0; i<n; ++i) {
app::Color color = getColorInHarmony(i);
double angle = color.getHue()-30.0;
double dist = color.getSaturation();
double angle = color.getHsvHue()-30.0;
double dist = color.getHsvSaturation();
color = app::Color::fromHsv(convertHueAngle(int(color.getHue()), 1),
color.getSaturation(),
color.getValue());
color = app::Color::fromHsv(convertHueAngle(int(color.getHsvHue()), 1),
color.getHsvSaturation(),
color.getHsvValue());
gfx::Point pos =
m_wheelBounds.center() +
gfx::Point(int(+std::cos(PI*angle/180.0)*double(m_wheelRadius)*dist/100.0),
int(-std::sin(PI*angle/180.0)*double(m_wheelRadius)*dist/100.0));
gfx::Point(int(+std::cos(PI*angle/180.0)*double(m_wheelRadius)*dist),
int(-std::sin(PI*angle/180.0)*double(m_wheelRadius)*dist));
she::Surface* icon = theme->parts.colorWheelIndicator()->bitmap(0);
g->drawRgbaSurface(icon,

View File

@ -1249,8 +1249,10 @@ public:
m_channel.addItem("Alpha");
m_channel.addItem("RGB+Alpha");
m_channel.addItem("RGB");
m_channel.addItem("HSB+Alpha");
m_channel.addItem("HSB");
m_channel.addItem("HSV+Alpha");
m_channel.addItem("HSV");
m_channel.addItem("HSL+Alpha");
m_channel.addItem("HSL");
m_channel.addItem("Gray+Alpha");
m_channel.addItem("Gray");
m_channel.addItem("Best fit Index");

View File

@ -951,6 +951,7 @@ int PaletteView::findExactIndex(const app::Color& color) const
case Color::RgbType:
case Color::HsvType:
case Color::HslType:
case Color::GrayType:
return currentPalette()->findExactMatch(
color.getRed(), color.getGreen(), color.getBlue(), color.getAlpha(), -1);

View File

@ -33,6 +33,7 @@ HueSaturationFilter::HueSaturationFilter()
: m_h(0.0)
, m_s(0.0)
, m_l(0.0)
, m_a(0)
{
}
@ -51,6 +52,11 @@ void HueSaturationFilter::setLightness(double l)
m_l = l;
}
void HueSaturationFilter::setAlpha(int a)
{
m_a = a;
}
void HueSaturationFilter::applyToRgba(FilterManager* filterMgr)
{
const uint32_t* src_address = (uint32_t*)filterMgr->getSourceAddress();
@ -95,6 +101,9 @@ void HueSaturationFilter::applyToRgba(FilterManager* filterMgr)
if (target & TARGET_RED_CHANNEL ) r = rgb.red();
if (target & TARGET_GREEN_CHANNEL) g = rgb.green();
if (target & TARGET_BLUE_CHANNEL ) b = rgb.blue();
if (a && (target & TARGET_ALPHA_CHANNEL))
a = MID(0, a+m_a, 255);
}
*(dst_address++) = rgba(r, g, b, a);
@ -131,6 +140,9 @@ void HueSaturationFilter::applyToGrayscale(FilterManager* filterMgr)
gfx::Rgb rgb(hsl);
if (target & TARGET_GRAY_CHANNEL) k = rgb.red();
if (a && (target & TARGET_ALPHA_CHANNEL))
a = MID(0, a+m_a, 255);
}
*(dst_address++) = graya(k, a);
@ -182,6 +194,9 @@ void HueSaturationFilter::applyToIndexed(FilterManager* filterMgr)
if (target & TARGET_RED_CHANNEL ) r = rgb.red();
if (target & TARGET_GREEN_CHANNEL) g = rgb.green();
if (target & TARGET_BLUE_CHANNEL ) b = rgb.blue();
if (a && (target & TARGET_ALPHA_CHANNEL))
a = MID(0, a+m_a, 255);
}
c = rgbmap->mapColor(r, g, b, a);

View File

@ -19,6 +19,7 @@ namespace filters {
void setHue(double h);
void setSaturation(double s);
void setLightness(double v);
void setAlpha(int a);
// Filter implementation
const char* getName();
@ -28,6 +29,7 @@ namespace filters {
private:
double m_h, m_s, m_l;
int m_a;
};
} // namespace filters

View File

@ -18,16 +18,12 @@ using namespace std;
Hsl::Hsl(double hue, double saturation, double lightness)
: m_hue(hue)
, m_saturation(saturation)
, m_lightness(lightness)
, m_saturation(MID(0.0, saturation, 1.0))
, m_lightness(MID(0.0, lightness, 1.0))
{
while (m_hue < 0.0)
m_hue += 360.0;
m_hue = std::fmod(m_hue, 360.0);
assert(hue >= 0.0 && hue <= 360.0);
assert(saturation >= 0.0 && saturation <= 1.0);
assert(lightness >= 0.0 && lightness <= 1.0);
}
Hsl::Hsl(const Rgb& rgb)
@ -76,17 +72,17 @@ Hsl::Hsl(const Rgb& rgb)
int Hsl::hueInt() const
{
return int(floor(m_hue + 0.5));
return int(std::floor(m_hue + 0.5));
}
int Hsl::saturationInt() const
{
return int(floor(m_saturation*100.0 + 0.5));
return int(std::floor(m_saturation*100.0 + 0.5));
}
int Hsl::lightnessInt() const
{
return int(floor(m_lightness*100.0 + 0.5));
return int(std::floor(m_lightness*100.0 + 0.5));
}
} // namespace gfx

View File

@ -8,7 +8,7 @@
#define GFX_HSL_H_INCLUDED
#pragma once
#include <cassert>
#include "base/base.h" // MID
namespace gfx {
@ -48,18 +48,15 @@ public:
int lightnessInt() const;
void hue(double hue) {
assert(hue >= 0.0 && hue <= 360.0);
m_hue = hue;
m_hue = MID(0.0, hue, 360.0);
}
void saturation(double saturation) {
assert(saturation >= 0.0 && saturation <= 1.0);
m_saturation = saturation;
m_saturation = MID(0.0, saturation, 1.0);
}
void lightness(double lightness) {
assert(lightness >= 0.0 && lightness <= 1.0);
m_lightness = lightness;
m_lightness = MID(0.0, lightness, 1.0);
}
// The comparison is done through the integer value of each component.

View File

@ -18,16 +18,12 @@ using namespace std;
Hsv::Hsv(double hue, double saturation, double value)
: m_hue(hue)
, m_saturation(saturation)
, m_value(value)
, m_saturation(MID(0.0, saturation, 1.0))
, m_value(MID(0.0, value, 1.0))
{
while (m_hue < 0.0)
m_hue += 360.0;
m_hue = std::fmod(m_hue, 360.0);
assert(hue >= 0.0 && hue <= 360.0);
assert(saturation >= 0.0 && saturation <= 1.0);
assert(value >= 0.0 && value <= 1.0);
}
// Reference: http://en.wikipedia.org/wiki/HSL_and_HSV
@ -77,17 +73,17 @@ Hsv::Hsv(const Rgb& rgb)
int Hsv::hueInt() const
{
return int(floor(m_hue + 0.5));
return int(std::floor(m_hue + 0.5));
}
int Hsv::saturationInt() const
{
return int(floor(m_saturation*100.0 + 0.5));
return int(std::floor(m_saturation*100.0 + 0.5));
}
int Hsv::valueInt() const
{
return int(floor(m_value*100.0 + 0.5));
return int(std::floor(m_value*100.0 + 0.5));
}
} // namespace gfx

View File

@ -8,7 +8,7 @@
#define GFX_HSV_H_INCLUDED
#pragma once
#include <cassert>
#include "base/base.h" // MID
namespace gfx {
@ -48,18 +48,15 @@ public:
int valueInt() const;
void hue(double hue) {
assert(hue >= 0.0 && hue <= 360.0);
m_hue = hue;
m_hue = MID(0.0, hue, 360.0);
}
void saturation(double saturation) {
assert(saturation >= 0.0 && saturation <= 1.0);
m_saturation = saturation;
m_saturation = MID(0.0, saturation, 1.0);
}
void value(double value) {
assert(value >= 0.0 && value <= 1.0);
m_value = value;
m_value = MID(0.0, value, 1.0);
}
// The comparison is done through the integer value of each component.