aseprite/src/widgets/colsel.cpp
2009-05-30 21:22:52 +00:00

559 lines
16 KiB
C++

/* ASE - Allegro Sprite Editor
* Copyright (C) 2001-2009 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 <assert.h>
#include <allegro.h>
#include "jinete/jinete.h"
#include "core/app.h"
#include "core/color.h"
#include "modules/gui.h"
#include "modules/gfx.h"
#include "modules/palettes.h"
#include "raster/image.h"
#include "raster/palette.h"
#include "widgets/colsel.h"
#include "widgets/paledit.h"
#include "widgets/tabs.h"
enum {
MODEL_RGB,
MODEL_HSV,
MODEL_GRAY,
MODEL_MASK
};
typedef struct Model
{
const char *text;
int model;
int color_type;
JWidget (*create)();
} Model;
typedef struct ColorSelector
{
color_t color;
bool palette_locked;
bool editable_palette;
} ColorSelector;
static JWidget create_rgb_container();
static JWidget create_hsv_container();
static JWidget create_gray_container();
static JWidget create_mask_container();
static int colorselector_type();
static ColorSelector* colorselector_data(JWidget widget);
static bool colorselector_msg_proc(JWidget widget, JMessage msg);
static void colorselector_update_lock_button(JWidget widget);
static void colorselector_set_color2(JWidget widget, color_t 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);
static void select_tab_callback(JWidget tabs, void* data, int button);
static bool slider_change_hook(JWidget widget, void* data);
static bool button_mask_select_hook(JWidget widget, void* data);
static bool paledit_change_hook(JWidget widget, void* data);
static bool lock_button_select_hook(JWidget widget, void* data);
static Model models[] = {
{ "RGB", MODEL_RGB, COLOR_TYPE_RGB, create_rgb_container },
{ "HSV", MODEL_HSV, COLOR_TYPE_RGB, create_hsv_container },
{ "Gray", MODEL_GRAY, COLOR_TYPE_GRAY, create_gray_container },
{ "Mask", MODEL_MASK, COLOR_TYPE_MASK, create_mask_container },
{ NULL, 0, 0, NULL }
};
JWidget colorselector_new(bool editable_palette)
{
JWidget window = jtooltip_window_new("");
JWidget grid1 = jgrid_new(3, FALSE);
JWidget grid2 = jgrid_new(5, FALSE);
JWidget tabs = tabs_new(select_tab_callback);
JWidget pal = paledit_new(get_current_palette(), FALSE, 1);
JWidget idx = jlabel_new("None");
JWidget lock = jbutton_new("");
JWidget child;
ColorSelector* colorselector = jnew(ColorSelector, 1);
Model* m;
jwidget_set_name(pal, "pal");
jwidget_set_name(idx, "idx");
jwidget_set_name(lock, "lock");
jwidget_set_name(tabs, "tabs");
jwidget_set_name(grid2, "grid2");
/* color selector */
colorselector->color = color_mask();
colorselector->palette_locked = TRUE;
colorselector->editable_palette = editable_palette;
/* palette */
jwidget_add_tooltip_text(pal, _("Use SHIFT or CTRL to select ranges"));
/* lock button */
add_gfxicon_to_button(lock, GFX_BOX_LOCK, JI_CENTER | JI_MIDDLE);
/* tabs */
jwidget_set_bg_color(tabs, window->bg_color());
/* data for a better layout */
grid1->child_spacing = 0;
grid2->border_width.t = 3;
jwidget_expansive(grid2, TRUE);
/* append a tab for each color-model */
for (m=models; m->text!=NULL; ++m) {
tabs_append_tab(tabs, _(m->text), (void*)m);
child = (*m->create)();
jwidget_set_name(child, m->text);
jgrid_add_child(grid2, child, 1, 1, JI_HORIZONTAL | JI_TOP);
}
/* add children */
jgrid_add_child(grid2, pal, 1, 1, JI_RIGHT | JI_TOP);
jgrid_add_child(grid1, tabs, 1, 1, JI_HORIZONTAL | JI_BOTTOM);
jgrid_add_child(grid1, idx, 1, 1, JI_RIGHT | JI_BOTTOM);
jgrid_add_child(grid1, lock, 1, 1, JI_RIGHT | JI_BOTTOM);
jgrid_add_child(grid1, grid2, 3, 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);
HOOK(lock, JI_SIGNAL_BUTTON_SELECT, lock_button_select_hook, 0);
/* update the lock button */
colorselector_update_lock_button(window);
jwidget_init_theme(window);
return window;
}
void colorselector_set_color(JWidget widget, color_t color)
{
colorselector_set_color2(widget, color, TRUE, TRUE, NULL);
}
color_t colorselector_get_color(JWidget widget)
{
ColorSelector* colorselector = colorselector_data(widget);
return colorselector->color;
}
JWidget colorselector_get_paledit(JWidget widget)
{
return jwidget_find_name(widget, "pal");
}
static JWidget create_rgb_container()
{
JWidget grid = jgrid_new(2, FALSE);
JWidget rlabel = jlabel_new("R");
JWidget glabel = jlabel_new("G");
JWidget blabel = jlabel_new("B");
JWidget rslider = jslider_new(0, 255, 0);
JWidget gslider = jslider_new(0, 255, 0);
JWidget bslider = jslider_new(0, 255, 0);
jgrid_add_child(grid, rlabel, 1, 1, JI_RIGHT);
jgrid_add_child(grid, rslider, 1, 1, JI_HORIZONTAL);
jgrid_add_child(grid, glabel, 1, 1, JI_RIGHT);
jgrid_add_child(grid, gslider, 1, 1, JI_HORIZONTAL);
jgrid_add_child(grid, blabel, 1, 1, JI_RIGHT);
jgrid_add_child(grid, bslider, 1, 1, JI_HORIZONTAL);
jwidget_set_name(rslider, "rgb_r");
jwidget_set_name(gslider, "rgb_g");
jwidget_set_name(bslider, "rgb_b");
HOOK(rslider, JI_SIGNAL_SLIDER_CHANGE, slider_change_hook, 0);
HOOK(gslider, JI_SIGNAL_SLIDER_CHANGE, slider_change_hook, 0);
HOOK(bslider, JI_SIGNAL_SLIDER_CHANGE, slider_change_hook, 0);
return grid;
}
static JWidget create_hsv_container()
{
JWidget grid = jgrid_new(2, FALSE);
JWidget hlabel = jlabel_new("H");
JWidget slabel = jlabel_new("S");
JWidget vlabel = jlabel_new("V");
JWidget hslider = jslider_new(0, 255, 0);
JWidget sslider = jslider_new(0, 255, 0);
JWidget vslider = jslider_new(0, 255, 0);
jgrid_add_child(grid, hlabel, 1, 1, JI_RIGHT);
jgrid_add_child(grid, hslider, 1, 1, JI_HORIZONTAL);
jgrid_add_child(grid, slabel, 1, 1, JI_RIGHT);
jgrid_add_child(grid, sslider, 1, 1, JI_HORIZONTAL);
jgrid_add_child(grid, vlabel, 1, 1, JI_RIGHT);
jgrid_add_child(grid, vslider, 1, 1, JI_HORIZONTAL);
jwidget_set_name(hslider, "hsv_h");
jwidget_set_name(sslider, "hsv_s");
jwidget_set_name(vslider, "hsv_v");
HOOK(hslider, JI_SIGNAL_SLIDER_CHANGE, slider_change_hook, 0);
HOOK(sslider, JI_SIGNAL_SLIDER_CHANGE, slider_change_hook, 0);
HOOK(vslider, JI_SIGNAL_SLIDER_CHANGE, slider_change_hook, 0);
return grid;
}
static JWidget create_gray_container()
{
JWidget grid = jgrid_new(2, FALSE);
JWidget klabel = jlabel_new("V");
JWidget vslider = jslider_new(0, 255, 0);
jgrid_add_child(grid, klabel, 1, 1, JI_RIGHT);
jgrid_add_child(grid, vslider, 1, 1, JI_HORIZONTAL);
jwidget_set_name(vslider, "gray_v");
HOOK(vslider, JI_SIGNAL_SLIDER_CHANGE, slider_change_hook, 0);
return grid;
}
static JWidget create_mask_container()
{
JWidget button = jbutton_new("Mask Color");
HOOK(button, JI_SIGNAL_BUTTON_SELECT, button_mask_select_hook, 0);
return button;
}
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:
jfree(colorselector);
break;
case JM_SIGNAL:
if (msg->signal.num == JI_SIGNAL_INIT_THEME) {
JWidget idx = jwidget_find_name(widget, "idx");
JWidget pal = jwidget_find_name(widget, "pal");
JWidget grid2 = jwidget_find_name(widget, "grid2");
int idxlen = ji_font_text_len(idx->font(), "Index=888");
jwidget_set_min_size(idx, idxlen, 0);
paledit_set_boxsize(pal, 4*guiscale());
jwidget_set_min_size(grid2, 200*guiscale(), 0);
}
break;
}
return FALSE;
}
static void colorselector_update_lock_button(JWidget widget)
{
ColorSelector* colorselector = colorselector_data(widget);
JWidget lock = jwidget_find_name(widget, "lock");
if (colorselector->palette_locked) {
set_gfxicon_in_button(lock, GFX_BOX_LOCK);
jwidget_add_tooltip_text(lock, _("Press here to edit the palette"));
}
else {
set_gfxicon_in_button(lock, GFX_BOX_UNLOCK);
jwidget_add_tooltip_text(lock, _("Press here to lock the palette"));
}
}
static void colorselector_set_color2(JWidget widget, color_t color,
bool update_index_entry,
bool select_index_entry,
Model* exclude_this_model)
{
ColorSelector* colorselector = colorselector_data(widget);
JWidget tabs = jwidget_find_name(widget, "tabs");
int imgtype = app_get_current_image_type();
Model* m = reinterpret_cast<Model*>(tabs_get_selected_tab(tabs));
JWidget rgb_rslider = jwidget_find_name(widget, "rgb_r");
JWidget rgb_gslider = jwidget_find_name(widget, "rgb_g");
JWidget rgb_bslider = jwidget_find_name(widget, "rgb_b");
JWidget hsv_hslider = jwidget_find_name(widget, "hsv_h");
JWidget hsv_sslider = jwidget_find_name(widget, "hsv_s");
JWidget hsv_vslider = jwidget_find_name(widget, "hsv_v");
JWidget gray_vslider = jwidget_find_name(widget, "gray_v");
colorselector->color = color;
if (exclude_this_model != models+MODEL_RGB) {
jslider_set_value(rgb_rslider, color_get_red(imgtype, color));
jslider_set_value(rgb_gslider, color_get_green(imgtype, color));
jslider_set_value(rgb_bslider, color_get_blue(imgtype, color));
}
if (exclude_this_model != models+MODEL_HSV) {
jslider_set_value(hsv_hslider, color_get_hue(imgtype, color));
jslider_set_value(hsv_sslider, color_get_saturation(imgtype, color));
jslider_set_value(hsv_vslider, color_get_value(imgtype, color));
}
if (exclude_this_model != models+MODEL_GRAY) {
jslider_set_value(gray_vslider, color_get_value(imgtype, color));
}
switch (color_type(color)) {
case COLOR_TYPE_MASK:
m = models+MODEL_MASK;
break;
case COLOR_TYPE_RGB:
m = models+MODEL_RGB;
break;
case COLOR_TYPE_INDEX:
if (m != models+MODEL_RGB &&
m != models+MODEL_HSV) {
m = models+MODEL_RGB;
}
break;
case COLOR_TYPE_HSV:
m = models+MODEL_HSV;
break;
case COLOR_TYPE_GRAY:
m = models+MODEL_GRAY;
break;
default:
assert(FALSE);
}
tabs_select_tab(tabs, m);
select_tab_callback(tabs, m, 1);
if (update_index_entry) {
switch (color_type(color)) {
case COLOR_TYPE_INDEX:
colorselector_set_paledit_index(widget, color_get_index(IMAGE_INDEXED, color),
select_index_entry);
break;
case COLOR_TYPE_MASK:
colorselector_set_paledit_index(widget, 0, TRUE);
break;
default: {
int r = color_get_red (IMAGE_RGB, color);
int g = color_get_green(IMAGE_RGB, color);
int b = color_get_blue (IMAGE_RGB, color);
int i = palette_find_bestfit(get_current_palette(), 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)
{
ColorSelector* colorselector = colorselector_data(widget);
JWidget pal = jwidget_find_name(widget, "pal");
JWidget idx = jwidget_find_name(widget, "idx");
JWidget lock = jwidget_find_name(widget, "lock");
char buf[256];
if (index >= 0) {
if (select_index_entry)
paledit_select_color(pal, index);
sprintf(buf, "Index=%d", index);
if (colorselector->editable_palette)
jwidget_enable(lock);
else
jwidget_disable(lock);
}
else {
if (select_index_entry)
paledit_select_range(pal, -1, -1, PALETTE_EDITOR_RANGE_NONE);
sprintf(buf, "None");
jwidget_disable(lock);
}
jwidget_set_text(idx, buf);
}
static void select_tab_callback(JWidget tabs, void* data, int button)
{
JWidget window = jwidget_get_window(tabs);
Model* selected_model = (Model*)data;
JWidget child;
Model* m;
bool something_change = FALSE;
for (m=models; m->text!=NULL; ++m) {
child = jwidget_find_name(window, m->text);
if (m == selected_model) {
if (child->flags & JI_HIDDEN) {
jwidget_show(child);
something_change = TRUE;
}
}
else {
if (!(child->flags & JI_HIDDEN)) {
jwidget_hide(child);
something_change = TRUE;
}
}
}
if (something_change)
jwidget_relayout(window);
}
static bool slider_change_hook(JWidget widget, void* data)
{
JWidget window = jwidget_get_window(widget);
ColorSelector* colorselector = colorselector_data(window);
JWidget tabs = jwidget_find_name(window, "tabs");
JWidget pal = jwidget_find_name(window, "pal");
Model* m = reinterpret_cast<Model*>(tabs_get_selected_tab(tabs));
color_t color = colorselector->color;
int i, r, g, b;
switch (m->model) {
case MODEL_RGB: {
JWidget rslider = jwidget_find_name(window, "rgb_r");
JWidget gslider = jwidget_find_name(window, "rgb_g");
JWidget bslider = jwidget_find_name(window, "rgb_b");
int r = jslider_get_value(rslider);
int g = jslider_get_value(gslider);
int b = jslider_get_value(bslider);
color = color_rgb(r, g, b);
break;
}
case MODEL_HSV: {
JWidget hslider = jwidget_find_name(window, "hsv_h");
JWidget sslider = jwidget_find_name(window, "hsv_s");
JWidget vslider = jwidget_find_name(window, "hsv_v");
int h = jslider_get_value(hslider);
int s = jslider_get_value(sslider);
int v = jslider_get_value(vslider);
color = color_hsv(h, s, v);
break;
}
case MODEL_GRAY: {
JWidget vslider = jwidget_find_name(window, "gray_v");
int v = jslider_get_value(vslider);
color = color_gray(v);
break;
}
}
r = color_get_red (IMAGE_RGB, color);
g = color_get_green(IMAGE_RGB, color);
b = color_get_blue (IMAGE_RGB, color);
/* if the palette is locked then we have to search for the closest
color to the RGB values */
if (colorselector->palette_locked) {
i = palette_find_bestfit(get_current_palette(), r, g, b);
if (i >= 0 && i < 256)
colorselector_set_paledit_index(window, i, TRUE);
}
/* the palette is unlocked, we have to modify the select entries */
else {
bool array[256];
paledit_get_selected_entries(pal, array);
for (i=0; i<256; ++i)
if (array[i])
set_current_color(i, r, g, b);
jwidget_dirty(pal);
i = paledit_get_2nd_color(pal);
if (i >= 0)
color = color_index(i);
}
colorselector_set_color2(window, color, FALSE, FALSE, m);
jwidget_emit_signal(window, SIGNAL_COLORSELECTOR_COLOR_CHANGED);
return 0;
}
static bool button_mask_select_hook(JWidget widget, void* data)
{
JWidget window = jwidget_get_window(widget);
colorselector_set_color(window, color_mask());
jwidget_emit_signal(window, SIGNAL_COLORSELECTOR_COLOR_CHANGED);
return TRUE;
}
static bool paledit_change_hook(JWidget widget, void* data)
{
JWidget window = jwidget_get_window(widget);
bool array[256];
color_t color = colorselector_get_color(window);
int i;
paledit_get_selected_entries(widget, array);
for (i=0; i<256; ++i)
if (array[i]) {
color = color_index(i);
break;
}
colorselector_set_color2(window, color, TRUE, FALSE, NULL);
jwidget_emit_signal(window, SIGNAL_COLORSELECTOR_COLOR_CHANGED);
return 0;
}
static bool lock_button_select_hook(JWidget widget, void* data)
{
JWidget window = jwidget_get_window(widget);
ColorSelector* colorselector = colorselector_data(window);
colorselector->palette_locked = !colorselector->palette_locked;
colorselector_update_lock_button(window);
return TRUE;
}