From c255d49f6908dc83aa52026be582a56196377a4c Mon Sep 17 00:00:00 2001 From: Holger Schemel Date: Sat, 5 Oct 2024 12:08:52 +0200 Subject: [PATCH] improved color picker for non-RGB (indexed) colors --- src/editor.c | 74 ++++++++++++-- src/libgame/gadgets.c | 221 +++++++++++++++++++++++++++++++++--------- src/libgame/gadgets.h | 8 +- 3 files changed, 245 insertions(+), 58 deletions(-) diff --git a/src/editor.c b/src/editor.c index 42b65489..756dc18e 100644 --- a/src/editor.c +++ b/src/editor.c @@ -411,6 +411,8 @@ ED_ENGINE_SETTINGS_XSTART) #define COLORPICKER_YPOS SY + (COLORPICKER_Y_REDEFINED ? COLORPICKER_Y : \ ED_ENGINE_SETTINGS_YSTART_0 + ED_GADGET_TEXT_DISTANCE) +#define COLORPICKER_C64_VALUES 16 +#define COLORPICKER_MAX_VALUES 256 // values for ClearEditorGadgetInfoText() and HandleEditorGadgetInfoText() #define INFOTEXT_FONT FONT_TEXT_2 @@ -1715,7 +1717,7 @@ static boolean levelset_copy_level_template = FALSE; static int levelset_save_mode = LEVELSET_SAVE_MODE_UPDATE; #define MAX_BD_COLORS 7 -#define MAX_BD_COLOR_TEXT_LEN 10 +#define MAX_BD_COLOR_TEXT_LEN 12 static int bd_color_type_default = GD_COLOR_TYPE_RGB; static int bd_color_type_last = GD_COLOR_TYPE_RGB; @@ -9922,12 +9924,64 @@ static void MapCheckbuttonGadget(int id) static void MapColorPickerGadget(int id, int color_nr) { + static int color_values[COLORPICKER_MAX_VALUES] = { 0 }; + static char *color_names[COLORPICKER_MAX_VALUES] = { NULL }; struct GadgetInfo *gi = level_editor_gadget[colorpicker_info[id].gadget_id]; - int color = gd_color_get_rgb(*bd_color[color_nr]); + int color_type = level.bd_color_type; + int bd_color_value = *bd_color[color_nr]; + int color_value_rgb = gd_color_get_rgb(bd_color_value); + int color_value_index = bd_color_value & 0xff; + int color_value = (color_type == GD_COLOR_TYPE_RGB ? color_value_rgb : color_value_index); + int color_count; + int i; + + if (color_type == GD_COLOR_TYPE_C64) + { + color_count = COLORPICKER_C64_VALUES; - ModifyGadget(gi, GDI_COLOR_NR, color_nr, GDI_END); - ModifyGadget(gi, GDI_COLOR_TYPE, level.bd_color_type, GDI_END); - ModifyGadget(gi, GDI_COLOR_VALUE, color, GDI_END); + for (i = 0; i < color_count; i++) + { + int color = gd_c64_color(i); + + color_values[i] = gd_color_get_rgb(color); + setString(&color_names[i], gd_color_get_string(color)); + } + } + else if (color_type == GD_COLOR_TYPE_C64DTV) + { + color_count = COLORPICKER_MAX_VALUES; + + for (i = 0; i < color_count; i++) + { + int color = gd_c64dtv_color(i); + + color_values[i] = gd_color_get_rgb(color); + setString(&color_names[i], gd_color_get_string(color)); + } + } + else if (color_type == GD_COLOR_TYPE_ATARI) + { + color_count = COLORPICKER_MAX_VALUES; + + for (i = 0; i < color_count; i++) + { + int color = gd_atari_color(i); + + color_values[i] = gd_color_get_rgb(color); + setString(&color_names[i], gd_color_get_string(color)); + } + } + else // GD_COLOR_TYPE_RGB + { + color_count = 0; + } + + ModifyGadget(gi, GDI_COLOR_NR, color_nr, GDI_END); + ModifyGadget(gi, GDI_COLOR_TYPE, color_type, GDI_END); + ModifyGadget(gi, GDI_COLOR_VALUE, color_value, GDI_END); + ModifyGadget(gi, GDI_COLOR_VALUES, color_values, GDI_END); + ModifyGadget(gi, GDI_COLOR_NAMES, color_names, GDI_END); + ModifyGadget(gi, GDI_COLOR_COUNT, color_count, GDI_END); MapGadget(gi); } @@ -11874,12 +11928,12 @@ static void DrawEngineConfigColors(void) // draw text input gadgets for (i = ED_TEXTINPUT_ID_COLORS_FIRST; i <= ED_TEXTINPUT_ID_COLORS_LAST; i++) MapTextInputGadget(i); - - // draw graphic button gadgets - for (i = ED_GRAPHICBUTTON_ID_PICK_FIRST; i <= ED_GRAPHICBUTTON_ID_PICK_LAST; i++) - MapGraphicbuttonGadget(i); } + // draw graphic button gadgets + for (i = ED_GRAPHICBUTTON_ID_PICK_FIRST; i <= ED_GRAPHICBUTTON_ID_PICK_LAST; i++) + MapGraphicbuttonGadget(i); + for (i = 0; i < MAX_BD_COLORS; i++) DrawColorBox_BD(i); @@ -17179,7 +17233,7 @@ static void HandleColorPickerGadgets(struct GadgetInfo *gi) if (type_id == ED_COLORPICKER_ID_PICK_COLOR) { if (gi->colorpicker.value != -1) - *bd_color[gi->colorpicker.nr] = gi->colorpicker.value; + *bd_color[gi->colorpicker.nr] = (gi->colorpicker.type << 24) + gi->colorpicker.value; DrawEditModeWindow(); } diff --git a/src/libgame/gadgets.c b/src/libgame/gadgets.c index b2758e26..e1576494 100644 --- a/src/libgame/gadgets.c +++ b/src/libgame/gadgets.c @@ -296,7 +296,77 @@ static void DrawColorPicker_HueGradient(SDL_Surface *surface) } } -static void DrawColorPicker_SampleBox(SDL_Surface *surface, SDL_Color color) +static void DrawColorPicker_Table(SDL_Surface *surface, struct GadgetInfo *gi) +{ + int *values = gi->colorpicker.values; + int count = gi->colorpicker.count; + int table_size = sqrt(count); + int box_size = CP_GADGET_WIDTH / table_size; + int x, y; + + for (y = 0; y < table_size; y++) + { + for (x = 0; x < table_size; x++) + { + SDL_Rect draw_rect = + { + x * box_size, + y * box_size, + box_size, + box_size, + }; + int pos = y * table_size + x; + int value = values[pos]; + SDL_Color color = from_RGBColor(int_to_rgb(value)); + Pixel pixel = SDL_MapRGB(surface->format, color.r, color.g, color.b); + + SDL_FillRect(surface, &draw_rect, pixel); + } + } +} + +static void DrawColorPicker_ColorMarker(struct GadgetInfo *gi) +{ + if (gi->colorpicker.count == 0) // RGB colors + { + int x = gi->x + gi->border.xsize; + int y = gi->y + gi->border.ysize; + int xsize_main = CP_MAIN_GRADIENT_WIDTH; + int ysize_main = CP_MAIN_GRADIENT_HEIGHT; + int xsize_hue = CP_HUE_GRADIENT_WIDTH; + int ysize_hue = CP_HUE_GRADIENT_HEIGHT; + int x_main = x + (xsize_main - 1) * cp_color_hsv.s; + int y_main = y + (ysize_main - 1) * (1.0 - cp_color_hsv.v); + int x_hue = x + ((cp_color_hsv.h / 360.0) * xsize_hue); + int y_hue = y + ysize_main; + + // draw color position indicator + FillRectangle(drawto, x_main - 1, y, CP_INDICATOR_SIZE, ysize_main, BLACK_PIXEL); + FillRectangle(drawto, x, y_main - 1, xsize_main, CP_INDICATOR_SIZE, BLACK_PIXEL); + + // draw color slider + FillRectangle(drawto, x_hue - 1, y_hue, CP_INDICATOR_SIZE, ysize_hue, BLACK_PIXEL); + } + else // indexed colors + { + int count = gi->colorpicker.count; + int table_size = sqrt(count); + int box_size = CP_GADGET_WIDTH / table_size; + int pos = gi->colorpicker.value; + int xpos = pos % table_size; + int ypos = pos / table_size; + int x = gi->x + gi->border.xsize + xpos * box_size; + int y = gi->y + gi->border.ysize + ypos * box_size; + + // draw color position indicator + FillRectangle(drawto, x - 1, y - 1, box_size + 2, CP_INDICATOR_SIZE, BLACK_PIXEL); + FillRectangle(drawto, x + box_size - 1, y - 1, CP_INDICATOR_SIZE, box_size + 2, BLACK_PIXEL); + FillRectangle(drawto, x - 1, y + box_size - 1, box_size + 2, CP_INDICATOR_SIZE, BLACK_PIXEL); + FillRectangle(drawto, x - 1, y - 1, CP_INDICATOR_SIZE, box_size + 2, BLACK_PIXEL); + } +} + +static void DrawColorPicker_SampleBox(SDL_Surface *surface, struct GadgetInfo *gi) { SDL_Rect draw_rect = { @@ -305,68 +375,96 @@ static void DrawColorPicker_SampleBox(SDL_Surface *surface, SDL_Color color) CP_SAMPLE_BOX_WIDTH, CP_SAMPLE_BOX_HEIGHT, }; - Pixel pixel = SDL_MapRGB(surface->format, color.r, color.g, color.b); - SDL_FillRect(surface, &draw_rect, pixel); -} + RGBColor color_rgb; -static void DrawColorPicker_ColorText(int x, int y, int font_nr) -{ - RGBColor rgb_color = hsv_to_rgb(cp_color_hsv); - char text[128]; + if (gi->colorpicker.count == 0) // RGB colors + { + color_rgb = hsv_to_rgb(cp_color_hsv); + } + else // indexed colors + { + int *values = gi->colorpicker.values; + int value = values[gi->colorpicker.value]; + + color_rgb = int_to_rgb(value); + } - sprintf(text, "#%02x%02x%02x", - (int) (rgb_color.r * 255), - (int) (rgb_color.g * 255), - (int) (rgb_color.b * 255)); + SDL_Color color = from_RGBColor(color_rgb); + Pixel pixel = SDL_MapRGB(surface->format, color.r, color.g, color.b); - DrawText(x, y, text, font_nr); + SDL_FillRect(surface, &draw_rect, pixel); } -static void DrawColorPicker(struct GadgetInfo *gi) +static void DrawColorPicker_ColorText(struct GadgetInfo *gi) { int x = gi->x + gi->border.xsize; int y = gi->y + gi->border.ysize;; int font_nr = gi->font; int font_height = getFontHeight(font_nr); int font_padding = (CP_HUE_GRADIENT_HEIGHT - font_height) / 2; - int xsize = CP_GADGET_WIDTH; - int ysize = CP_GADGET_HEIGHT; - int xsize_main = CP_MAIN_GRADIENT_WIDTH; int ysize_main = CP_MAIN_GRADIENT_HEIGHT; - int xsize_hue = CP_HUE_GRADIENT_WIDTH; int ysize_hue = CP_HUE_GRADIENT_HEIGHT; - int x_main = x + (xsize_main - 1) * cp_color_hsv.s; - int y_main = y + (ysize_main - 1) * (1.0 - cp_color_hsv.v); - int x_hue = x + ((cp_color_hsv.h / 360.0) * xsize_hue); - int y_hue = y + ysize_main; int x_text = x + font_padding; int y_text = y + ysize_main + ysize_hue + font_padding; - SDL_Surface *surface = SDL_CreateRGBSurface(0, xsize, ysize, 32, - 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000); - DrawColorPicker_Gradient(surface, cp_color_hsv.h); - DrawColorPicker_HueGradient(surface); - DrawColorPicker_SampleBox(surface, from_RGBColor(hsv_to_rgb(cp_color_hsv))); + if (gi->colorpicker.count == 0) + { + RGBColor rgb_color = hsv_to_rgb(cp_color_hsv); + char text[128]; + + sprintf(text, "#%02x%02x%02x", + (int) (rgb_color.r * 255), + (int) (rgb_color.g * 255), + (int) (rgb_color.b * 255)); + + DrawText(x_text, y_text, text, font_nr); + } + else + { + DrawText(x_text, y_text, gi->colorpicker.names[gi->colorpicker.value], font_nr); + } +} + +static void DrawColorPicker(struct GadgetInfo *gi) +{ + SDL_Surface *surface; + int x = gi->x + gi->border.xsize; + int y = gi->y + gi->border.ysize;; + int xsize = CP_GADGET_WIDTH; + int ysize = CP_GADGET_HEIGHT; + + surface = SDL_CreateRGBSurface(0, xsize, ysize, 32, 0x0000ff, 0x00ff00, 0xff0000, 0); + + if (gi->colorpicker.count == 0) + { + DrawColorPicker_Gradient(surface, cp_color_hsv.h); + DrawColorPicker_HueGradient(surface); + } + else + { + DrawColorPicker_Table(surface, gi); + } + + DrawColorPicker_SampleBox(surface, gi); SDLBlitSurface(surface, drawto->surface, 0, 0, xsize, ysize, x, y); SDL_FreeSurface(surface); - // draw color position indicator - FillRectangle(drawto, x_main - 1, y, CP_INDICATOR_SIZE, ysize_main, BLACK_PIXEL); - FillRectangle(drawto, x, y_main - 1, xsize_main, CP_INDICATOR_SIZE, BLACK_PIXEL); - - // draw color slider - FillRectangle(drawto, x_hue - 1, y_hue, CP_INDICATOR_SIZE, ysize_hue, BLACK_PIXEL); + // draw color marker + DrawColorPicker_ColorMarker(gi); // draw color RGB value - DrawColorPicker_ColorText(x_text, y_text, font_nr); + DrawColorPicker_ColorText(gi); } static void SelectColorPickerColor(struct GadgetInfo *gi) { - gi->event.type = GD_EVENT_COLOR_PICKER_LEAVING; - gi->colorpicker.value = rgb_to_int(hsv_to_rgb(cp_color_hsv)); + if (gi->colorpicker.count == 0) // RGB colors + { + gi->colorpicker.value = rgb_to_int(hsv_to_rgb(cp_color_hsv)); + gi->event.type = GD_EVENT_COLOR_PICKER_LEAVING; + } } void InitGadgetsSoundCallback(void (*activating_function)(void), @@ -1744,6 +1842,18 @@ static void HandleGadgetTags(struct GadgetInfo *gi, int first_tag, va_list ap) gi->colorpicker.value = va_arg(ap, int); break; + case GDI_COLOR_VALUES: + gi->colorpicker.values = va_arg(ap, int *); + break; + + case GDI_COLOR_NAMES: + gi->colorpicker.names = va_arg(ap, char **); + break; + + case GDI_COLOR_COUNT: + gi->colorpicker.count = va_arg(ap, int); + break; + default: Fail("HandleGadgetTags(): unknown tag %d", tag); } @@ -1947,13 +2057,13 @@ static void HandleGadgetTags(struct GadgetInfo *gi, int first_tag, va_list ap) gi->textarea.full_open = FALSE; } - if (gi->type & GD_TYPE_COLOR_PICKER) { gi->width = CP_GADGET_WIDTH + 2 * gi->border.xsize; gi->height = CP_GADGET_HEIGHT + 2 * gi->border.ysize; - cp_color_hsv = rgb_to_hsv(int_to_rgb(gi->colorpicker.value)); + if (gi->colorpicker.count == 0) // RGB colors + cp_color_hsv = rgb_to_hsv(int_to_rgb(gi->colorpicker.value)); // always start with closed color picker gi->colorpicker.open = FALSE; @@ -2511,27 +2621,44 @@ boolean HandleGadgets(int mx, int my, int button) int ysize_main = CP_MAIN_GRADIENT_HEIGHT; int xsize_hue = CP_HUE_GRADIENT_WIDTH; int ysize_hue = CP_HUE_GRADIENT_HEIGHT; - int xpos = mx - gi->x - gi->border.xsize; - int ypos = my - gi->y - gi->border.ysize; + int x = mx - gi->x - gi->border.xsize; + int y = my - gi->y - gi->border.ysize; + int x_hue = MIN(MAX(0, x), xsize_hue - 1); + int x_main = MIN(MAX(0, x), xsize_main - 1); + int y_main = MIN(MAX(0, y), ysize_main - 1); if (!motion_status) - state = (ypos < ysize_main ? CP_STATE_GRADIENT_CHANGE : - xpos < xsize_hue && ypos < ysize_main + ysize_hue ? CP_STATE_SLIDER_CHANGE : - xpos >= xsize_hue && ypos >= ysize_main ? CP_STATE_SAMPLE_BOX : + state = (y < ysize_main ? CP_STATE_GRADIENT_CHANGE : + x < xsize_hue && y < ysize_main + ysize_hue ? CP_STATE_SLIDER_CHANGE : + x >= xsize_hue && y >= ysize_main ? CP_STATE_SAMPLE_BOX : CP_STATE_NONE); if (state == CP_STATE_GRADIENT_CHANGE) { - cp_color_hsv.s = (double)MIN(MAX(0, xpos), xsize_main) / xsize_main; - cp_color_hsv.v = 1.0 - (double)MIN(MAX(0, ypos), ysize_main) / ysize_main; + if (gi->colorpicker.count == 0) // RGB colors + { + cp_color_hsv.s = (double)x_main / xsize_main; + cp_color_hsv.v = 1.0 - (double)y_main / ysize_main; + } + else // indexed colors + { + int count = gi->colorpicker.count; + int table_size = sqrt(count); + int box_size = CP_GADGET_WIDTH / table_size; + + gi->colorpicker.value = (y_main / box_size * table_size + x_main / box_size); + } DrawColorPicker(gi); } else if (state == CP_STATE_SLIDER_CHANGE) { - cp_color_hsv.h = (double)MIN(MAX(0, xpos), xsize_hue) / xsize_hue * 360.0; + if (gi->colorpicker.count == 0) // RGB colors + { + cp_color_hsv.h = (double)x_hue / xsize_hue * 360.0; - DrawColorPicker(gi); + DrawColorPicker(gi); + } } else if (state == CP_STATE_SAMPLE_BOX) { diff --git a/src/libgame/gadgets.h b/src/libgame/gadgets.h index 9d616260..9d824b94 100644 --- a/src/libgame/gadgets.h +++ b/src/libgame/gadgets.h @@ -122,6 +122,9 @@ #define GDI_COLOR_NR 54 #define GDI_COLOR_TYPE 55 #define GDI_COLOR_VALUE 56 +#define GDI_COLOR_VALUES 57 +#define GDI_COLOR_NAMES 58 +#define GDI_COLOR_COUNT 59 // gadget deactivation hack #define GDI_ACTIVE_POS(a) ((a) < 0 ? POS_OFFSCREEN : (a)) @@ -250,7 +253,10 @@ struct GadgetColorPicker { int nr; // color slot (if using several colors) int type; // color type (RGB, C64, C64DTV, Atari) - int value; // color value + int value; // color value (RGB or index position) + int *values; // array of color values (always RGB) + char **names; // array of color names + int count; // number of color values/names in above arrays // runtime values boolean open; // opening state of color picker -- 2.34.1