Add the new ColorTintShadeTone color picker (#707)

This commit is contained in:
David Capello 2016-02-26 11:18:46 -03:00
parent 4e4f473dd6
commit 7a0a89e59e
8 changed files with 304 additions and 1 deletions

View File

@ -377,6 +377,9 @@
<key command="SetInkType"><param name="type" value="lock-alpha" /></key>
<key command="SetInkType"><param name="type" value="shading" /></key>
<key command="SetSameInk" />
<key command="SetColorSelector">
<param name="type" value="tint-shade-tone" />
</key>
<key command="SetColorSelector">
<param name="type" value="spectrum" />
</key>
@ -855,6 +858,9 @@
<param name="size" value="17" />
</item>
<separator />
<item command="SetColorSelector" text="Color Tint/Shade/Tone">
<param name="type" value="tint-shade-tone" />
</item>
<item command="SetColorSelector" text="Color Spectrum">
<param name="type" value="spectrum" />
</item>

View File

@ -112,7 +112,7 @@
<option id="box_size" type="int" default="11" />
<option id="fg_color" type="app::Color" default="app::Color::fromRgb(255, 255, 255)" />
<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="selector" type="app::ColorBar::ColorSelector" default="app::ColorBar::ColorSelector::TINT_SHADE_TONE" />
<option id="discrete_wheel" type="bool" default="false" />
<option id="wheel_model" type="int" default="0" />
<option id="harmony" type="int" default="0" />

View File

@ -339,6 +339,7 @@ add_library(app-lib
ui/color_selector.cpp
ui/color_sliders.cpp
ui/color_spectrum.cpp
ui/color_tint_shade_tone.cpp
ui/color_wheel.cpp
ui/configure_timeline_popup.cpp
ui/context_bar.cpp

View File

@ -46,6 +46,9 @@ void SetColorSelectorCommand::onLoadParams(const Params& params)
if (type == "spectrum") {
m_type = ColorBar::ColorSelector::SPECTRUM;
}
else if (type == "tint-shade-tone") {
m_type = ColorBar::ColorSelector::TINT_SHADE_TONE;
}
else if (type == "wheel" ||
type == "rgb-wheel") {
m_type = ColorBar::ColorSelector::RGB_WHEEL;
@ -73,6 +76,9 @@ std::string SetColorSelectorCommand::onGetFriendlyName() const
case ColorBar::ColorSelector::SPECTRUM:
result += "Color Spectrum";
break;
case ColorBar::ColorSelector::TINT_SHADE_TONE:
result += "Color Tint/Shade/Tone";
break;
case ColorBar::ColorSelector::RGB_WHEEL:
result += "RGB Color Wheel";
break;

View File

@ -31,6 +31,7 @@
#include "app/pref/preferences.h"
#include "app/transaction.h"
#include "app/ui/color_spectrum.h"
#include "app/ui/color_tint_shade_tone.h"
#include "app/ui/color_wheel.h"
#include "app/ui/editor/editor.h"
#include "app/ui/hex_color_entry.h"
@ -136,6 +137,7 @@ ColorBar::ColorBar(int align)
Preferences::instance().colorBar.boxSize() * guiscale())
, m_remapButton("Remap")
, m_selector(ColorSelector::NONE)
, m_tintShadeTone(nullptr)
, m_spectrum(nullptr)
, m_wheel(nullptr)
, m_fgColor(app::Color::fromRgb(255, 255, 255), IMAGE_RGB)
@ -306,6 +308,7 @@ void ColorBar::setColorSelector(ColorSelector selector)
if (m_selector == selector)
return;
if (m_tintShadeTone) m_tintShadeTone->setVisible(false);
if (m_spectrum) m_spectrum->setVisible(false);
if (m_wheel) m_wheel->setVisible(false);
@ -314,6 +317,17 @@ void ColorBar::setColorSelector(ColorSelector selector)
switch (m_selector) {
case ColorSelector::TINT_SHADE_TONE:
if (!m_tintShadeTone) {
m_tintShadeTone = new ColorTintShadeTone;
m_tintShadeTone->setExpansive(true);
m_tintShadeTone->selectColor(m_fgColor.getColor());
m_tintShadeTone->ColorChange.connect(&ColorBar::onPickSpectrum, this);
m_selectorPlaceholder.addChild(m_tintShadeTone);
}
m_tintShadeTone->setVisible(true);
break;
case ColorSelector::SPECTRUM:
if (!m_spectrum) {
m_spectrum = new ColorSpectrum;
@ -791,6 +805,9 @@ void ColorBar::onColorButtonChange(const app::Color& color)
m_paletteView.invalidate();
}
if (m_tintShadeTone && m_tintShadeTone->isVisible())
m_tintShadeTone->selectColor(color);
if (m_spectrum && m_spectrum->isVisible())
m_spectrum->selectColor(color);

View File

@ -32,6 +32,7 @@ namespace app {
class ColorButton;
class ColorSpectrum;
class ColorTintShadeTone;
class ColorWheel;
class CommandExecutionEvent;
class PaletteIndexChangeEvent;
@ -50,6 +51,7 @@ namespace app {
SPECTRUM,
RGB_WHEEL,
RYB_WHEEL,
TINT_SHADE_TONE,
};
static ColorBar* instance() { return m_instance; }
@ -148,6 +150,7 @@ namespace app {
PaletteView m_paletteView;
ui::Button m_remapButton;
ColorSelector m_selector;
ColorTintShadeTone* m_tintShadeTone;
ColorSpectrum* m_spectrum;
ColorWheel* m_wheel;
ColorButton m_fgColor;

View File

@ -0,0 +1,220 @@
// Aseprite
// Copyright (C) 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
// published by the Free Software Foundation.
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "app/ui/color_tint_shade_tone.h"
#include "app/color_utils.h"
#include "app/ui/skin/skin_theme.h"
#include "app/ui/status_bar.h"
#include "she/surface.h"
#include "ui/graphics.h"
#include "ui/message.h"
#include "ui/paint_event.h"
#include "ui/size_hint_event.h"
#include "ui/resize_event.h"
#include "ui/system.h"
namespace app {
using namespace app::skin;
using namespace gfx;
using namespace ui;
ColorTintShadeTone::ColorTintShadeTone()
: Widget(kGenericWidget)
, m_capturedInHue(false)
{
setBorder(gfx::Border(3*ui::guiscale()));
}
ColorTintShadeTone::~ColorTintShadeTone()
{
}
app::Color ColorTintShadeTone::pickColor(const gfx::Point& pos) const
{
gfx::Rect rc = childrenBounds();
if (rc.isEmpty())
return app::Color::fromMask();
int u, v, umax, vmax;
int huebar = getHueBarSize();
u = pos.x - rc.x;
v = pos.y - rc.y;
umax = MAX(1, rc.w-1);
vmax = MAX(1, rc.h-1-huebar);
double hue, sat, val;
if (m_capturedInHue) {
hue = (360.0 * u / umax);
sat = m_color.getSaturation();
val = m_color.getValue();
}
else {
hue = m_color.getHue();
sat = (100.0 * u / umax);
val = (100.0 - 100.0 * v / vmax);
}
return app::Color::fromHsv(
MID(0.0, hue, 360.0),
MID(0.0, sat, 100.0),
MID(0.0, val, 100.0));
}
void ColorTintShadeTone::selectColor(const app::Color& color)
{
m_color = color;
invalidate();
}
void ColorTintShadeTone::onSizeHint(SizeHintEvent& ev)
{
ev.setSizeHint(gfx::Size(32*ui::guiscale(), 32*ui::guiscale()));
}
void ColorTintShadeTone::onResize(ui::ResizeEvent& ev)
{
Widget::onResize(ev);
}
void ColorTintShadeTone::onPaint(ui::PaintEvent& ev)
{
ui::Graphics* g = ev.graphics();
SkinTheme* theme = static_cast<SkinTheme*>(this->theme());
theme->drawRect(g, clientBounds(),
theme->parts.editorNormal().get(),
bgColor());
gfx::Rect rc = clientChildrenBounds();
if (rc.isEmpty())
return;
double hue = m_color.getHue();
int umax, vmax;
int huebar = getHueBarSize();
umax = MAX(1, rc.w-1);
vmax = MAX(1, rc.h-1-huebar);
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);
gfx::Color color = color_utils::color_for_ui(
app::Color::fromHsv(
hue,
MID(0.0, sat, 100.0),
MID(0.0, val, 100.0)));
g->putPixel(color, rc.x+x, rc.y+y);
}
}
if (huebar > 0) {
for (int y=rc.h-huebar; y<rc.h; ++y) {
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));
g->putPixel(color, rc.x+x, rc.y+y);
}
}
}
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));
she::Surface* icon = theme->parts.colorWheelIndicator()->bitmap(0);
g->drawColoredRgbaSurface(
icon,
val > 50.0 ? gfx::rgba(0, 0, 0): gfx::rgba(255, 255, 255),
pos.x-icon->width()/2,
pos.y-icon->height()/2);
if (huebar > 0) {
pos.x = rc.x + int(rc.w * hue / 360.0);
pos.y = rc.y + rc.h - huebar/2;
g->drawColoredRgbaSurface(
icon,
gfx::rgba(0, 0, 0),
pos.x-icon->width()/2,
pos.y-icon->height()/2);
}
}
}
bool ColorTintShadeTone::onProcessMessage(ui::Message* msg)
{
switch (msg->type()) {
case kMouseDownMessage:
captureMouse();
// Continue...
case kMouseMoveMessage: {
MouseMessage* mouseMsg = static_cast<MouseMessage*>(msg);
if (msg->type() == kMouseDownMessage)
m_capturedInHue = inHueBarArea(mouseMsg->position());
app::Color color = pickColor(mouseMsg->position());
if (color != app::Color::fromMask()) {
StatusBar::instance()->showColor(0, "", color);
if (hasCapture())
ColorChange(color, mouseMsg->buttons());
}
break;
}
case kMouseUpMessage:
if (hasCapture()) {
releaseMouse();
}
return true;
case kSetCursorMessage: {
MouseMessage* mouseMsg = static_cast<MouseMessage*>(msg);
if (childrenBounds().contains(mouseMsg->position())) {
ui::set_mouse_cursor(kEyedropperCursor);
return true;
}
break;
}
}
return Widget::onProcessMessage(msg);
}
bool ColorTintShadeTone::inHueBarArea(const gfx::Point& pos) const
{
gfx::Rect rc = childrenBounds();
if (rc.isEmpty() || !rc.contains(pos))
return false;
else
return (pos.y >= rc.y+rc.h-getHueBarSize());
}
int ColorTintShadeTone::getHueBarSize() const
{
gfx::Rect rc = clientChildrenBounds();
int size = 8*guiscale();
return rc.h < 2*size ? 0: size;
}
} // namespace app

