mirror of
https://github.com/aseprite/aseprite.git
synced 2025-01-02 11:59:58 +00:00
Add HSV-saturation/value sliders in ColorSpectrum/Wheel (related to #707)
Simplified ColorSelectors using more shared code in the base class.
This commit is contained in:
parent
29a49ad7fa
commit
b7f8efc0a3
@ -10,20 +10,29 @@
|
||||
|
||||
#include "app/ui/color_selector.h"
|
||||
|
||||
#include "app/ui/skin/skin_theme.h"
|
||||
#include "app/ui/status_bar.h"
|
||||
#include "she/surface.h"
|
||||
#include "ui/manager.h"
|
||||
#include "ui/message.h"
|
||||
#include "ui/paint_event.h"
|
||||
#include "ui/scale.h"
|
||||
#include "ui/size_hint_event.h"
|
||||
#include "ui/system.h"
|
||||
|
||||
#include <cmath>
|
||||
|
||||
namespace app {
|
||||
|
||||
using namespace app::skin;
|
||||
using namespace ui;
|
||||
|
||||
ColorSelector::ColorSelector()
|
||||
: Widget(kGenericWidget)
|
||||
, m_lockColor(false)
|
||||
, m_capturedInBottom(false)
|
||||
{
|
||||
setBorder(gfx::Border(3*ui::guiscale()));
|
||||
}
|
||||
|
||||
void ColorSelector::selectColor(const app::Color& color)
|
||||
@ -35,6 +44,26 @@ void ColorSelector::selectColor(const app::Color& color)
|
||||
invalidate();
|
||||
}
|
||||
|
||||
app::Color ColorSelector::getColorByPosition(const gfx::Point& pos)
|
||||
{
|
||||
gfx::Rect rc = childrenBounds();
|
||||
if (rc.isEmpty())
|
||||
return app::Color::fromMask();
|
||||
|
||||
int u, v, umax, vmax;
|
||||
int barSize = getBottomBarSize();
|
||||
u = pos.x - rc.x;
|
||||
v = pos.y - rc.y;
|
||||
umax = MAX(1, rc.w-1);
|
||||
vmax = MAX(1, rc.h-1-barSize);
|
||||
|
||||
if (( hasCapture() && m_capturedInBottom) ||
|
||||
(!hasCapture() && inBottomBarArea(pos)))
|
||||
return getBottomBarColor(u, umax);
|
||||
else
|
||||
return getMainAreaColor(u, umax, v, vmax);
|
||||
}
|
||||
|
||||
void ColorSelector::onSizeHint(SizeHintEvent& ev)
|
||||
{
|
||||
ev.setSizeHint(gfx::Size(32*ui::guiscale(), 32*ui::guiscale()));
|
||||
@ -44,6 +73,47 @@ bool ColorSelector::onProcessMessage(ui::Message* msg)
|
||||
{
|
||||
switch (msg->type()) {
|
||||
|
||||
case kMouseDownMessage:
|
||||
if (manager()->getCapture())
|
||||
break;
|
||||
|
||||
captureMouse();
|
||||
|
||||
// Continue...
|
||||
|
||||
case kMouseMoveMessage: {
|
||||
MouseMessage* mouseMsg = static_cast<MouseMessage*>(msg);
|
||||
|
||||
if (msg->type() == kMouseDownMessage)
|
||||
m_capturedInBottom = inBottomBarArea(mouseMsg->position());
|
||||
|
||||
app::Color color = getColorByPosition(mouseMsg->position());
|
||||
if (color != app::Color::fromMask()) {
|
||||
// base::ScopedValue<bool> switcher(m_lockColor, m_harmonyPicked, false);
|
||||
|
||||
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);
|
||||
app::Color color = getColorByPosition(mouseMsg->position());
|
||||
if (color.getType() != app::Color::MaskType) {
|
||||
ui::set_mouse_cursor(kCustomCursor, SkinTheme::instance()->cursors.eyedropper());
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case kMouseWheelMessage:
|
||||
if (!hasCapture()) {
|
||||
double scale = 1.0;
|
||||
@ -78,4 +148,58 @@ bool ColorSelector::onProcessMessage(ui::Message* msg)
|
||||
return Widget::onProcessMessage(msg);
|
||||
}
|
||||
|
||||
void ColorSelector::onPaint(ui::PaintEvent& ev)
|
||||
{
|
||||
ui::Graphics* g = ev.graphics();
|
||||
SkinTheme* theme = static_cast<SkinTheme*>(this->theme());
|
||||
|
||||
theme->drawRect(g, clientBounds(),
|
||||
theme->parts.editorNormal().get(),
|
||||
false); // Do not fill the center
|
||||
|
||||
gfx::Rect rc = clientChildrenBounds();
|
||||
if (rc.isEmpty())
|
||||
return;
|
||||
|
||||
int barSize = getBottomBarSize();
|
||||
rc.h -= barSize;
|
||||
onPaintMainArea(g, rc);
|
||||
|
||||
if (barSize > 0) {
|
||||
rc.y += rc.h;
|
||||
rc.h = barSize;
|
||||
onPaintBottomBar(g, rc);
|
||||
}
|
||||
}
|
||||
|
||||
void ColorSelector::paintColorIndicator(ui::Graphics* g,
|
||||
const gfx::Point& pos,
|
||||
const bool white)
|
||||
{
|
||||
SkinTheme* theme = static_cast<SkinTheme*>(this->theme());
|
||||
she::Surface* icon = theme->parts.colorWheelIndicator()->bitmap(0);
|
||||
|
||||
g->drawColoredRgbaSurface(
|
||||
icon,
|
||||
white ? gfx::rgba(255, 255, 255): gfx::rgba(0, 0, 0),
|
||||
pos.x-icon->width()/2,
|
||||
pos.y-icon->height()/2);
|
||||
}
|
||||
|
||||
bool ColorSelector::inBottomBarArea(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-getBottomBarSize());
|
||||
}
|
||||
|
||||
int ColorSelector::getBottomBarSize() const
|
||||
{
|
||||
gfx::Rect rc = clientChildrenBounds();
|
||||
int size = 8*guiscale();
|
||||
return rc.h < 2*size ? 0: size;
|
||||
}
|
||||
|
||||
} // namespace app
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2016 David Capello
|
||||
// Copyright (C) 2016-2017 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
// the End-User License Agreement for Aseprite.
|
||||
@ -23,19 +23,43 @@ namespace app {
|
||||
|
||||
void selectColor(const app::Color& color);
|
||||
|
||||
// IColorSource impl
|
||||
app::Color getColorByPosition(const gfx::Point& pos) override;
|
||||
|
||||
// Signals
|
||||
obs::signal<void(const app::Color&, ui::MouseButtons)> ColorChange;
|
||||
|
||||
protected:
|
||||
void onSizeHint(ui::SizeHintEvent& ev) override;
|
||||
bool onProcessMessage(ui::Message* msg) override;
|
||||
virtual app::Color getMainAreaColor(const int u, const int umax,
|
||||
const int v, const int vmax) = 0;
|
||||
virtual app::Color getBottomBarColor(const int u, const int umax) = 0;
|
||||
virtual void onPaintMainArea(ui::Graphics* g, const gfx::Rect& rc) = 0;
|
||||
virtual void onPaintBottomBar(ui::Graphics* g, const gfx::Rect& rc) = 0;
|
||||
|
||||
void paintColorIndicator(ui::Graphics* g,
|
||||
const gfx::Point& pos,
|
||||
const bool white);
|
||||
|
||||
app::Color m_color;
|
||||
|
||||
private:
|
||||
void onSizeHint(ui::SizeHintEvent& ev) override;
|
||||
bool onProcessMessage(ui::Message* msg) override;
|
||||
void onPaint(ui::PaintEvent& ev) override;
|
||||
|
||||
bool inBottomBarArea(const gfx::Point& pos) const;
|
||||
int getBottomBarSize() const;
|
||||
|
||||
// Internal flag used to lock the modification of m_color.
|
||||
// E.g. When the user picks a color harmony, we don't want to
|
||||
// change the main color.
|
||||
bool m_lockColor;
|
||||
|
||||
// True when the user pressed the mouse button in the bottom
|
||||
// slider. It's used to avoid swapping in both areas (main color
|
||||
// area vs bottom slider) when we drag the mouse above this
|
||||
// widget.
|
||||
bool m_capturedInBottom;
|
||||
};
|
||||
|
||||
} // namespace app
|
||||
|
@ -29,140 +29,77 @@ using namespace ui;
|
||||
|
||||
ColorSpectrum::ColorSpectrum()
|
||||
{
|
||||
setAlign(HORIZONTAL);
|
||||
setBorder(gfx::Border(3*ui::guiscale()));
|
||||
}
|
||||
|
||||
app::Color ColorSpectrum::getColorByPosition(const gfx::Point& pos)
|
||||
app::Color ColorSpectrum::getMainAreaColor(const int u, const int umax,
|
||||
const int v, const int vmax)
|
||||
{
|
||||
gfx::Rect rc = childrenBounds();
|
||||
if (rc.isEmpty())
|
||||
return app::Color::fromMask();
|
||||
|
||||
int vmid = (align() & HORIZONTAL ? rc.h/2 : rc.w/2);
|
||||
vmid = MAX(1, vmid);
|
||||
|
||||
int u, v, umax;
|
||||
if (align() & HORIZONTAL) {
|
||||
u = pos.x - rc.x;
|
||||
v = pos.y - rc.y;
|
||||
umax = MAX(1, rc.w-1);
|
||||
}
|
||||
else {
|
||||
u = pos.y - rc.y;
|
||||
v = pos.x - rc.x;
|
||||
umax = MAX(1, rc.h-1);
|
||||
}
|
||||
|
||||
double hue = 360.0 * u / umax;
|
||||
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(
|
||||
double lit = 1.0 - (double(v)/double(vmax));
|
||||
return app::Color::fromHsl(
|
||||
MID(0.0, hue, 360.0),
|
||||
MID(0.0, sat, 1.0),
|
||||
MID(0.0, val, 1.0));
|
||||
m_color.getHslSaturation(),
|
||||
MID(0.0, lit, 1.0));
|
||||
}
|
||||
|
||||
void ColorSpectrum::onPaint(ui::PaintEvent& ev)
|
||||
app::Color ColorSpectrum::getBottomBarColor(const int u, const int umax)
|
||||
{
|
||||
ui::Graphics* g = ev.graphics();
|
||||
SkinTheme* theme = static_cast<SkinTheme*>(this->theme());
|
||||
double sat = double(u) / double(umax);
|
||||
return app::Color::fromHsl(
|
||||
m_color.getHslHue(),
|
||||
MID(0.0, sat, 1.0),
|
||||
m_color.getHslLightness());
|
||||
}
|
||||
|
||||
theme->drawRect(g, clientBounds(),
|
||||
theme->parts.editorNormal().get(),
|
||||
false); // Do not fill the center
|
||||
|
||||
gfx::Rect rc = clientChildrenBounds();
|
||||
if (rc.isEmpty())
|
||||
return;
|
||||
|
||||
int vmid = (align() & HORIZONTAL ? rc.h/2 : rc.w/2);
|
||||
vmid = MAX(1, vmid);
|
||||
void ColorSpectrum::onPaintMainArea(ui::Graphics* g, const gfx::Rect& rc)
|
||||
{
|
||||
double sat = m_color.getHslSaturation();
|
||||
int umax = MAX(1, rc.w-1);
|
||||
int vmax = MAX(1, rc.h-1);
|
||||
|
||||
for (int y=0; y<rc.h; ++y) {
|
||||
for (int x=0; x<rc.w; ++x) {
|
||||
int u, v, umax;
|
||||
if (align() & HORIZONTAL) {
|
||||
u = x;
|
||||
v = y;
|
||||
umax = MAX(1, rc.w-1);
|
||||
}
|
||||
else {
|
||||
u = y;
|
||||
v = x;
|
||||
umax = MAX(1, rc.h-1);
|
||||
}
|
||||
|
||||
double hue = 360.0 * u / umax;
|
||||
double sat = (v < vmid ? double(v) / double(vmid) : 1.0);
|
||||
double val = (v < vmid ? 1.0 : 1.0-(double(v-vmid) / double(vmid)));
|
||||
double hue = 360.0 * double(x) / double(umax);
|
||||
double lit = 1.0 - double(y) / double(vmax);
|
||||
|
||||
gfx::Color color = color_utils::color_for_ui(
|
||||
app::Color::fromHsv(
|
||||
app::Color::fromHsl(
|
||||
MID(0.0, hue, 360.0),
|
||||
MID(0.0, sat, 1.0),
|
||||
MID(0.0, val, 1.0)));
|
||||
sat,
|
||||
MID(0.0, lit, 1.0)));
|
||||
|
||||
g->putPixel(color, rc.x+x, rc.y+y);
|
||||
}
|
||||
}
|
||||
|
||||
if (m_color.getType() != app::Color::MaskType) {
|
||||
double hue = m_color.getHsvHue();
|
||||
double sat = m_color.getHsvSaturation();
|
||||
double val = m_color.getHsvValue();
|
||||
double lit = (2.0 - sat) * val / 2.0;
|
||||
double hue = m_color.getHslHue();
|
||||
double lit = m_color.getHslLightness();
|
||||
gfx::Point pos(rc.x + int(hue * rc.w / 360.0),
|
||||
rc.y + rc.h - int(lit * rc.h));
|
||||
|
||||
she::Surface* icon = theme->parts.colorWheelIndicator()->bitmap(0);
|
||||
g->drawColoredRgbaSurface(
|
||||
icon,
|
||||
lit > 0.5 ? gfx::rgba(0, 0, 0): gfx::rgba(255, 255, 255),
|
||||
pos.x-icon->width()/2,
|
||||
pos.y-icon->height()/2);
|
||||
paintColorIndicator(g, pos, lit < 0.5);
|
||||
}
|
||||
}
|
||||
|
||||
bool ColorSpectrum::onProcessMessage(ui::Message* msg)
|
||||
void ColorSpectrum::onPaintBottomBar(ui::Graphics* g, const gfx::Rect& rc)
|
||||
{
|
||||
switch (msg->type()) {
|
||||
double hue = m_color.getHslHue();
|
||||
double lit = m_color.getHslLightness();
|
||||
|
||||
case kMouseDownMessage:
|
||||
captureMouse();
|
||||
// Continue...
|
||||
|
||||
case kMouseMoveMessage: {
|
||||
MouseMessage* mouseMsg = static_cast<MouseMessage*>(msg);
|
||||
|
||||
app::Color color = getColorByPosition(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(kCustomCursor, SkinTheme::instance()->cursors.eyedropper());
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
for (int x=0; x<rc.w; ++x) {
|
||||
gfx::Color color = color_utils::color_for_ui(
|
||||
app::Color::fromHsl(hue, double(x) / double(rc.w), lit));
|
||||
|
||||
g->drawVLine(color, rc.x+x, rc.y, rc.h);
|
||||
}
|
||||
|
||||
return ColorSelector::onProcessMessage(msg);
|
||||
if (m_color.getType() != app::Color::MaskType) {
|
||||
double sat = m_color.getHslSaturation();
|
||||
gfx::Point pos(rc.x + int(double(rc.w) * sat),
|
||||
rc.y + rc.h/2);
|
||||
paintColorIndicator(g, pos, false);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace app
|
||||
|
@ -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.
|
||||
@ -9,7 +9,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "app/ui/color_selector.h"
|
||||
#include "ui/button.h"
|
||||
|
||||
namespace app {
|
||||
|
||||
@ -17,12 +16,12 @@ namespace app {
|
||||
public:
|
||||
ColorSpectrum();
|
||||
|
||||
// IColorSource
|
||||
app::Color getColorByPosition(const gfx::Point& pos) override;
|
||||
|
||||
protected:
|
||||
void onPaint(ui::PaintEvent& ev) override;
|
||||
bool onProcessMessage(ui::Message* msg) override;
|
||||
app::Color getMainAreaColor(const int u, const int umax,
|
||||
const int v, const int vmax) override;
|
||||
app::Color getBottomBarColor(const int u, const int umax) override;
|
||||
void onPaintMainArea(ui::Graphics* g, const gfx::Rect& rc) override;
|
||||
void onPaintBottomBar(ui::Graphics* g, const gfx::Rect& rc) override;
|
||||
};
|
||||
|
||||
} // namespace app
|
||||
|
@ -12,14 +12,7 @@
|
||||
|
||||
#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 {
|
||||
|
||||
@ -28,67 +21,36 @@ using namespace gfx;
|
||||
using namespace ui;
|
||||
|
||||
ColorTintShadeTone::ColorTintShadeTone()
|
||||
: m_capturedInHue(false)
|
||||
{
|
||||
setBorder(gfx::Border(3*ui::guiscale()));
|
||||
}
|
||||
|
||||
app::Color ColorTintShadeTone::getColorByPosition(const gfx::Point& pos)
|
||||
app::Color ColorTintShadeTone::getMainAreaColor(const int u, const int umax,
|
||||
const int v, const int vmax)
|
||||
{
|
||||
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;
|
||||
|
||||
bool inHue =
|
||||
(( hasCapture() && m_capturedInHue) ||
|
||||
(!hasCapture() && inHueBarArea(pos)));
|
||||
|
||||
if (inHue) {
|
||||
hue = (360.0 * u / umax);
|
||||
sat = m_color.getHsvSaturation();
|
||||
val = m_color.getHsvValue();
|
||||
}
|
||||
else {
|
||||
hue = m_color.getHsvHue();
|
||||
sat = (1.0 * u / umax);
|
||||
val = (1.0 - double(v) / double(vmax));
|
||||
}
|
||||
|
||||
double sat = (1.0 * u / umax);
|
||||
double val = (1.0 - double(v) / double(vmax));
|
||||
return app::Color::fromHsv(
|
||||
MID(0.0, hue, 360.0),
|
||||
m_color.getHsvHue(),
|
||||
MID(0.0, sat, 1.0),
|
||||
MID(0.0, val, 1.0));
|
||||
}
|
||||
|
||||
void ColorTintShadeTone::onPaint(ui::PaintEvent& ev)
|
||||
app::Color ColorTintShadeTone::getBottomBarColor(const int u, const int umax)
|
||||
{
|
||||
ui::Graphics* g = ev.graphics();
|
||||
SkinTheme* theme = static_cast<SkinTheme*>(this->theme());
|
||||
|
||||
theme->drawRect(g, clientBounds(),
|
||||
theme->parts.editorNormal().get(),
|
||||
false); // Do not fill the center
|
||||
|
||||
gfx::Rect rc = clientChildrenBounds();
|
||||
if (rc.isEmpty())
|
||||
return;
|
||||
double hue = (360.0 * u / umax);
|
||||
return app::Color::fromHsv(
|
||||
MID(0.0, hue, 360.0),
|
||||
m_color.getHsvSaturation(),
|
||||
m_color.getHsvValue());
|
||||
}
|
||||
|
||||
void ColorTintShadeTone::onPaintMainArea(ui::Graphics* g, const gfx::Rect& rc)
|
||||
{
|
||||
double hue = m_color.getHsvHue();
|
||||
int umax, vmax;
|
||||
int huebar = getHueBarSize();
|
||||
umax = MAX(1, rc.w-1);
|
||||
vmax = MAX(1, rc.h-1-huebar);
|
||||
int umax = MAX(1, rc.w-1);
|
||||
int vmax = MAX(1, rc.h-1);
|
||||
|
||||
for (int y=0; y<rc.h-huebar; ++y) {
|
||||
for (int y=0; y<rc.h; ++y) {
|
||||
for (int x=0; x<rc.w; ++x) {
|
||||
double sat = double(x) / double(umax);
|
||||
double val = 1.0 - double(y) / double(vmax);
|
||||
@ -103,104 +65,32 @@ void ColorTintShadeTone::onPaint(ui::PaintEvent& ev)
|
||||
}
|
||||
}
|
||||
|
||||
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), 1.0, 1.0));
|
||||
|
||||
g->putPixel(color, rc.x+x, rc.y+y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (m_color.getType() != app::Color::MaskType) {
|
||||
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)));
|
||||
rc.y + int((1.0-val) * rc.h));
|
||||
|
||||
she::Surface* icon = theme->parts.colorWheelIndicator()->bitmap(0);
|
||||
g->drawColoredRgbaSurface(
|
||||
icon,
|
||||
val > 0.5 ? 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);
|
||||
}
|
||||
paintColorIndicator(g, pos, val < 0.5);
|
||||
}
|
||||
}
|
||||
|
||||
bool ColorTintShadeTone::onProcessMessage(ui::Message* msg)
|
||||
void ColorTintShadeTone::onPaintBottomBar(ui::Graphics* g, const gfx::Rect& rc)
|
||||
{
|
||||
switch (msg->type()) {
|
||||
|
||||
case kMouseDownMessage:
|
||||
if (manager()->getCapture())
|
||||
break;
|
||||
|
||||
captureMouse();
|
||||
|
||||
// Continue...
|
||||
|
||||
case kMouseMoveMessage: {
|
||||
MouseMessage* mouseMsg = static_cast<MouseMessage*>(msg);
|
||||
|
||||
if (msg->type() == kMouseDownMessage)
|
||||
m_capturedInHue = inHueBarArea(mouseMsg->position());
|
||||
|
||||
app::Color color = getColorByPosition(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(kCustomCursor, SkinTheme::instance()->cursors.eyedropper());
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
for (int x=0; x<rc.w; ++x) {
|
||||
gfx::Color color = color_utils::color_for_ui(
|
||||
app::Color::fromHsv(
|
||||
(360.0 * x / rc.w), 1.0, 1.0));
|
||||
|
||||
g->drawVLine(color, rc.x+x, rc.y, rc.h);
|
||||
}
|
||||
|
||||
return ColorSelector::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;
|
||||
if (m_color.getType() != app::Color::MaskType) {
|
||||
double hue = m_color.getHsvHue();
|
||||
gfx::Point pos(rc.x + int(rc.w * hue / 360.0),
|
||||
rc.y + rc.h/2);
|
||||
paintColorIndicator(g, pos, false);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace app
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2016 David Capello
|
||||
// Copyright (C) 2016-2017 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
// the End-User License Agreement for Aseprite.
|
||||
@ -16,21 +16,12 @@ namespace app {
|
||||
public:
|
||||
ColorTintShadeTone();
|
||||
|
||||
// IColorSource
|
||||
app::Color getColorByPosition(const gfx::Point& pos) override;
|
||||
|
||||
protected:
|
||||
void onPaint(ui::PaintEvent& ev) override;
|
||||
bool onProcessMessage(ui::Message* msg) override;
|
||||
|
||||
private:
|
||||
bool inHueBarArea(const gfx::Point& pos) const;
|
||||
int getHueBarSize() const;
|
||||
|
||||
// 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;
|
||||
app::Color getMainAreaColor(const int u, const int umax,
|
||||
const int v, const int vmax) override;
|
||||
app::Color getBottomBarColor(const int u, const int umax) override;
|
||||
void onPaintMainArea(ui::Graphics* g, const gfx::Rect& rc) override;
|
||||
void onPaintBottomBar(ui::Graphics* g, const gfx::Rect& rc) override;
|
||||
};
|
||||
|
||||
} // namespace app
|
||||
|
@ -56,7 +56,6 @@ ColorWheel::ColorWheel()
|
||||
, m_harmonyPicked(false)
|
||||
{
|
||||
SkinTheme* theme = SkinTheme::instance();
|
||||
setBorder(gfx::Border(3*ui::guiscale()));
|
||||
|
||||
m_options.Click.connect(base::Bind<void>(&ColorWheel::onOptions, this));
|
||||
m_options.setStyle(theme->styles.colorWheelOptions());
|
||||
@ -64,17 +63,13 @@ ColorWheel::ColorWheel()
|
||||
addChild(&m_options);
|
||||
}
|
||||
|
||||
app::Color ColorWheel::getColorByPosition(const gfx::Point& mousePos)
|
||||
{
|
||||
return getColorInClientPos(mousePos - bounds().origin());
|
||||
}
|
||||
|
||||
app::Color ColorWheel::getColorInClientPos(const gfx::Point& pos)
|
||||
app::Color ColorWheel::getMainAreaColor(const int _u, const int umax,
|
||||
const int _v, const int vmax)
|
||||
{
|
||||
m_harmonyPicked = false;
|
||||
|
||||
int u = (pos.x - (m_wheelBounds.x+m_wheelBounds.w/2));
|
||||
int v = (pos.y - (m_wheelBounds.y+m_wheelBounds.h/2));
|
||||
int u = _u - umax/2;
|
||||
int v = _v - vmax/2;
|
||||
double d = std::sqrt(u*u + v*v);
|
||||
|
||||
// Pick from the wheel
|
||||
@ -106,7 +101,7 @@ app::Color ColorWheel::getColorInClientPos(const gfx::Point& pos)
|
||||
return app::Color::fromHsv(
|
||||
MID(0, hue, 360),
|
||||
MID(0, sat / 100.0, 1.0),
|
||||
1.0);
|
||||
m_color.getHsvValue());
|
||||
}
|
||||
|
||||
// Pick harmonies
|
||||
@ -120,7 +115,7 @@ app::Color ColorWheel::getColorInClientPos(const gfx::Point& pos)
|
||||
|
||||
if (gfx::Rect(rc.x+rc.w-(n-i)*boxsize,
|
||||
rc.y+rc.h-boxsize,
|
||||
boxsize, boxsize).contains(pos)) {
|
||||
boxsize, boxsize).contains(gfx::Point(u, v))) {
|
||||
m_harmonyPicked = true;
|
||||
|
||||
color = app::Color::fromHsv(convertHueAngle(int(color.getHsvHue()), 1),
|
||||
@ -134,6 +129,97 @@ app::Color ColorWheel::getColorInClientPos(const gfx::Point& pos)
|
||||
return app::Color::fromMask();
|
||||
}
|
||||
|
||||
app::Color ColorWheel::getBottomBarColor(const int u, const int umax)
|
||||
{
|
||||
double val = double(u) / double(umax);
|
||||
return app::Color::fromHsv(
|
||||
m_color.getHsvHue(),
|
||||
m_color.getHsvSaturation(),
|
||||
MID(0.0, val, 1.0));
|
||||
}
|
||||
|
||||
void ColorWheel::onPaintMainArea(ui::Graphics* g, const gfx::Rect& rc)
|
||||
{
|
||||
SkinTheme* theme = static_cast<SkinTheme*>(this->theme());
|
||||
|
||||
int r = MIN(rc.w/2, rc.h/2);
|
||||
m_clientBounds = rc;
|
||||
m_wheelRadius = r;
|
||||
m_wheelBounds = gfx::Rect(rc.x+rc.w/2-r,
|
||||
rc.y+rc.h/2-r,
|
||||
r*2, r*2);
|
||||
|
||||
int umax = MAX(1, rc.w-1);
|
||||
int vmax = MAX(1, rc.h-1);
|
||||
|
||||
for (int y=0; y<rc.h; ++y) {
|
||||
for (int x=0; x<rc.w; ++x) {
|
||||
app::Color appColor =
|
||||
getMainAreaColor(x, umax,
|
||||
y, vmax);
|
||||
|
||||
gfx::Color color;
|
||||
if (appColor.getType() != app::Color::MaskType) {
|
||||
color = color_utils::color_for_ui(appColor);
|
||||
}
|
||||
else {
|
||||
color = theme->colors.editorFace();
|
||||
}
|
||||
|
||||
g->putPixel(color, rc.x+x, rc.y+y);
|
||||
}
|
||||
}
|
||||
|
||||
if (m_color.getAlpha() > 0) {
|
||||
int n = getHarmonies();
|
||||
int boxsize = MIN(rc.w/10, rc.h/10);
|
||||
|
||||
for (int i=0; i<n; ++i) {
|
||||
app::Color color = getColorInHarmony(i);
|
||||
double angle = color.getHsvHue()-30.0;
|
||||
double dist = color.getHsvSaturation();
|
||||
|
||||
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),
|
||||
int(-std::sin(PI*angle/180.0)*double(m_wheelRadius)*dist));
|
||||
|
||||
paintColorIndicator(g, pos, false);
|
||||
|
||||
g->fillRect(gfx::rgba(color.getRed(),
|
||||
color.getGreen(),
|
||||
color.getBlue(), 255),
|
||||
gfx::Rect(rc.x+rc.w-(n-i)*boxsize,
|
||||
rc.y+rc.h-boxsize,
|
||||
boxsize, boxsize));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ColorWheel::onPaintBottomBar(ui::Graphics* g, const gfx::Rect& rc)
|
||||
{
|
||||
double hue = m_color.getHsvHue();
|
||||
double sat = m_color.getHsvValue();
|
||||
|
||||
for (int x=0; x<rc.w; ++x) {
|
||||
gfx::Color color = color_utils::color_for_ui(
|
||||
app::Color::fromHsv(hue, sat, double(x) / double(rc.w)));
|
||||
|
||||
g->drawVLine(color, rc.x+x, rc.y, rc.h);
|
||||
}
|
||||
|
||||
if (m_color.getType() != app::Color::MaskType) {
|
||||
double val = m_color.getHsvValue();
|
||||
gfx::Point pos(rc.x + int(double(rc.w) * val),
|
||||
rc.y + rc.h/2);
|
||||
paintColorIndicator(g, pos, false);
|
||||
}
|
||||
}
|
||||
|
||||
void ColorWheel::setDiscrete(bool state)
|
||||
{
|
||||
m_discrete = state;
|
||||
@ -180,14 +266,6 @@ void ColorWheel::onResize(ui::ResizeEvent& ev)
|
||||
ColorSelector::onResize(ev);
|
||||
|
||||
gfx::Rect rc = clientChildrenBounds();
|
||||
int r = MIN(rc.w/2, rc.h/2);
|
||||
|
||||
m_clientBounds = rc;
|
||||
m_wheelRadius = r;
|
||||
m_wheelBounds = gfx::Rect(rc.x+rc.w/2-r,
|
||||
rc.y+rc.h/2-r,
|
||||
r*2, r*2);
|
||||
|
||||
gfx::Size prefSize = m_options.sizeHint();
|
||||
rc = childrenBounds();
|
||||
rc.x += rc.w-prefSize.w;
|
||||
@ -196,116 +274,6 @@ void ColorWheel::onResize(ui::ResizeEvent& ev)
|
||||
m_options.setBounds(rc);
|
||||
}
|
||||
|
||||
void ColorWheel::onPaint(ui::PaintEvent& ev)
|
||||
{
|
||||
ui::Graphics* g = ev.graphics();
|
||||
SkinTheme* theme = static_cast<SkinTheme*>(this->theme());
|
||||
|
||||
theme->drawRect(g, clientBounds(),
|
||||
theme->parts.editorNormal().get(),
|
||||
false); // Do not fill the center
|
||||
|
||||
const gfx::Rect& rc = m_clientBounds;
|
||||
|
||||
for (int y=rc.y; y<rc.y+rc.h; ++y) {
|
||||
for (int x=rc.x; x<rc.x+rc.w; ++x) {
|
||||
app::Color appColor =
|
||||
ColorWheel::getColorInClientPos(gfx::Point(x, y));
|
||||
|
||||
gfx::Color color;
|
||||
if (appColor.getType() != app::Color::MaskType) {
|
||||
color = color_utils::color_for_ui(appColor);
|
||||
}
|
||||
else {
|
||||
color = theme->colors.editorFace();
|
||||
}
|
||||
|
||||
g->putPixel(color, x, y);
|
||||
}
|
||||
}
|
||||
|
||||
if (m_color.getAlpha() > 0) {
|
||||
int n = getHarmonies();
|
||||
int boxsize = MIN(rc.w/10, rc.h/10);
|
||||
|
||||
for (int i=0; i<n; ++i) {
|
||||
app::Color color = getColorInHarmony(i);
|
||||
double angle = color.getHsvHue()-30.0;
|
||||
double dist = color.getHsvSaturation();
|
||||
|
||||
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),
|
||||
int(-std::sin(PI*angle/180.0)*double(m_wheelRadius)*dist));
|
||||
|
||||
she::Surface* icon = theme->parts.colorWheelIndicator()->bitmap(0);
|
||||
g->drawRgbaSurface(icon,
|
||||
pos.x-icon->width()/2,
|
||||
pos.y-icon->height()/2);
|
||||
|
||||
g->fillRect(gfx::rgba(color.getRed(),
|
||||
color.getGreen(),
|
||||
color.getBlue(), 255),
|
||||
gfx::Rect(rc.x+rc.w-(n-i)*boxsize,
|
||||
rc.y+rc.h-boxsize,
|
||||
boxsize, boxsize));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool ColorWheel::onProcessMessage(ui::Message* msg)
|
||||
{
|
||||
switch (msg->type()) {
|
||||
|
||||
case kMouseDownMessage:
|
||||
captureMouse();
|
||||
// Continue...
|
||||
|
||||
case kMouseMoveMessage: {
|
||||
MouseMessage* mouseMsg = static_cast<MouseMessage*>(msg);
|
||||
|
||||
app::Color color = getColorInClientPos(
|
||||
mouseMsg->position()
|
||||
- bounds().origin());
|
||||
|
||||
if (color != app::Color::fromMask()) {
|
||||
base::ScopedValue<bool> switcher(m_lockColor, m_harmonyPicked, false);
|
||||
|
||||
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);
|
||||
app::Color color = getColorInClientPos(
|
||||
mouseMsg->position()
|
||||
- bounds().origin());
|
||||
|
||||
if (color.getType() != app::Color::MaskType) {
|
||||
ui::set_mouse_cursor(kCustomCursor, SkinTheme::instance()->cursors.eyedropper());
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return ColorSelector::onProcessMessage(msg);
|
||||
}
|
||||
|
||||
void ColorWheel::onOptions()
|
||||
{
|
||||
Menu menu;
|
||||
|
@ -34,20 +34,21 @@ namespace app {
|
||||
|
||||
ColorWheel();
|
||||
|
||||
// IColorSource
|
||||
app::Color getColorByPosition(const gfx::Point& pos) override;
|
||||
|
||||
bool isDiscrete() const { return m_discrete; }
|
||||
void setDiscrete(bool state);
|
||||
|
||||
void setColorModel(ColorModel colorModel);
|
||||
void setHarmony(Harmony harmony);
|
||||
|
||||
protected:
|
||||
app::Color getMainAreaColor(const int u, const int umax,
|
||||
const int v, const int vmax) override;
|
||||
app::Color getBottomBarColor(const int u, const int umax) override;
|
||||
void onPaintMainArea(ui::Graphics* g, const gfx::Rect& rc) override;
|
||||
void onPaintBottomBar(ui::Graphics* g, const gfx::Rect& rc) override;
|
||||
|
||||
private:
|
||||
app::Color getColorInClientPos(const gfx::Point& pos);
|
||||
void onResize(ui::ResizeEvent& ev) override;
|
||||
void onPaint(ui::PaintEvent& ev) override;
|
||||
bool onProcessMessage(ui::Message* msg) override;
|
||||
void onOptions();
|
||||
int getHarmonies() const;
|
||||
app::Color getColorInHarmony(int i) const;
|
||||
|
Loading…
Reference in New Issue
Block a user