Rewrite the entire color selector as C++ class.

+ Added ColorSliders widget for RGB, HSV, and Grayscale sliders.
+ Added HexColorEntry to show a color in HTML format.
This commit is contained in:
David Capello 2011-03-01 22:50:49 -03:00
parent 2ac1d38d62
commit bb1151c0ac
9 changed files with 698 additions and 495 deletions

View File

@ -232,6 +232,7 @@ add_library(aseprite-library
widgets/color_bar.cpp
widgets/color_button.cpp
widgets/color_selector.cpp
widgets/color_sliders.cpp
widgets/curvedit.cpp
widgets/editor/click.cpp
widgets/editor/cursor.cpp
@ -240,6 +241,7 @@ add_library(aseprite-library
widgets/editor/pixels_movement.cpp
widgets/fileview.cpp
widgets/groupbut.cpp
widgets/hex_color_entry.cpp
widgets/menuitem.cpp
widgets/palette_view.cpp
widgets/preview.cpp

View File

@ -34,8 +34,6 @@
#include "widgets/editor.h"
#include "widgets/statebar.h"
static bool tooltip_window_msg_proc(JWidget widget, JMessage msg);
static int colorbutton_type()
{
static int type = 0;
@ -48,15 +46,14 @@ ColorButton::ColorButton(const Color& color, int imgtype)
: ButtonBase("", colorbutton_type(), JI_BUTTON, JI_BUTTON)
, m_color(color)
, m_imgtype(imgtype)
, m_tooltip_window(NULL)
, m_frame(NULL)
{
jwidget_focusrest(this, true);
}
ColorButton::~ColorButton()
{
if (m_tooltip_window != NULL)
delete m_tooltip_window; // widget, frame
delete m_frame; // widget, frame
}
int ColorButton::getImgType() const
@ -100,8 +97,7 @@ bool ColorButton::onProcessMessage(JMessage msg)
case JM_SIGNAL:
if (msg->signal.num == JI_SIGNAL_BUTTON_SELECT) {
// If the popup window was not created or shown yet..
if (this->m_tooltip_window == NULL ||
!this->m_tooltip_window->isVisible()) {
if (m_frame == NULL || !m_frame->isVisible()) {
// Open it
openSelectorDialog();
}
@ -114,9 +110,9 @@ bool ColorButton::onProcessMessage(JMessage msg)
break;
case JM_MOTION:
if (this->hasCapture()) {
if (hasCapture()) {
Widget* picked = ji_get_default_manager()->pick(msg->mouse.x, msg->mouse.y);
Color color = this->m_color;
Color color = m_color;
if (picked && picked != this) {
// Pick a color from another color-button
@ -144,14 +140,14 @@ bool ColorButton::onProcessMessage(JMessage msg)
}
// Did the color change?
if (color != this->m_color) {
if (color != m_color) {
setColor(color);
}
}
break;
case JM_SETCURSOR:
if (this->hasCapture()) {
if (hasCapture()) {
jmouse_set_cursor(JI_CURSOR_EYEDROPPER);
return true;
}
@ -170,8 +166,8 @@ void ColorButton::onPreferredSize(PreferredSizeEvent& ev)
box.x2 = box.x1+64;
ev.setPreferredSize(jrect_w(&box) + this->border_width.l + this->border_width.r,
jrect_h(&box) + this->border_width.t + this->border_width.b);
ev.setPreferredSize(jrect_w(&box) + border_width.l + border_width.r,
jrect_h(&box) + border_width.t + border_width.b);
}
void ColorButton::onPaint(PaintEvent& ev) // TODO use "ev.getGraphics()"
@ -186,7 +182,7 @@ void ColorButton::onPaint(PaintEvent& ev) // TODO use "ev.getGraphics()"
Color color;
// When the button is pushed, show the negative
if (this->isSelected()) {
if (isSelected()) {
color = Color::fromRgb(255-m_color.getRed(),
255-m_color.getGreen(),
255-m_color.getBlue());
@ -220,68 +216,48 @@ void ColorButton::onPaint(PaintEvent& ev) // TODO use "ev.getGraphics()"
void ColorButton::openSelectorDialog()
{
Frame* window;
int x, y;
if (m_tooltip_window == NULL) {
window = colorselector_new();
window->user_data[0] = this;
jwidget_add_hook(window, -1, tooltip_window_msg_proc, NULL);
m_tooltip_window = window;
}
else {
window = m_tooltip_window;
if (m_frame == NULL) {
m_frame = new ColorSelector();
m_frame->user_data[0] = this;
m_frame->ColorChange.connect(&ColorButton::onFrameColorChange, this);
}
colorselector_set_color(window, m_color);
m_frame->setColor(m_color);
m_frame->open_window();
window->open_window();
x = MID(0, this->rc->x1, JI_SCREEN_W-jrect_w(window->rc));
if (this->rc->y2 <= JI_SCREEN_H-jrect_h(window->rc))
x = MID(0, this->rc->x1, JI_SCREEN_W-jrect_w(m_frame->rc));
if (this->rc->y2 <= JI_SCREEN_H-jrect_h(m_frame->rc))
y = MAX(0, this->rc->y2);
else
y = MAX(0, this->rc->y1-jrect_h(window->rc));
y = MAX(0, this->rc->y1-jrect_h(m_frame->rc));
window->position_window(x, y);
m_frame->position_window(x, y);
jmanager_dispatch_messages(window->getManager());
jwidget_relayout(window);
jmanager_dispatch_messages(m_frame->getManager());
jwidget_relayout(m_frame);
/* setup the hot-region */
{
JRect rc = jrect_new(MIN(this->rc->x1, window->rc->x1)-8,
MIN(this->rc->y1, window->rc->y1)-8,
MAX(this->rc->x2, window->rc->x2)+8,
MAX(this->rc->y2, window->rc->y2)+8);
JRect rc = jrect_new(MIN(this->rc->x1, m_frame->rc->x1)-8,
MIN(this->rc->y1, m_frame->rc->y1)-8,
MAX(this->rc->x2, m_frame->rc->x2)+8,
MAX(this->rc->y2, m_frame->rc->y2)+8);
JRegion rgn = jregion_new(rc, 1);
jrect_free(rc);
static_cast<PopupFrame*>(window)->setHotRegion(rgn);
static_cast<PopupFrame*>(m_frame)->setHotRegion(rgn);
}
}
void ColorButton::closeSelectorDialog()
{
if (m_tooltip_window != NULL)
m_tooltip_window->closeWindow(NULL);
if (m_frame != NULL)
m_frame->closeWindow(NULL);
}
static bool tooltip_window_msg_proc(JWidget widget, JMessage msg)
void ColorButton::onFrameColorChange(const Color& color)
{
switch (msg->type) {
case JM_SIGNAL:
if (msg->signal.num == SIGNAL_COLORSELECTOR_COLOR_CHANGED) {
ColorButton* colorbutton_widget = (ColorButton*)widget->user_data[0];
Color color = colorselector_get_color(widget);
colorbutton_widget->setColor(color);
}
break;
}
return false;
setColor(color);
}

View File

@ -23,7 +23,7 @@
#include "base/signal.h"
#include "gui/button.h"
class Frame;
class ColorSelector;
class ColorButton : public ButtonBase
{
@ -49,10 +49,11 @@ protected:
private:
void openSelectorDialog();
void closeSelectorDialog();
void onFrameColorChange(const Color& color);
Color m_color;
int m_imgtype;
Frame* m_tooltip_window;
ColorSelector* m_frame;
};
#endif

View File

@ -24,6 +24,8 @@
#include "app.h"
#include "app/color.h"
#include "base/bind.h"
#include "gfx/border.h"
#include "gfx/size.h"
#include "gui/gui.h"
#include "modules/gfx.h"
#include "modules/gui.h"
@ -33,463 +35,157 @@
#include "widgets/color_selector.h"
#include "widgets/palette_view.h"
enum {
MODEL_RGB,
MODEL_HSV,
MODEL_GRAY,
MODEL_MASK
};
struct Model
ColorSelector::ColorSelector()
: PopupFrame("Color Selector", false)
, m_color(Color::fromMask())
, m_vbox(JI_VERTICAL)
, m_topBox(JI_HORIZONTAL)
, m_colorPalette(false)
, m_indexButton("Index", 1, JI_BUTTON)
, m_rgbButton("RGB", 1, JI_BUTTON)
, m_hsvButton("HSV", 1, JI_BUTTON)
, m_grayButton("Gray", 1, JI_BUTTON)
, m_maskButton("Mask", 1, JI_BUTTON)
, m_maskLabel("Transparent Color Selected")
, m_disableHexUpdate(false)
{
const char *text;
int model;
Widget* (*create)();
};
m_topBox.setBorder(gfx::Border(0));
m_topBox.child_spacing = 0;
struct ColorSelector
{
Color color;
Model* selected_model;
std::vector<Widget*> model_buttons;
};
m_colorPalette.setColumns(40);
m_colorPalette.setBoxSize(6*jguiscale());
m_colorPaletteContainer.attachToView(&m_colorPalette);
jwidget_expansive(&m_colorPaletteContainer, true);
static Widget* create_rgb_container();
static Widget* create_hsv_container();
static Widget* create_gray_container();
static Widget* create_mask_container();
setup_mini_look(&m_indexButton);
setup_mini_look(&m_rgbButton);
setup_mini_look(&m_hsvButton);
setup_mini_look(&m_grayButton);
setup_mini_look(&m_maskButton);
static int colorselector_type();
static ColorSelector* colorselector_data(JWidget widget);
static bool colorselector_msg_proc(JWidget widget, JMessage msg);
static void colorselector_set_color2(JWidget widget, const Color& color,
bool update_index_entry,
bool select_index_entry,
Model* exclude_this_model);
static void colorselector_set_paledit_index(JWidget widget, int index,
bool select_index_entry);
jwidget_add_child(&m_topBox, &m_indexButton);
jwidget_add_child(&m_topBox, &m_rgbButton);
jwidget_add_child(&m_topBox, &m_hsvButton);
jwidget_add_child(&m_topBox, &m_grayButton);
jwidget_add_child(&m_topBox, &m_maskButton);
jwidget_add_child(&m_topBox, &m_hexColorEntry);
jwidget_add_child(&m_vbox, &m_topBox);
jwidget_add_child(&m_vbox, &m_colorPaletteContainer);
jwidget_add_child(&m_vbox, &m_rgbSliders);
jwidget_add_child(&m_vbox, &m_hsvSliders);
jwidget_add_child(&m_vbox, &m_graySlider);
jwidget_add_child(&m_vbox, &m_maskLabel);
jwidget_add_child(this, &m_vbox);
static bool select_model_hook(Frame* frame, Model* selected_model);
static void slider_change_hook(Slider* widget);
static bool paledit_change_hook(JWidget widget, void* data);
m_indexButton.Click.connect(&ColorSelector::onColorTypeButtonClick, this);
m_rgbButton.Click.connect(&ColorSelector::onColorTypeButtonClick, this);
m_hsvButton.Click.connect(&ColorSelector::onColorTypeButtonClick, this);
m_grayButton.Click.connect(&ColorSelector::onColorTypeButtonClick, this);
m_maskButton.Click.connect(&ColorSelector::onColorTypeButtonClick, this);
static Model models[] = {
{ "RGB", MODEL_RGB, create_rgb_container },
{ "HSV", MODEL_HSV, create_hsv_container },
{ "Gray", MODEL_GRAY, create_gray_container },
{ "Mask", MODEL_MASK, create_mask_container },
{ NULL, 0, NULL }
};
m_colorPalette.IndexChange.connect(&ColorSelector::onColorPaletteIndexChange, this);
m_rgbSliders.ColorChange.connect(&ColorSelector::onColorSlidersChange, this);
m_hsvSliders.ColorChange.connect(&ColorSelector::onColorSlidersChange, this);
m_graySlider.ColorChange.connect(&ColorSelector::onColorSlidersChange, this);
m_hexColorEntry.ColorChange.connect(&ColorSelector::onColorHexEntryChange, this);
Frame* colorselector_new()
{
Frame* window = new PopupFrame(NULL, false);
Grid* grid1 = new Grid(2, false);
Grid* grid2 = new Grid(5, false);
Box* models_box = new Box(JI_HORIZONTAL);
PaletteView* pal = new PaletteView(false);
Label* idx = new Label("None");
Widget* child;
ColorSelector* colorselector = new ColorSelector;
Model* m;
selectColorType(Color::RgbType);
setPreferredSize(gfx::Size(300*jguiscale(), getPreferredSize().h));
pal->setName("pal");
idx->setName("idx");
grid2->setName("grid2");
/* color selector */
colorselector->color = Color::fromMask();
colorselector->selected_model = &models[0];
/* palette */
jwidget_add_tooltip_text(pal, "Use SHIFT or CTRL to select ranges", JI_TOP);
/* data for a better layout */
grid1->child_spacing = 0;
grid2->border_width.t = 3 * jguiscale();
jwidget_expansive(grid2, true);
jwidget_noborders(models_box);
// Append one button for each color-model
for (m=models; m->text!=NULL; ++m) {
// Create the color-model button to select it
RadioButton* model_button = new RadioButton(m->text, 1, JI_BUTTON);
colorselector->model_buttons.push_back(model_button);
setup_mini_look(model_button);
model_button->Click.connect(Bind<bool>(&select_model_hook, window, m));
jwidget_add_child(models_box, model_button);
// Create the color-model container
child = (*m->create)();
child->setName(m->text);
grid2->addChildInCell(child, 1, 1, JI_HORIZONTAL | JI_TOP);
}
/* add children */
grid2->addChildInCell(pal, 1, 1, JI_RIGHT | JI_TOP);
grid1->addChildInCell(models_box, 1, 1, JI_HORIZONTAL | JI_BOTTOM);
grid1->addChildInCell(idx, 1, 1, JI_RIGHT | JI_BOTTOM);
grid1->addChildInCell(grid2, 2, 1, JI_HORIZONTAL | JI_VERTICAL);
jwidget_add_child(window, grid1);
/* hooks */
jwidget_add_hook(window,
colorselector_type(),
colorselector_msg_proc, colorselector);
HOOK(pal, SIGNAL_PALETTE_EDITOR_CHANGE, paledit_change_hook, 0);
window->initTheme();
return window;
initTheme();
}
void colorselector_set_color(JWidget widget, const Color& color)
void ColorSelector::setColor(const Color& color)
{
colorselector_set_color2(widget, color, true, true, NULL);
m_color = color;
if (color.getType() == Color::IndexType)
m_colorPalette.selectColor(color.getIndex());
m_rgbSliders.setColor(m_color);
m_hsvSliders.setColor(m_color);
m_graySlider.setColor(m_color);
if (!m_disableHexUpdate)
m_hexColorEntry.setColor(m_color);
selectColorType(m_color.getType());
}
Color colorselector_get_color(JWidget widget)
Color ColorSelector::getColor() const
{
ColorSelector* colorselector = colorselector_data(widget);
return colorselector->color;
return m_color;
}
JWidget colorselector_get_paledit(JWidget widget)
void ColorSelector::onColorPaletteIndexChange(int index)
{
return jwidget_find_name(widget, "pal");
setColorWithSignal(Color::fromIndex(index));
}
static Widget* create_rgb_container()
void ColorSelector::onColorSlidersChange(const Color& color)
{
Grid* grid = new Grid(2, false);
Label* rlabel = new Label("R");
Label* glabel = new Label("G");
Label* blabel = new Label("B");
Slider* rslider = new Slider(0, 255, 0);
Slider* gslider = new Slider(0, 255, 0);
Slider* bslider = new Slider(0, 255, 0);
grid->addChildInCell(rlabel, 1, 1, JI_RIGHT);
grid->addChildInCell(rslider, 1, 1, JI_HORIZONTAL);
grid->addChildInCell(glabel, 1, 1, JI_RIGHT);
grid->addChildInCell(gslider, 1, 1, JI_HORIZONTAL);
grid->addChildInCell(blabel, 1, 1, JI_RIGHT);
grid->addChildInCell(bslider, 1, 1, JI_HORIZONTAL);
setColorWithSignal(color);
rslider->setName("rgb_r");
gslider->setName("rgb_g");
bslider->setName("rgb_b");
rslider->Change.connect(Bind<void>(&slider_change_hook, rslider));
gslider->Change.connect(Bind<void>(&slider_change_hook, gslider));
bslider->Change.connect(Bind<void>(&slider_change_hook, bslider));
return grid;
}
static Widget* create_hsv_container()
{
Grid* grid = new Grid(2, false);
Label* hlabel = new Label("H");
Label* slabel = new Label("S");
Label* vlabel = new Label("V");
Slider* hslider = new Slider(0, 360, 0);
Slider* sslider = new Slider(0, 100, 0);
Slider* vslider = new Slider(0, 100, 0);
grid->addChildInCell(hlabel, 1, 1, JI_RIGHT);
grid->addChildInCell(hslider, 1, 1, JI_HORIZONTAL);
grid->addChildInCell(slabel, 1, 1, JI_RIGHT);
grid->addChildInCell(sslider, 1, 1, JI_HORIZONTAL);
grid->addChildInCell(vlabel, 1, 1, JI_RIGHT);
grid->addChildInCell(vslider, 1, 1, JI_HORIZONTAL);
hslider->setName("hsv_h");
sslider->setName("hsv_s");
vslider->setName("hsv_v");
hslider->Change.connect(Bind<void>(&slider_change_hook, hslider));
sslider->Change.connect(Bind<void>(&slider_change_hook, sslider));
vslider->Change.connect(Bind<void>(&slider_change_hook, vslider));
return grid;
}
static Widget* create_gray_container()
{
Grid* grid = new Grid(2, false);
Label* klabel = new Label("V");
Slider* vslider = new Slider(0, 255, 0);
grid->addChildInCell(klabel, 1, 1, JI_RIGHT);
grid->addChildInCell(vslider, 1, 1, JI_HORIZONTAL);
vslider->setName("gray_v");
vslider->Change.connect(Bind<void>(&slider_change_hook, vslider));
return grid;
}
static Widget* create_mask_container()
{
return new Label("Mask color selected");
}
static int colorselector_type()
{
static int type = 0;
if (!type)
type = ji_register_widget_type();
return type;
}
static ColorSelector* colorselector_data(JWidget widget)
{
return reinterpret_cast<ColorSelector*>
(jwidget_get_data(widget, colorselector_type()));
}
static bool colorselector_msg_proc(JWidget widget, JMessage msg)
{
ColorSelector* colorselector = colorselector_data(widget);
switch (msg->type) {
case JM_DESTROY:
delete colorselector;
break;
case JM_SIGNAL:
if (msg->signal.num == JI_SIGNAL_INIT_THEME) {
Widget* idx = widget->findChild("idx");
PaletteView* pal = static_cast<PaletteView*>(widget->findChild("pal"));
Widget* grid2 = widget->findChild("grid2");
int idxlen = ji_font_text_len(idx->getFont(), "Index=888");
jwidget_set_min_size(idx, idxlen, 0);
pal->setBoxSize(4*jguiscale());
jwidget_set_min_size(grid2, 200*jguiscale(), 0);
}
break;
}
return false;
}
static void colorselector_set_color2(JWidget widget, const Color& color,
bool update_index_entry,
bool select_index_entry,
Model* exclude_this_model)
{
ColorSelector* colorselector = colorselector_data(widget);
Model* m = colorselector->selected_model;
Slider* rgb_rslider = widget->findChildT<Slider>("rgb_r");
Slider* rgb_gslider = widget->findChildT<Slider>("rgb_g");
Slider* rgb_bslider = widget->findChildT<Slider>("rgb_b");
Slider* hsv_hslider = widget->findChildT<Slider>("hsv_h");
Slider* hsv_sslider = widget->findChildT<Slider>("hsv_s");
Slider* hsv_vslider = widget->findChildT<Slider>("hsv_v");
Slider* gray_vslider = widget->findChildT<Slider>("gray_v");
colorselector->color = color;
if (exclude_this_model != models+MODEL_RGB) {
rgb_rslider->setValue(color.getRed());
rgb_gslider->setValue(color.getGreen());
rgb_bslider->setValue(color.getBlue());
}
if (exclude_this_model != models+MODEL_HSV) {
hsv_hslider->setValue(color.getHue());
hsv_sslider->setValue(color.getSaturation());
hsv_vslider->setValue(color.getValue());
}
if (exclude_this_model != models+MODEL_GRAY) {
gray_vslider->setValue(color.getGray());
}
switch (color.getType()) {
case Color::MaskType:
m = models+MODEL_MASK;
break;
case Color::RgbType:
m = models+MODEL_RGB;
break;
case Color::IndexType:
if (m != models+MODEL_RGB &&
m != models+MODEL_HSV) {
m = models+MODEL_RGB;
}
break;
case Color::HsvType:
m = models+MODEL_HSV;
break;
case Color::GrayType:
m = models+MODEL_GRAY;
break;
default:
ASSERT(false);
}
// // Select the RGB button
// jwidget_select(colorselector->rgb_button);
colorselector->model_buttons[m->model]->setSelected(true);
// Call the hook
select_model_hook(dynamic_cast<Frame*>(widget->getRoot()), m);
if (update_index_entry) {
switch (color.getType()) {
case Color::IndexType:
colorselector_set_paledit_index(widget, color.getIndex(), select_index_entry);
break;
case Color::MaskType:
colorselector_set_paledit_index(widget, 0, true);
break;
default: {
int r = color.getRed();
int g = color.getGreen();
int b = color.getBlue();
int i = get_current_palette()->findBestfit(r, g, b);
if (i >= 0 && i < 256)
colorselector_set_paledit_index(widget, i, true);
else
colorselector_set_paledit_index(widget, -1, true);
break;
}
}
}
}
static void colorselector_set_paledit_index(JWidget widget, int index, bool select_index_entry)
{
PaletteView* pal = static_cast<PaletteView*>(widget->findChild("pal"));
Widget* idx = widget->findChild("idx");
char buf[256];
if (index >= 0) {
if (select_index_entry)
pal->selectColor(index);
sprintf(buf, "Index=%d", index);
}
else {
if (select_index_entry)
pal->selectRange(-1, -1, PALETTE_EDITOR_RANGE_NONE);
sprintf(buf, "None");
}
idx->setText(buf);
}
static bool select_model_hook(Frame* frame, Model* selected_model)
{
ASSERT(frame != NULL);
ColorSelector* colorselector = colorselector_data(frame);
JWidget child;
Model* m;
bool something_change = false;
colorselector->selected_model = selected_model;
for (m=models; m->text!=NULL; ++m) {
child = jwidget_find_name(frame, m->text);
if (m == selected_model) {
if (child->flags & JI_HIDDEN) {
child->setVisible(true);
something_change = true;
}
}
else {
if (!(child->flags & JI_HIDDEN)) {
child->setVisible(false);
something_change = true;
}
}
}
if (something_change) {
// Select the mask color
if (selected_model->model == MODEL_MASK) {
colorselector_set_color2(frame, Color::fromMask(), false, false, NULL);
jwidget_emit_signal(frame, SIGNAL_COLORSELECTOR_COLOR_CHANGED);
}
jwidget_relayout(frame);
}
return true;
}
static void slider_change_hook(Slider* widget)
{
Frame* window = static_cast<Frame*>(widget->getRoot());
ColorSelector* colorselector = colorselector_data(window);
Model* m = colorselector->selected_model;
Color color = colorselector->color;
int i, r, g, b;
switch (m->model) {
case MODEL_RGB: {
Slider* rslider = window->findChildT<Slider>("rgb_r");
Slider* gslider = window->findChildT<Slider>("rgb_g");
Slider* bslider = window->findChildT<Slider>("rgb_b");
int r = rslider->getValue();
int g = gslider->getValue();
int b = bslider->getValue();
color = Color::fromRgb(r, g, b);
break;
}
case MODEL_HSV: {
Slider* hslider = window->findChildT<Slider>("hsv_h");
Slider* sslider = window->findChildT<Slider>("hsv_s");
Slider* vslider = window->findChildT<Slider>("hsv_v");
int h = hslider->getValue();
int s = sslider->getValue();
int v = vslider->getValue();
color = Color::fromHsv(h, s, v);
break;
}
case MODEL_GRAY: {
Slider* vslider = window->findChildT<Slider>("gray_v");
int v = vslider->getValue();
color = Color::fromGray(v);
break;
}
}
r = color.getRed();
g = color.getGreen();
b = color.getBlue();
// Find bestfit palette entry
int r = color.getRed();
int g = color.getGreen();
int b = color.getBlue();
// Search for the closest color to the RGB values
i = get_current_palette()->findBestfit(r, g, b);
int i = get_current_palette()->findBestfit(r, g, b);
if (i >= 0 && i < 256)
colorselector_set_paledit_index(window, i, true);
colorselector_set_color2(window, color, false, false, m);
jwidget_emit_signal(window, SIGNAL_COLORSELECTOR_COLOR_CHANGED);
m_colorPalette.selectColor(i);
}
static bool paledit_change_hook(Widget* widget, void* data)
void ColorSelector::onColorHexEntryChange(const Color& color)
{
Frame* window = static_cast<Frame*>(widget->getRoot());
PaletteView* paledit = static_cast<PaletteView*>(widget);
bool array[256];
Color color = colorselector_get_color(window);
int i;
// Disable updating the hex entry so we don't override what the user
// is writting in the text field.
m_disableHexUpdate = true;
paledit->getSelectedEntries(array);
for (i=0; i<256; ++i)
if (array[i]) {
color = Color::fromIndex(i);
break;
}
onColorSlidersChange(color);
colorselector_set_color2(window, color, true, false, NULL);
jwidget_emit_signal(window, SIGNAL_COLORSELECTOR_COLOR_CHANGED);
return 0;
m_disableHexUpdate = false;
}
void ColorSelector::onColorTypeButtonClick(Event& ev)
{
RadioButton* source = static_cast<RadioButton*>(ev.getSource());
if (source == &m_indexButton) selectColorType(Color::IndexType);
else if (source == &m_rgbButton) selectColorType(Color::RgbType);
else if (source == &m_hsvButton) selectColorType(Color::HsvType);
else if (source == &m_grayButton) selectColorType(Color::GrayType);
else if (source == &m_maskButton) {
// Select mask color directly when the radio button is pressed
setColorWithSignal(Color::fromMask());
}
}
void ColorSelector::setColorWithSignal(const Color& color)
{
setColor(color);
// Fire ColorChange signal
ColorChange(color);
}
void ColorSelector::selectColorType(Color::Type type)
{
m_colorPaletteContainer.setVisible(type == Color::IndexType);
m_rgbSliders.setVisible(type == Color::RgbType);
m_hsvSliders.setVisible(type == Color::HsvType);
m_graySlider.setVisible(type == Color::GrayType);
m_maskLabel.setVisible(type == Color::MaskType);
switch (type) {
case Color::IndexType: m_indexButton.setSelected(true); break;
case Color::RgbType: m_rgbButton.setSelected(true); break;
case Color::HsvType: m_hsvButton.setSelected(true); break;
case Color::GrayType: m_grayButton.setSelected(true); break;
case Color::MaskType: m_maskButton.setSelected(true); break;
}
m_vbox.setBounds(m_vbox.getBounds()); // TODO add Widget::relayout member function
m_vbox.invalidate();
}

View File

@ -20,18 +20,58 @@
#define WIDGETS_COLOR_SELECTOR_H_INCLUDED
#include "app/color.h"
#include "gui/base.h"
#include "base/signal.h"
#include "gui/button.h"
#include "gui/grid.h"
#include "gui/label.h"
#include "gui/popup_frame.h"
#include "gui/view.h"
#include "widgets/color_sliders.h"
#include "widgets/hex_color_entry.h"
#include "widgets/palette_view.h"
class Frame;
class ColorSelector : public PopupFrame
{
public:
ColorSelector();
// TODO use some JI_SIGNAL_USER
#define SIGNAL_COLORSELECTOR_COLOR_CHANGED 0x10009
void setColor(const Color& color);
Color getColor() const;
Frame* colorselector_new();
// Signals
Signal1<void, const Color&> ColorChange;
protected:
void onColorPaletteIndexChange(int index);
void onColorSlidersChange(const Color& color);
void onColorHexEntryChange(const Color& color);
void onColorTypeButtonClick(Event& ev);
void colorselector_set_color(Widget* widget, const Color& color);
Color colorselector_get_color(Widget* widget);
private:
void selectColorType(Color::Type type);
void setColorWithSignal(const Color& color);
Widget* colorselector_get_paledit(Widget* widget);
Box m_vbox;
Box m_topBox;
Color m_color;
View m_colorPaletteContainer;
PaletteView m_colorPalette;
RadioButton m_indexButton;
RadioButton m_rgbButton;
RadioButton m_hsvButton;
RadioButton m_grayButton;
RadioButton m_maskButton;
HexColorEntry m_hexColorEntry;
RgbSliders m_rgbSliders;
HsvSliders m_hsvSliders;
GraySlider m_graySlider;
Label m_maskLabel;
// This variable is used to avoid updating the m_hexColorEntry text
// when the color change is generated from a
// HexColorEntry::ColorChange signal. In this way we don't override
// what the user is writting in the text field.
bool m_disableHexUpdate;
};
#endif

View File

@ -0,0 +1,268 @@
/* ASE - Allegro Sprite Editor
* Copyright (C) 2001-2011 David Capello
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "config.h"
#include <allegro.h>
#include "app/color_utils.h"
#include "base/bind.h"
#include "gui/box.h"
#include "gui/entry.h"
#include "gui/graphics.h"
#include "gui/label.h"
#include "gui/preferred_size_event.h"
#include "gui/slider.h"
#include "skin/skin_slider_property.h"
#include "widgets/color_sliders.h"
using namespace gfx;
namespace {
// This class is used as SkinSliderProperty for RGB/HSV sliders to
// draw the background of them.
class ColorSliderBgPainter : public ISliderBgPainter
{
public:
ColorSliderBgPainter(ColorSliders::Channel channel)
: m_channel(channel)
{ }
void setColor(const Color& color) {
m_color = color;
}
void paint(Slider* slider, Graphics* g, const gfx::Rect& rc) {
int depth = g->getBitsPerPixel();
int color;
for (int x=0; x < rc.w; ++x) {
switch (m_channel) {
case ColorSliders::Red:
color = makecol(255 * x / (rc.w-1), m_color.getGreen(), m_color.getBlue());
break;
case ColorSliders::Green:
color = makecol(m_color.getRed(), 255 * x / (rc.w-1), m_color.getBlue());
break;
case ColorSliders::Blue:
color = makecol(m_color.getRed(), m_color.getGreen(), 255 * x / (rc.w-1));
break;
case ColorSliders::Hue:
color = color_utils::color_for_allegro(Color::fromHsv(360 * x / (rc.w-1), m_color.getSaturation(), m_color.getValue()), depth);
break;
case ColorSliders::Saturation:
color = color_utils::color_for_allegro(Color::fromHsv(m_color.getHue(), 100 * x / (rc.w-1), m_color.getValue()), depth);
break;
case ColorSliders::Value:
color = color_utils::color_for_allegro(Color::fromHsv(m_color.getHue(), m_color.getSaturation(), 100 * x / (rc.w-1)), depth);
break;
case ColorSliders::Gray:
color = color_utils::color_for_allegro(Color::fromGray(255 * x / (rc.w-1)), depth);
break;
}
g->drawVLine(color, rc.x+x, rc.y, rc.h);
}
}
private:
ColorSliders::Channel m_channel;
BITMAP* m_cachedBg;
Color m_color;
};
}
//////////////////////////////////////////////////////////////////////
// ColorSliders
ColorSliders::ColorSliders()
: Widget(JI_WIDGET)
, m_grid(3, false)
{
jwidget_add_child(this, &m_grid);
}
ColorSliders::~ColorSliders()
{
}
void ColorSliders::setColor(const Color& color)
{
onSetColor(color);
updateSlidersBgColor(color);
}
void ColorSliders:: onPreferredSize(PreferredSizeEvent& ev)
{
ev.setPreferredSize(m_grid.getPreferredSize());
}
void ColorSliders::addSlider(Channel channel, const char* labelText, int min, int max)
{
Label* label = new Label(labelText);
Slider* slider = new Slider(min, max, 0);
Entry* entry = new Entry(3, "0");
m_label.push_back(label);
m_slider.push_back(slider);
m_entry.push_back(entry);
slider->setProperty(PropertyPtr(new SkinSliderProperty(new ColorSliderBgPainter(channel))));
slider->setDoubleBuffered(true);
slider->Change.connect(Bind<void>(&ColorSliders::onSliderChange, this, m_slider.size()-1));
entry->EntryChange.connect(Bind<void>(&ColorSliders::onEntryChange, this, m_entry.size()-1));
m_grid.addChildInCell(label, 1, 1, JI_LEFT | JI_MIDDLE);
m_grid.addChildInCell(slider, 1, 1, JI_HORIZONTAL | JI_VERTICAL | JI_EXPANSIVE);
m_grid.addChildInCell(entry, 1, 1, JI_LEFT | JI_MIDDLE);
}
void ColorSliders::setSliderValue(int sliderIndex, int value)
{
Slider* slider = m_slider[sliderIndex];
slider->setValue(value);
}
int ColorSliders::getSliderValue(int sliderIndex) const
{
Slider* slider = m_slider[sliderIndex];
return slider->getValue();
}
void ColorSliders::onSliderChange(int i)
{
// Update the entry related to the changed slider widget.
m_entry[i]->setTextf("%d", m_slider[i]->getValue());
onControlChange();
}
void ColorSliders::onEntryChange(int i)
{
// Update the slider related to the changed entry widget.
int value = m_entry[i]->getTextInt();
value = MID(m_slider[i]->getMinValue(),
value,
m_slider[i]->getMaxValue());
m_slider[i]->setValue(value);
onControlChange();
}
void ColorSliders::onControlChange()
{
// Call derived class impl of getColorFromSliders() to update the
// background color of sliders.
Color color = getColorFromSliders();
updateSlidersBgColor(color);
// Fire ColorChange() signal
ColorChange(color);
}
void ColorSliders::updateSlidersBgColor(const Color& color)
{
for (size_t i = 0; i < m_slider.size(); ++i)
updateSliderBgColor(m_slider[i], color);
}
void ColorSliders::updateSliderBgColor(Slider* slider, const Color& color)
{
SharedPtr<SkinSliderProperty> sliderProperty(slider->getProperty("SkinProperty"));
static_cast<ColorSliderBgPainter*>(sliderProperty->getBgPainter())->setColor(color);
slider->invalidate();
}
//////////////////////////////////////////////////////////////////////
// RgbSliders
RgbSliders::RgbSliders()
: ColorSliders()
{
addSlider(Red, "R", 0, 255);
addSlider(Green, "G", 0, 255);
addSlider(Blue, "B", 0, 255);
}
void RgbSliders::onSetColor(const Color& color)
{
setSliderValue(0, color.getRed());
setSliderValue(1, color.getGreen());
setSliderValue(2, color.getBlue());
}
Color RgbSliders::getColorFromSliders()
{
return Color::fromRgb(getSliderValue(0),
getSliderValue(1),
getSliderValue(2));
}
//////////////////////////////////////////////////////////////////////
// HsvSliders
HsvSliders::HsvSliders()
: ColorSliders()
{
addSlider(Hue, "H", 0, 360);
addSlider(Saturation, "S", 0, 100);
addSlider(Value, "V", 0, 100);
}
void HsvSliders::onSetColor(const Color& color)
{
setSliderValue(0, color.getHue());
setSliderValue(1, color.getSaturation());
setSliderValue(2, color.getValue());
}
Color HsvSliders::getColorFromSliders()
{
return Color::fromHsv(getSliderValue(0),
getSliderValue(1),
getSliderValue(2));
}
//////////////////////////////////////////////////////////////////////
// GraySlider
GraySlider::GraySlider()
: ColorSliders()
{
addSlider(Gray, "V", 0, 255);
}
void GraySlider::onSetColor(const Color& color)
{
setSliderValue(0, color.getGray());
}
Color GraySlider::getColorFromSliders()
{
return Color::fromGray(getSliderValue(0));
}

103
src/widgets/color_sliders.h Normal file
View File

@ -0,0 +1,103 @@
/* ASE - Allegro Sprite Editor
* Copyright (C) 2001-2011 David Capello
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef WIDGETS_COLOR_SLIDERS_H_INCLUDED
#define WIDGETS_COLOR_SLIDERS_H_INCLUDED
#include "app/color.h"
#include "base/signal.h"
#include "gui/grid.h"
#include "gui/widget.h"
#include <vector>
class Label;
class Slider;
class Entry;
class ColorSliders : public Widget
{
public:
enum Channel { Red, Green, Blue,
Hue, Saturation, Value,
Gray };
ColorSliders();
~ColorSliders();
void setColor(const Color& color);
// Signals
Signal1<void, const Color&> ColorChange;
protected:
void onPreferredSize(PreferredSizeEvent& ev);
// For derived classes
void addSlider(Channel channel, const char* labelText, int min, int max);
void setSliderValue(int sliderIndex, int value);
int getSliderValue(int sliderIndex) const;
virtual void onSetColor(const Color& color) = 0;
virtual Color getColorFromSliders() = 0;
private:
void onSliderChange(int i);
void onEntryChange(int i);
void onControlChange();
void updateSlidersBgColor(const Color& color);
void updateSliderBgColor(Slider* slider, const Color& color);
std::vector<Label*> m_label;
std::vector<Slider*> m_slider;
std::vector<Entry*> m_entry;
Grid m_grid;
};
class RgbSliders : public ColorSliders
{
public:
RgbSliders();
private:
virtual void onSetColor(const Color& color);
virtual Color getColorFromSliders();
};
class HsvSliders : public ColorSliders
{
public:
HsvSliders();
private:
virtual void onSetColor(const Color& color);
virtual Color getColorFromSliders();
};
class GraySlider : public ColorSliders
{
public:
GraySlider();
private:
virtual void onSetColor(const Color& color);
virtual Color getColorFromSliders();
};
#endif

View File

@ -0,0 +1,70 @@
/* ASE - Allegro Sprite Editor
* Copyright (C) 2001-2011 David Capello
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "config.h"
#include <cstdlib>
#include <string>
#include "gfx/border.h"
#include "gui/theme.h"
#include "widgets/hex_color_entry.h"
HexColorEntry::HexColorEntry()
: Box(JI_HORIZONTAL)
, m_label("#")
, m_entry(6, "")
{
jwidget_add_child(this, &m_label);
jwidget_add_child(this, &m_entry);
m_entry.EntryChange.connect(&HexColorEntry::onEntryChange, this);
initTheme();
setBorder(gfx::Border(2*jguiscale(), 0, 0, 0));
child_spacing = 0;
}
void HexColorEntry::setColor(const Color& color)
{
m_entry.setTextf("%02x%02x%02x",
color.getRed(),
color.getGreen(),
color.getBlue());
}
void HexColorEntry::onEntryChange()
{
std::string text = m_entry.getText();
int r, g, b;
int c;
// Fill with zeros at the end of the text
while (text.size() < 6)
text.push_back('0');
// Convert text (Base 16) to integer
int hex = std::strtol(text.c_str(), NULL, 16);
r = (hex & 0xff0000) >> 16;
g = (hex & 0xff00) >> 8;
b = (hex & 0xff);
ColorChange(Color::fromRgb(r, g, b));
}

View File

@ -0,0 +1,47 @@
/* ASE - Allegro Sprite Editor
* Copyright (C) 2001-2011 David Capello
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef WIDGETS_HEX_COLOR_ENTRY_H_INCLUDED
#define WIDGETS_HEX_COLOR_ENTRY_H_INCLUDED
#include "app/color.h"
#include "base/signal.h"
#include "gui/box.h"
#include "gui/entry.h"
#include "gui/label.h"
// Little widget to show a color in hexadecimal format (as HTML).
class HexColorEntry : public Box
{
public:
HexColorEntry();
void setColor(const Color& color);
// Signals
Signal1<void, const Color&> ColorChange;
protected:
void onEntryChange();
private:
Label m_label;
Entry m_entry;
};
#endif