View File

@ -0,0 +1,50 @@
// Aseprite
// Copyright (C) 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
// published by the Free Software Foundation.
#ifndef APP_UI_COLOR_TINT_SHADE_TONE_H_INCLUDED
#define APP_UI_COLOR_TINT_SHADE_TONE_H_INCLUDED
#pragma once
#include "app/color.h"
#include "base/signal.h"
#include "ui/mouse_buttons.h"
#include "ui/widget.h"
namespace app {
class ColorTintShadeTone : public ui::Widget {
public:
ColorTintShadeTone();
~ColorTintShadeTone();
void selectColor(const app::Color& color);
// Signals
base::Signal2<void, const app::Color&, ui::MouseButtons> ColorChange;
protected:
void onSizeHint(ui::SizeHintEvent& ev) override;
void onResize(ui::ResizeEvent& ev) override;
void onPaint(ui::PaintEvent& ev) override;
bool onProcessMessage(ui::Message* msg) override;
private:
app::Color pickColor(const gfx::Point& pos) const;
bool inHueBarArea(const gfx::Point& pos) const;
int getHueBarSize() const;
app::Color m_color;
// True when the user pressed the mouse button in the hue slider.
// It's used to avoid swapping in both areas (tint/shades/tones
// area vs hue slider) when we drag the mouse above this widget.
bool m_capturedInHue;
};
} // namespace app
#endif