mirror of
https://github.com/aseprite/aseprite.git
synced 2025-03-29 01:20:17 +00:00
Add alpha channel to palette/color bar/color selector (issue #286)
This commit is contained in:
parent
78918c0df8
commit
318bc2e2f9
@ -35,30 +35,33 @@ Color Color::fromMask()
|
||||
}
|
||||
|
||||
// static
|
||||
Color Color::fromRgb(int r, int g, int b)
|
||||
Color Color::fromRgb(int r, int g, int b, int a)
|
||||
{
|
||||
Color color(Color::RgbType);
|
||||
color.m_value.rgb.r = r;
|
||||
color.m_value.rgb.g = g;
|
||||
color.m_value.rgb.b = b;
|
||||
color.m_value.rgb.a = a;
|
||||
return color;
|
||||
}
|
||||
|
||||
// static
|
||||
Color Color::fromHsv(int h, int s, int v)
|
||||
Color Color::fromHsv(int h, int s, int v, int a)
|
||||
{
|
||||
Color color(Color::HsvType);
|
||||
color.m_value.hsv.h = h;
|
||||
color.m_value.hsv.s = s;
|
||||
color.m_value.hsv.v = v;
|
||||
color.m_value.hsv.a = a;
|
||||
return color;
|
||||
}
|
||||
|
||||
// static
|
||||
Color Color::fromGray(int g)
|
||||
Color Color::fromGray(int g, int a)
|
||||
{
|
||||
Color color(Color::GrayType);
|
||||
color.m_value.gray = g;
|
||||
color.m_value.gray.g = g;
|
||||
color.m_value.gray.a = a;
|
||||
return color;
|
||||
}
|
||||
|
||||
@ -83,13 +86,15 @@ Color Color::fromImage(PixelFormat pixelFormat, color_t c)
|
||||
if (rgba_geta(c) > 0) {
|
||||
color = Color::fromRgb(rgba_getr(c),
|
||||
rgba_getg(c),
|
||||
rgba_getb(c));
|
||||
rgba_getb(c),
|
||||
rgba_geta(c));
|
||||
}
|
||||
break;
|
||||
|
||||
case IMAGE_GRAYSCALE:
|
||||
if (graya_geta(c) > 0) {
|
||||
color = Color::fromGray(graya_getv(c));
|
||||
color = Color::fromGray(graya_getv(c),
|
||||
graya_geta(c));
|
||||
}
|
||||
break;
|
||||
|
||||
@ -117,26 +122,26 @@ Color Color::fromString(const std::string& str)
|
||||
|
||||
if (str != "mask") {
|
||||
if (str.find("rgb{") == 0 ||
|
||||
str.find("hsv{") == 0) {
|
||||
int c = 0, table[3] = { 0, 0, 0 };
|
||||
str.find("hsv{") == 0 ||
|
||||
str.find("gray{") == 0) {
|
||||
int c = 0, table[4] = { 0, 0, 0, 255 };
|
||||
std::string::size_type i = 4, j;
|
||||
|
||||
while ((j = str.find_first_of(",}", i)) != std::string::npos) {
|
||||
std::string element = str.substr(i, j - i);
|
||||
if (c < 3)
|
||||
if (c < 4)
|
||||
table[c++] = std::strtol(element.c_str(), NULL, 10);
|
||||
if (c >= 3)
|
||||
if (c >= 4)
|
||||
break;
|
||||
i = j+1;
|
||||
}
|
||||
|
||||
if (str[0] == 'r')
|
||||
color = Color::fromRgb(table[0], table[1], table[2]);
|
||||
else
|
||||
color = Color::fromHsv(table[0], table[1], table[2]);
|
||||
}
|
||||
else if (str.find("gray{") == 0) {
|
||||
color = Color::fromGray(std::strtol(str.c_str()+5, NULL, 10));
|
||||
color = Color::fromRgb(table[0], table[1], table[2], table[3]);
|
||||
else if (str[0] == 'h')
|
||||
color = Color::fromHsv(table[0], table[1], table[2], table[3]);
|
||||
else if (str[0] == 'g')
|
||||
color = Color::fromGray(table[0], c >= 2 ? table[1]: 255);
|
||||
}
|
||||
else if (str.find("index{") == 0) {
|
||||
color = Color::fromIndex(std::strtol(str.c_str()+6, NULL, 10));
|
||||
@ -160,18 +165,22 @@ std::string Color::toString() const
|
||||
result << "rgb{"
|
||||
<< m_value.rgb.r << ","
|
||||
<< m_value.rgb.g << ","
|
||||
<< m_value.rgb.b << "}";
|
||||
<< m_value.rgb.b << ","
|
||||
<< m_value.rgb.a << "}";
|
||||
break;
|
||||
|
||||
case Color::HsvType:
|
||||
result << "hsv{"
|
||||
<< m_value.hsv.h << ","
|
||||
<< m_value.hsv.s << ","
|
||||
<< m_value.hsv.v << "}";
|
||||
<< m_value.hsv.v << ","
|
||||
<< m_value.hsv.a << "}";
|
||||
break;
|
||||
|
||||
case Color::GrayType:
|
||||
result << "gray{" << m_value.gray << "}";
|
||||
result << "gray{"
|
||||
<< m_value.gray.g << ","
|
||||
<< m_value.gray.a << "}";
|
||||
break;
|
||||
|
||||
case Color::IndexType:
|
||||
@ -226,7 +235,7 @@ std::string Color::toHumanReadableString(PixelFormat pixelFormat, HumanReadableS
|
||||
break;
|
||||
|
||||
case Color::GrayType:
|
||||
result << "Gray " << m_value.gray;
|
||||
result << "Gray " << m_value.gray.g;
|
||||
break;
|
||||
|
||||
case Color::IndexType: {
|
||||
@ -288,7 +297,7 @@ std::string Color::toHumanReadableString(PixelFormat pixelFormat, HumanReadableS
|
||||
break;
|
||||
|
||||
case Color::GrayType:
|
||||
result << "Gry-" << m_value.gray;
|
||||
result << "Gry-" << m_value.gray.g;
|
||||
break;
|
||||
|
||||
case Color::IndexType:
|
||||
@ -318,16 +327,20 @@ bool Color::operator==(const Color& other) const
|
||||
return
|
||||
m_value.rgb.r == other.m_value.rgb.r &&
|
||||
m_value.rgb.g == other.m_value.rgb.g &&
|
||||
m_value.rgb.b == other.m_value.rgb.b;
|
||||
m_value.rgb.b == other.m_value.rgb.b &&
|
||||
m_value.rgb.a == other.m_value.rgb.a;
|
||||
|
||||
case Color::HsvType:
|
||||
return
|
||||
m_value.hsv.h == other.m_value.hsv.h &&
|
||||
m_value.hsv.s == other.m_value.hsv.s &&
|
||||
m_value.hsv.v == other.m_value.hsv.v;
|
||||
m_value.hsv.v == other.m_value.hsv.v &&
|
||||
m_value.hsv.a == other.m_value.hsv.a;
|
||||
|
||||
case Color::GrayType:
|
||||
return m_value.gray == other.m_value.gray;
|
||||
return
|
||||
m_value.gray.g == other.m_value.gray.g &&
|
||||
m_value.gray.a == other.m_value.gray.a;
|
||||
|
||||
case Color::IndexType:
|
||||
return m_value.index == other.m_value.index;
|
||||
@ -370,7 +383,7 @@ int Color::getRed() const
|
||||
double(m_value.hsv.v) / 100.0)).red();
|
||||
|
||||
case Color::GrayType:
|
||||
return m_value.gray;
|
||||
return m_value.gray.g;
|
||||
|
||||
case Color::IndexType: {
|
||||
int i = m_value.index;
|
||||
@ -402,7 +415,7 @@ int Color::getGreen() const
|
||||
double(m_value.hsv.v) / 100.0)).green();
|
||||
|
||||
case Color::GrayType:
|
||||
return m_value.gray;
|
||||
return m_value.gray.g;
|
||||
|
||||
case Color::IndexType: {
|
||||
int i = m_value.index;
|
||||
@ -434,7 +447,7 @@ int Color::getBlue() const
|
||||
double(m_value.hsv.v) / 100.0)).blue();
|
||||
|
||||
case Color::GrayType:
|
||||
return m_value.gray;
|
||||
return m_value.gray.g;
|
||||
|
||||
case Color::IndexType: {
|
||||
int i = m_value.index;
|
||||
@ -538,7 +551,7 @@ int Color::getValue() const
|
||||
return m_value.hsv.v;
|
||||
|
||||
case Color::GrayType:
|
||||
return 100 * m_value.gray / 255;
|
||||
return 100 * m_value.gray.g / 255;
|
||||
|
||||
case Color::IndexType: {
|
||||
int i = m_value.index;
|
||||
@ -574,7 +587,7 @@ int Color::getGray() const
|
||||
return 255 * m_value.hsv.v / 100;
|
||||
|
||||
case Color::GrayType:
|
||||
return m_value.gray;
|
||||
return m_value.gray.g;
|
||||
|
||||
case Color::IndexType: {
|
||||
int i = m_value.index;
|
||||
@ -602,13 +615,9 @@ int Color::getIndex() const
|
||||
return 0;
|
||||
|
||||
case Color::RgbType:
|
||||
return get_current_palette()->findBestfit(getRed(), getGreen(), getBlue());
|
||||
|
||||
case Color::HsvType:
|
||||
return get_current_palette()->findBestfit(getRed(), getGreen(), getBlue());
|
||||
|
||||
case Color::GrayType:
|
||||
return m_value.gray;
|
||||
return get_current_palette()->findBestfit(getRed(), getGreen(), getBlue(), getAlpha(), 0);
|
||||
|
||||
case Color::IndexType:
|
||||
return m_value.index;
|
||||
@ -619,4 +628,34 @@ int Color::getIndex() const
|
||||
return -1;
|
||||
}
|
||||
|
||||
int Color::getAlpha() const
|
||||
{
|
||||
switch (getType()) {
|
||||
|
||||
case Color::MaskType:
|
||||
return 0;
|
||||
|
||||
case Color::RgbType:
|
||||
return m_value.rgb.a;
|
||||
|
||||
case Color::HsvType:
|
||||
return m_value.hsv.a;
|
||||
|
||||
case Color::GrayType:
|
||||
return m_value.gray.a;
|
||||
|
||||
case Color::IndexType: {
|
||||
int i = m_value.index;
|
||||
if (i >= 0 && i < get_current_palette()->size())
|
||||
return rgba_geta(get_current_palette()->getEntry(i));
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
ASSERT(false);
|
||||
return -1;
|
||||
}
|
||||
|
||||
} // namespace app
|
||||
|
@ -42,9 +42,9 @@ namespace app {
|
||||
Color() : m_type(MaskType) { }
|
||||
|
||||
static Color fromMask();
|
||||
static Color fromRgb(int r, int g, int b);
|
||||
static Color fromHsv(int h, int s, int v); // h=[0,360], s=[0,100], v=[0,100]
|
||||
static Color fromGray(int g);
|
||||
static Color fromRgb(int r, int g, int b, int a = 255);
|
||||
static Color fromHsv(int h, int s, int v, int a = 255); // h=[0,360], s=[0,100], v=[0,100]
|
||||
static Color fromGray(int g, int a = 255);
|
||||
static Color fromIndex(int index);
|
||||
|
||||
static Color fromImage(PixelFormat pixelFormat, color_t c);
|
||||
@ -74,6 +74,7 @@ namespace app {
|
||||
int getValue() const;
|
||||
int getGray() const;
|
||||
int getIndex() const;
|
||||
int getAlpha() const;
|
||||
|
||||
private:
|
||||
Color(Type type) : m_type(type) { }
|
||||
@ -84,12 +85,14 @@ namespace app {
|
||||
// Color value
|
||||
union {
|
||||
struct {
|
||||
int r, g, b;
|
||||
int r, g, b, a;
|
||||
} rgb;
|
||||
struct {
|
||||
int h, s, v;
|
||||
int h, s, v, a;
|
||||
} hsv;
|
||||
int gray;
|
||||
struct {
|
||||
int g, a;
|
||||
} gray;
|
||||
int index;
|
||||
} m_value;
|
||||
};
|
||||
|
@ -52,14 +52,16 @@ gfx::Color color_utils::color_for_ui(const app::Color& color)
|
||||
c = gfx::rgba(
|
||||
color.getRed(),
|
||||
color.getGreen(),
|
||||
color.getBlue(), 255);
|
||||
color.getBlue(),
|
||||
color.getAlpha());
|
||||
break;
|
||||
|
||||
case app::Color::GrayType:
|
||||
c = gfx::rgba(
|
||||
color.getGray(),
|
||||
color.getGray(),
|
||||
color.getGray(), 255);
|
||||
color.getGray(),
|
||||
color.getAlpha());
|
||||
break;
|
||||
|
||||
case app::Color::IndexType: {
|
||||
@ -70,7 +72,8 @@ gfx::Color color_utils::color_for_ui(const app::Color& color)
|
||||
c = gfx::rgba(
|
||||
rgba_getr(_c),
|
||||
rgba_getg(_c),
|
||||
rgba_getb(_c), 255);
|
||||
rgba_getb(_c),
|
||||
color.getAlpha());
|
||||
break;
|
||||
}
|
||||
|
||||
@ -116,10 +119,10 @@ doc::color_t color_utils::color_for_target_mask(const app::Color& color, const C
|
||||
else {
|
||||
switch (colorTarget.pixelFormat()) {
|
||||
case IMAGE_RGB:
|
||||
c = doc::rgba(color.getRed(), color.getGreen(), color.getBlue(), 255);
|
||||
c = doc::rgba(color.getRed(), color.getGreen(), color.getBlue(), color.getAlpha());
|
||||
break;
|
||||
case IMAGE_GRAYSCALE:
|
||||
c = doc::graya(color.getGray(), 255);
|
||||
c = doc::graya(color.getGray(), color.getAlpha());
|
||||
break;
|
||||
case IMAGE_INDEXED:
|
||||
if (color.getType() == app::Color::IndexType) {
|
||||
@ -130,6 +133,7 @@ doc::color_t color_utils::color_for_target_mask(const app::Color& color, const C
|
||||
color.getRed(),
|
||||
color.getGreen(),
|
||||
color.getBlue(),
|
||||
color.getAlpha(),
|
||||
colorTarget.isTransparent() ?
|
||||
colorTarget.maskColor(): // Don't return the mask color
|
||||
-1); // Return any color, we are in a background layer.
|
||||
|
@ -497,7 +497,7 @@ void PaletteEntryEditor::setAbsolutePaletteEntryChannel(ColorSliders::Channel ch
|
||||
int picksCount = entries.picks();
|
||||
|
||||
uint32_t src_color;
|
||||
int r, g, b;
|
||||
int r, g, b, a;
|
||||
|
||||
Palette* palette = get_current_palette();
|
||||
for (int c=0; c<palette->size(); c++) {
|
||||
@ -509,6 +509,7 @@ void PaletteEntryEditor::setAbsolutePaletteEntryChannel(ColorSliders::Channel ch
|
||||
r = rgba_getr(src_color);
|
||||
g = rgba_getg(src_color);
|
||||
b = rgba_getb(src_color);
|
||||
a = rgba_geta(src_color);
|
||||
|
||||
switch (m_type) {
|
||||
|
||||
@ -518,6 +519,7 @@ void PaletteEntryEditor::setAbsolutePaletteEntryChannel(ColorSliders::Channel ch
|
||||
r = color.getRed();
|
||||
g = color.getGreen();
|
||||
b = color.getBlue();
|
||||
a = color.getAlpha();
|
||||
}
|
||||
// Modify one channel a set of entries
|
||||
else {
|
||||
@ -531,6 +533,9 @@ void PaletteEntryEditor::setAbsolutePaletteEntryChannel(ColorSliders::Channel ch
|
||||
case ColorSliders::Blue:
|
||||
b = color.getBlue();
|
||||
break;
|
||||
case ColorSliders::Alpha:
|
||||
a = color.getAlpha();
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
@ -561,6 +566,9 @@ void PaletteEntryEditor::setAbsolutePaletteEntryChannel(ColorSliders::Channel ch
|
||||
case ColorSliders::Value:
|
||||
hsv.value(double(color.getValue()) / 100.0);
|
||||
break;
|
||||
case ColorSliders::Alpha:
|
||||
a = color.getAlpha();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -573,7 +581,7 @@ void PaletteEntryEditor::setAbsolutePaletteEntryChannel(ColorSliders::Channel ch
|
||||
break;
|
||||
}
|
||||
|
||||
palette->setEntry(c, doc::rgba(r, g, b, 255));
|
||||
palette->setEntry(c, doc::rgba(r, g, b, a));
|
||||
}
|
||||
}
|
||||
|
||||
@ -586,7 +594,7 @@ void PaletteEntryEditor::setRelativePaletteEntryChannel(ColorSliders::Channel ch
|
||||
m_relDeltas[channel] = delta;
|
||||
|
||||
uint32_t src_color;
|
||||
int r, g, b;
|
||||
int r, g, b, a;
|
||||
|
||||
Palette* palette = get_current_palette();
|
||||
for (int c=0; c<palette->size(); c++) {
|
||||
@ -598,6 +606,7 @@ void PaletteEntryEditor::setRelativePaletteEntryChannel(ColorSliders::Channel ch
|
||||
r = rgba_getr(src_color);
|
||||
g = rgba_getg(src_color);
|
||||
b = rgba_getb(src_color);
|
||||
a = rgba_geta(src_color);
|
||||
|
||||
switch (m_type) {
|
||||
|
||||
@ -605,6 +614,7 @@ void PaletteEntryEditor::setRelativePaletteEntryChannel(ColorSliders::Channel ch
|
||||
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);
|
||||
a = MID(0, a+m_relDeltas[ColorSliders::Alpha], 255);
|
||||
break;
|
||||
|
||||
case app::Color::HsvType: {
|
||||
@ -627,12 +637,13 @@ void PaletteEntryEditor::setRelativePaletteEntryChannel(ColorSliders::Channel ch
|
||||
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, 255));
|
||||
palette->setEntry(c, doc::rgba(r, g, b, a));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -666,9 +666,7 @@ static Palette* ase_file_read_palette_chunk(FILE* f, Palette* prevPal, frame_t f
|
||||
int g = fgetc(f);
|
||||
int b = fgetc(f);
|
||||
int a = fgetc(f);
|
||||
|
||||
// TODO don't ignore alpha
|
||||
pal->setEntry(c, rgba(r, g, b, 255));
|
||||
pal->setEntry(c, rgba(r, g, b, a));
|
||||
|
||||
// Skip name
|
||||
if (flags & 1) {
|
||||
|
@ -62,33 +62,38 @@ static void rectgrid(ui::Graphics* g, const gfx::Rect& rc, const gfx::Size& tile
|
||||
}
|
||||
}
|
||||
|
||||
static void draw_color(ui::Graphics* g, const Rect& rc, const app::Color& color)
|
||||
void draw_color(ui::Graphics* g, const Rect& rc, const app::Color& color)
|
||||
{
|
||||
if (rc.w < 1 || rc.h < 1)
|
||||
return;
|
||||
|
||||
app::Color::Type type = color.getType();
|
||||
int alpha = color.getAlpha();
|
||||
|
||||
if (type == app::Color::MaskType) {
|
||||
rectgrid(g, rc, gfx::Size(rc.w/4, rc.h/2));
|
||||
return;
|
||||
if (alpha < 255) {
|
||||
if (rc.w == rc.h)
|
||||
rectgrid(g, rc, gfx::Size(rc.w/2, rc.h/2));
|
||||
else
|
||||
rectgrid(g, rc, gfx::Size(rc.w/4, rc.h/2));
|
||||
}
|
||||
else if (type == app::Color::IndexType) {
|
||||
int index = color.getIndex();
|
||||
|
||||
if (index >= 0 && index < get_current_palette()->size()) {
|
||||
if (alpha > 0) {
|
||||
if (type == app::Color::IndexType) {
|
||||
int index = color.getIndex();
|
||||
|
||||
if (index >= 0 && index < get_current_palette()->size()) {
|
||||
g->fillRect(color_utils::color_for_ui(color), rc);
|
||||
}
|
||||
else {
|
||||
g->fillRect(gfx::rgba(0, 0, 0), rc);
|
||||
g->drawLine(gfx::rgba(255, 255, 255),
|
||||
gfx::Point(rc.x+rc.w-2, rc.y+1),
|
||||
gfx::Point(rc.x+1, rc.y+rc.h-2));
|
||||
}
|
||||
}
|
||||
else
|
||||
g->fillRect(color_utils::color_for_ui(color), rc);
|
||||
}
|
||||
else {
|
||||
g->fillRect(gfx::rgba(0, 0, 0), rc);
|
||||
g->drawLine(gfx::rgba(255, 255, 255),
|
||||
gfx::Point(rc.x+rc.w-2, rc.y+1),
|
||||
gfx::Point(rc.x+1, rc.y+rc.h-2));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
g->fillRect(color_utils::color_for_ui(color), rc);
|
||||
}
|
||||
|
||||
void draw_color_button(ui::Graphics* g,
|
||||
|
@ -18,6 +18,9 @@
|
||||
namespace app {
|
||||
using namespace doc;
|
||||
|
||||
void draw_color(ui::Graphics* g,
|
||||
const gfx::Rect& rc, const app::Color& color);
|
||||
|
||||
void draw_color_button(ui::Graphics* g,
|
||||
const gfx::Rect& rc, const app::Color& color,
|
||||
bool hot, bool drag);
|
||||
|
@ -819,7 +819,7 @@ void BrushInkProcessing<IndexedTraits>::processPixel(int x, int y) {
|
||||
switch (m_brushImage->pixelFormat()) {
|
||||
case IMAGE_RGB: {
|
||||
c = get_pixel_fast<RgbTraits>(m_brushImage, x, y);
|
||||
c = m_palette->findBestfit(rgba_getr(c), rgba_getg(c), rgba_getb(c));
|
||||
c = m_palette->findBestfit(rgba_getr(c), rgba_getg(c), rgba_getb(c), rgba_geta(c), 0);
|
||||
break;
|
||||
}
|
||||
case IMAGE_INDEXED: {
|
||||
@ -828,8 +828,7 @@ void BrushInkProcessing<IndexedTraits>::processPixel(int x, int y) {
|
||||
}
|
||||
case IMAGE_GRAYSCALE: {
|
||||
c = get_pixel_fast<GrayscaleTraits>(m_brushImage, x, y);
|
||||
c = graya_getv(c);
|
||||
c = m_palette->findBestfit(c, c, c);
|
||||
c = m_palette->findBestfit(graya_getv(c), graya_getv(c), graya_getv(c), graya_geta(c), 0);
|
||||
break;
|
||||
}
|
||||
case IMAGE_BITMAP: {
|
||||
|
@ -805,11 +805,13 @@ void ColorBar::onFixWarningClick(ColorButton* colorButton, ui::Button* warningIc
|
||||
color_t color = doc::rgba(
|
||||
appColor.getRed(),
|
||||
appColor.getGreen(),
|
||||
appColor.getBlue(), 255);
|
||||
appColor.getBlue(),
|
||||
appColor.getAlpha());
|
||||
int index = newPalette->findExactMatch(
|
||||
appColor.getRed(),
|
||||
appColor.getGreen(),
|
||||
appColor.getBlue());
|
||||
appColor.getBlue(),
|
||||
appColor.getAlpha());
|
||||
|
||||
// It should be -1, because the user has pressed the warning
|
||||
// button that is available only when the color isn't in the
|
||||
@ -853,7 +855,8 @@ void ColorBar::updateWarningIcon(const app::Color& color, ui::Button* warningIco
|
||||
int index = get_current_palette()->findExactMatch(
|
||||
color.getRed(),
|
||||
color.getGreen(),
|
||||
color.getBlue());
|
||||
color.getBlue(),
|
||||
color.getAlpha());
|
||||
|
||||
warningIcon->setVisible(index < 0);
|
||||
warningIcon->getParent()->layout();
|
||||
|
@ -159,20 +159,27 @@ void ColorSelector::onColorHexEntryChange(const app::Color& color)
|
||||
|
||||
void ColorSelector::onColorTypeClick()
|
||||
{
|
||||
app::Color newColor;
|
||||
app::Color newColor = getColor();
|
||||
|
||||
switch (m_colorType.selectedItem()) {
|
||||
case INDEX_MODE:
|
||||
newColor = app::Color::fromIndex(getColor().getIndex());
|
||||
newColor = app::Color::fromIndex(newColor.getIndex());
|
||||
break;
|
||||
case RGB_MODE:
|
||||
newColor = app::Color::fromRgb(getColor().getRed(), getColor().getGreen(), getColor().getBlue());
|
||||
newColor = app::Color::fromRgb(newColor.getRed(),
|
||||
newColor.getGreen(),
|
||||
newColor.getBlue(),
|
||||
newColor.getAlpha());
|
||||
break;
|
||||
case HSB_MODE:
|
||||
newColor = app::Color::fromHsv(getColor().getHue(), getColor().getSaturation(), getColor().getValue());
|
||||
newColor = app::Color::fromHsv(newColor.getHue(),
|
||||
newColor.getSaturation(),
|
||||
newColor.getValue(),
|
||||
newColor.getAlpha());
|
||||
break;
|
||||
case GRAY_MODE:
|
||||
newColor = app::Color::fromGray(getColor().getGray());
|
||||
newColor = app::Color::fromGray(newColor.getGray(),
|
||||
newColor.getAlpha());
|
||||
break;
|
||||
case MASK_MODE:
|
||||
newColor = app::Color::fromMask();
|
||||
@ -194,10 +201,11 @@ void ColorSelector::findBestfitIndex(const app::Color& color)
|
||||
int r = color.getRed();
|
||||
int g = color.getGreen();
|
||||
int b = color.getBlue();
|
||||
int a = color.getAlpha();
|
||||
|
||||
// Search for the closest color to the RGB values
|
||||
int i = get_current_palette()->findBestfit(r, g, b);
|
||||
if (i >= 0 && i < 256) {
|
||||
int i = get_current_palette()->findBestfit(r, g, b, a, 0);
|
||||
if (i >= 0) {
|
||||
m_colorPalette.deselect();
|
||||
m_colorPalette.selectColor(i);
|
||||
}
|
||||
|
@ -237,6 +237,7 @@ RgbSliders::RgbSliders()
|
||||
addSlider(Red, "R", 0, 255);
|
||||
addSlider(Green, "G", 0, 255);
|
||||
addSlider(Blue, "B", 0, 255);
|
||||
addSlider(Alpha, "A", 0, 255);
|
||||
}
|
||||
|
||||
void RgbSliders::onSetColor(const app::Color& color)
|
||||
@ -244,13 +245,15 @@ void RgbSliders::onSetColor(const app::Color& color)
|
||||
setAbsSliderValue(0, color.getRed());
|
||||
setAbsSliderValue(1, color.getGreen());
|
||||
setAbsSliderValue(2, color.getBlue());
|
||||
setAbsSliderValue(3, color.getAlpha());
|
||||
}
|
||||
|
||||
app::Color RgbSliders::getColorFromSliders()
|
||||
{
|
||||
return app::Color::fromRgb(getAbsSliderValue(0),
|
||||
getAbsSliderValue(1),
|
||||
getAbsSliderValue(2));
|
||||
getAbsSliderValue(2),
|
||||
getAbsSliderValue(3));
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
@ -262,6 +265,7 @@ HsvSliders::HsvSliders()
|
||||
addSlider(Hue, "H", 0, 360);
|
||||
addSlider(Saturation, "S", 0, 100);
|
||||
addSlider(Value, "B", 0, 100);
|
||||
addSlider(Alpha, "A", 0, 255);
|
||||
}
|
||||
|
||||
void HsvSliders::onSetColor(const app::Color& color)
|
||||
@ -269,13 +273,15 @@ void HsvSliders::onSetColor(const app::Color& color)
|
||||
setAbsSliderValue(0, color.getHue());
|
||||
setAbsSliderValue(1, color.getSaturation());
|
||||
setAbsSliderValue(2, color.getValue());
|
||||
setAbsSliderValue(3, color.getAlpha());
|
||||
}
|
||||
|
||||
app::Color HsvSliders::getColorFromSliders()
|
||||
{
|
||||
return app::Color::fromHsv(getAbsSliderValue(0),
|
||||
getAbsSliderValue(1),
|
||||
getAbsSliderValue(2));
|
||||
getAbsSliderValue(2),
|
||||
getAbsSliderValue(3));
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
@ -284,18 +290,20 @@ app::Color HsvSliders::getColorFromSliders()
|
||||
GraySlider::GraySlider()
|
||||
: ColorSliders()
|
||||
{
|
||||
addSlider(Gray, "V", 0, 255);
|
||||
addSlider(Gray, "V", 0, 255);
|
||||
addSlider(Alpha, "A", 0, 255);
|
||||
}
|
||||
|
||||
void GraySlider::onSetColor(const app::Color& color)
|
||||
{
|
||||
setAbsSliderValue(0, color.getGray());
|
||||
setAbsSliderValue(1, color.getAlpha());
|
||||
}
|
||||
|
||||
|
||||
app::Color GraySlider::getColorFromSliders()
|
||||
{
|
||||
return app::Color::fromGray(getAbsSliderValue(0));
|
||||
return app::Color::fromGray(getAbsSliderValue(0),
|
||||
getAbsSliderValue(1));
|
||||
}
|
||||
|
||||
} // namespace app
|
||||
|
@ -31,7 +31,8 @@ namespace app {
|
||||
public:
|
||||
enum Channel { Red, Green, Blue,
|
||||
Hue, Saturation, Value,
|
||||
Gray };
|
||||
Gray,
|
||||
Alpha };
|
||||
enum Mode { Absolute, Relative };
|
||||
|
||||
ColorSliders();
|
||||
|
@ -14,6 +14,7 @@
|
||||
#include "app/color_utils.h"
|
||||
#include "app/commands/commands.h"
|
||||
#include "app/modules/editors.h"
|
||||
#include "app/modules/gfx.h"
|
||||
#include "app/modules/gui.h"
|
||||
#include "app/modules/palettes.h"
|
||||
#include "app/ui/editor/editor.h"
|
||||
@ -422,37 +423,44 @@ void PaletteView::onPaint(ui::PaintEvent& ev)
|
||||
// Draw palette entries
|
||||
for (int i=0; i<palette->size(); ++i) {
|
||||
gfx::Rect box = getPaletteEntryBounds(i);
|
||||
gfx::Color color = gfx::rgba(
|
||||
rgba_getr(palette->getEntry(i)),
|
||||
rgba_getg(palette->getEntry(i)),
|
||||
rgba_getb(palette->getEntry(i)));
|
||||
doc::color_t palColor = palette->getEntry(i);
|
||||
app::Color appColor = app::Color::fromRgb(
|
||||
rgba_getr(palColor),
|
||||
rgba_getg(palColor),
|
||||
rgba_getb(palColor),
|
||||
rgba_geta(palColor));
|
||||
gfx::Color gfxColor = gfx::rgba(
|
||||
rgba_getr(palColor),
|
||||
rgba_getg(palColor),
|
||||
rgba_getb(palColor),
|
||||
rgba_geta(palColor));
|
||||
|
||||
g->drawRect(gfx::rgba(0, 0, 0), gfx::Rect(box).enlarge(guiscale()));
|
||||
g->fillRect(color, box);
|
||||
draw_color(g, box, appColor);
|
||||
|
||||
switch (m_style) {
|
||||
|
||||
case SelectOneColor:
|
||||
if (m_currentEntry == i)
|
||||
g->fillRect(color_utils::blackandwhite_neg(color),
|
||||
g->fillRect(color_utils::blackandwhite_neg(gfxColor),
|
||||
gfx::Rect(box.getCenter(), gfx::Size(1, 1)));
|
||||
break;
|
||||
|
||||
case FgBgColors:
|
||||
if (fgIndex == i) {
|
||||
gfx::Color neg = color_utils::blackandwhite_neg(color);
|
||||
gfx::Color neg = color_utils::blackandwhite_neg(gfxColor);
|
||||
for (int i=0; i<m_boxsize/2; ++i)
|
||||
g->drawHLine(neg, box.x, box.y+i, m_boxsize/2-i);
|
||||
}
|
||||
|
||||
if (bgIndex == i) {
|
||||
gfx::Color neg = color_utils::blackandwhite_neg(color);
|
||||
gfx::Color neg = color_utils::blackandwhite_neg(gfxColor);
|
||||
for (int i=0; i<m_boxsize/4; ++i)
|
||||
g->drawHLine(neg, box.x+box.w-(i+1), box.y+box.h-m_boxsize/4+i, i+1);
|
||||
}
|
||||
|
||||
if (transparentIndex == i)
|
||||
g->fillRect(color_utils::blackandwhite_neg(color),
|
||||
g->fillRect(color_utils::blackandwhite_neg(gfxColor),
|
||||
gfx::Rect(box.getCenter(), gfx::Size(1, 1)));
|
||||
break;
|
||||
}
|
||||
@ -804,7 +812,7 @@ int PaletteView::findExactIndex(const app::Color& color) const
|
||||
case Color::RgbType:
|
||||
case Color::HsvType:
|
||||
case Color::GrayType:
|
||||
return currentPalette()->findExactMatch(color.getRed(), color.getGreen(), color.getBlue());
|
||||
return currentPalette()->findExactMatch(color.getRed(), color.getGreen(), color.getBlue(), color.getAlpha());
|
||||
|
||||
case Color::IndexType:
|
||||
return color.getIndex();
|
||||
|
@ -142,9 +142,9 @@ void Palette::makeBlack()
|
||||
// Creates a linear ramp in the palette.
|
||||
void Palette::makeGradient(int from, int to)
|
||||
{
|
||||
int r, g, b;
|
||||
int r1, g1, b1;
|
||||
int r2, g2, b2;
|
||||
int r, g, b, a;
|
||||
int r1, g1, b1, a1;
|
||||
int r2, g2, b2, a2;
|
||||
int i, n;
|
||||
|
||||
ASSERT(from >= 0 && from <= 255);
|
||||
@ -160,22 +160,27 @@ void Palette::makeGradient(int from, int to)
|
||||
r1 = rgba_getr(getEntry(from));
|
||||
g1 = rgba_getg(getEntry(from));
|
||||
b1 = rgba_getb(getEntry(from));
|
||||
a1 = rgba_geta(getEntry(from));
|
||||
|
||||
r2 = rgba_getr(getEntry(to));
|
||||
g2 = rgba_getg(getEntry(to));
|
||||
b2 = rgba_getb(getEntry(to));
|
||||
a2 = rgba_geta(getEntry(to));
|
||||
|
||||
for (i=from+1; i<to; ++i) {
|
||||
r = r1 + (r2-r1) * (i-from) / n;
|
||||
g = g1 + (g2-g1) * (i-from) / n;
|
||||
b = b1 + (b2-b1) * (i-from) / n;
|
||||
setEntry(i, rgba(r, g, b, 255));
|
||||
a = a1 + (a2-a1) * (i-from) / n;
|
||||
|
||||
setEntry(i, rgba(r, g, b, a));
|
||||
}
|
||||
}
|
||||
|
||||
int Palette::findExactMatch(int r, int g, int b) const
|
||||
int Palette::findExactMatch(int r, int g, int b, int a) const
|
||||
{
|
||||
for (int i=0; i<(int)m_colors.size(); ++i)
|
||||
if (getEntry(i) == rgba(r, g, b, 255))
|
||||
if (getEntry(i) == rgba(r, g, b, a))
|
||||
return i;
|
||||
|
||||
return -1;
|
||||
@ -198,18 +203,14 @@ static void bestfit_init()
|
||||
}
|
||||
}
|
||||
|
||||
int Palette::findBestfit(int r, int g, int b, int mask_index) const
|
||||
int Palette::findBestfit(int r, int g, int b, int a, int mask_index) const
|
||||
{
|
||||
#ifdef __GNUC__
|
||||
register int bestfit asm("%eax");
|
||||
#else
|
||||
register int bestfit;
|
||||
#endif
|
||||
int i, coldiff, lowest;
|
||||
int i, bestfit, coldiff, lowest;
|
||||
|
||||
ASSERT(r >= 0 && r <= 255);
|
||||
ASSERT(g >= 0 && g <= 255);
|
||||
ASSERT(b >= 0 && b <= 255);
|
||||
ASSERT(a >= 0 && a <= 255);
|
||||
|
||||
if (col_diff[1] == 0)
|
||||
bestfit_init();
|
||||
|
@ -77,8 +77,8 @@ namespace doc {
|
||||
|
||||
void makeGradient(int from, int to);
|
||||
|
||||
int findExactMatch(int r, int g, int b) const;
|
||||
int findBestfit(int r, int g, int b, int mask_index = 0) const;
|
||||
int findExactMatch(int r, int g, int b, int a) const;
|
||||
int findBestfit(int r, int g, int b, int a, int mask_index) const;
|
||||
|
||||
private:
|
||||
frame_t m_frame;
|
||||
|
@ -44,7 +44,7 @@ void RgbMap::regenerate(const Palette* palette, int mask_index)
|
||||
palette->findBestfit(
|
||||
scale_5bits_to_8bits(r),
|
||||
scale_5bits_to_8bits(g),
|
||||
scale_5bits_to_8bits(b), mask_index);
|
||||
scale_5bits_to_8bits(b), 255, mask_index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -90,7 +90,7 @@ namespace render {
|
||||
int b = doc::rgba_getb(color);
|
||||
doc::color_t nearest1idx =
|
||||
(rgbmap ? rgbmap->mapColor(r, g, b):
|
||||
palette->findBestfit(r, g, b, m_transparentIndex));
|
||||
palette->findBestfit(r, g, b, 255, m_transparentIndex));
|
||||
|
||||
doc::color_t nearest1rgb = palette->getEntry(nearest1idx);
|
||||
int r1 = doc::rgba_getr(nearest1rgb);
|
||||
@ -109,7 +109,7 @@ namespace render {
|
||||
b2 = MID(0, b2, 255);
|
||||
doc::color_t nearest2idx =
|
||||
(rgbmap ? rgbmap->mapColor(r2, g2, b2):
|
||||
palette->findBestfit(r2, g2, b2, m_transparentIndex));
|
||||
palette->findBestfit(r2, g2, b2, 255, m_transparentIndex));
|
||||
|
||||
// If both possible RGB colors use the same index, we cannot
|
||||
// make any dither with these two colors.
|
||||
|
@ -492,10 +492,18 @@ void Render::renderSprite(
|
||||
switch (m_bgType) {
|
||||
|
||||
case BgType::CHECKED:
|
||||
if (bgLayer && bgLayer->isVisible())
|
||||
if (bgLayer && bgLayer->isVisible() && rgba_geta(bg_color) == 255) {
|
||||
fill_rect(dstImage, area.dstBounds(), bg_color);
|
||||
else
|
||||
}
|
||||
else {
|
||||
renderBackground(dstImage, area, zoom);
|
||||
if (bgLayer && bgLayer->isVisible() && rgba_geta(bg_color) > 0) {
|
||||
blend_rect(dstImage, area.dst.x, area.dst.y,
|
||||
area.dst.x+area.size.w-1,
|
||||
area.dst.y+area.size.h-1,
|
||||
bg_color, 255);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case BgType::TRANSPARENT:
|
||||
|
Loading…
x
Reference in New Issue
Block a user