From bb1151c0ac3b1a96f2014a43065f2f8937465de7 Mon Sep 17 00:00:00 2001 From: David Capello Date: Tue, 1 Mar 2011 22:50:49 -0300 Subject: [PATCH] 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. --- src/CMakeLists.txt | 2 + src/widgets/color_button.cpp | 86 ++--- src/widgets/color_button.h | 5 +- src/widgets/color_selector.cpp | 556 ++++++++------------------------ src/widgets/color_selector.h | 56 +++- src/widgets/color_sliders.cpp | 268 +++++++++++++++ src/widgets/color_sliders.h | 103 ++++++ src/widgets/hex_color_entry.cpp | 70 ++++ src/widgets/hex_color_entry.h | 47 +++ 9 files changed, 698 insertions(+), 495 deletions(-) create mode 100644 src/widgets/color_sliders.cpp create mode 100644 src/widgets/color_sliders.h create mode 100644 src/widgets/hex_color_entry.cpp create mode 100644 src/widgets/hex_color_entry.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 0ab518aa3..a2d40ef02 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -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 diff --git a/src/widgets/color_button.cpp b/src/widgets/color_button.cpp index 3c2d98536..ed9f0b9b5 100644 --- a/src/widgets/color_button.cpp +++ b/src/widgets/color_button.cpp @@ -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(window)->setHotRegion(rgn); + static_cast(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); } diff --git a/src/widgets/color_button.h b/src/widgets/color_button.h index 7248e1210..341211bd9 100644 --- a/src/widgets/color_button.h +++ b/src/widgets/color_button.h @@ -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 diff --git a/src/widgets/color_selector.cpp b/src/widgets/color_selector.cpp index 4bf16eaf8..6aa12aa76 100644 --- a/src/widgets/color_selector.cpp +++ b/src/widgets/color_selector.cpp @@ -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 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(&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(&slider_change_hook, rslider)); - gslider->Change.connect(Bind(&slider_change_hook, gslider)); - bslider->Change.connect(Bind(&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(&slider_change_hook, hslider)); - sslider->Change.connect(Bind(&slider_change_hook, sslider)); - vslider->Change.connect(Bind(&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(&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 - (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(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("rgb_r"); - Slider* rgb_gslider = widget->findChildT("rgb_g"); - Slider* rgb_bslider = widget->findChildT("rgb_b"); - Slider* hsv_hslider = widget->findChildT("hsv_h"); - Slider* hsv_sslider = widget->findChildT("hsv_s"); - Slider* hsv_vslider = widget->findChildT("hsv_v"); - Slider* gray_vslider = widget->findChildT("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(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(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(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("rgb_r"); - Slider* gslider = window->findChildT("rgb_g"); - Slider* bslider = window->findChildT("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("hsv_h"); - Slider* sslider = window->findChildT("hsv_s"); - Slider* vslider = window->findChildT("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("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(widget->getRoot()); - PaletteView* paledit = static_cast(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(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(); } diff --git a/src/widgets/color_selector.h b/src/widgets/color_selector.h index bc8f432c7..8979b941b 100644 --- a/src/widgets/color_selector.h +++ b/src/widgets/color_selector.h @@ -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 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 diff --git a/src/widgets/color_sliders.cpp b/src/widgets/color_sliders.cpp new file mode 100644 index 000000000..d2779e9ac --- /dev/null +++ b/src/widgets/color_sliders.cpp @@ -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 + +#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(&ColorSliders::onSliderChange, this, m_slider.size()-1)); + entry->EntryChange.connect(Bind(&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 sliderProperty(slider->getProperty("SkinProperty")); + + static_cast(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)); +} diff --git a/src/widgets/color_sliders.h b/src/widgets/color_sliders.h new file mode 100644 index 000000000..c60d8ddf1 --- /dev/null +++ b/src/widgets/color_sliders.h @@ -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 + +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 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 m_label; + std::vector m_slider; + std::vector 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 diff --git a/src/widgets/hex_color_entry.cpp b/src/widgets/hex_color_entry.cpp new file mode 100644 index 000000000..0117e0b04 --- /dev/null +++ b/src/widgets/hex_color_entry.cpp @@ -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 +#include + +#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)); +} diff --git a/src/widgets/hex_color_entry.h b/src/widgets/hex_color_entry.h new file mode 100644 index 000000000..fb2ae4395 --- /dev/null +++ b/src/widgets/hex_color_entry.h @@ -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 ColorChange; + +protected: + void onEntryChange(); + +private: + Label m_label; + Entry m_entry; +}; + +#endif