diff --git a/data/images/ui/color_picker_val.png b/data/images/ui/color_picker_val.png new file mode 100644 index 000000000..f075676f4 Binary files /dev/null and b/data/images/ui/color_picker_val.png differ diff --git a/docs/CHANGES.txt b/docs/CHANGES.txt index a7d38156c..45e62dfec 100644 --- a/docs/CHANGES.txt +++ b/docs/CHANGES.txt @@ -7,7 +7,7 @@ Various contributors (see below, and AUTHORS.txt) http://www.tuxpaint.org/ -2022.February.27 (0.9.28) +2022.March.2 (0.9.28) * Improvements to "Paint" and "Lines" tools: ------------------------------------------ * Brush spacing may now be altered within Tux Paint. @@ -106,6 +106,10 @@ http://www.tuxpaint.org/ form a desired color. Undo/Redo is available! Bill Kendrick + * The rainbow palette color picker now acts as a true + Hue/Saturation/Value picker, with the addition of a "value" slider. + Bill Kendrick + * Show a "pipette"-shaped mouse pointer when selecting a color from the color palette, or the picture. Bill Kendrick diff --git a/src/tuxpaint.c b/src/tuxpaint.c index 0276a307f..1866f1b9d 100644 --- a/src/tuxpaint.c +++ b/src/tuxpaint.c @@ -22,7 +22,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA (See COPYING.txt) - June 14, 2002 - February 23, 2022 + June 14, 2002 - March 2, 2022 */ #include "platform.h" @@ -1523,8 +1523,9 @@ static SDL_Surface *img_magic_paint, *img_magic_fullscreen; static SDL_Surface *img_shapes_corner, *img_shapes_center; static SDL_Surface *img_bold, *img_italic; static SDL_Surface *img_label_select, *img_label_apply; -static SDL_Surface *img_color_picker, *img_color_picker_thumb, *img_paintwell, *img_color_sel, *img_color_mix; -static int color_picker_x, color_picker_y; +static SDL_Surface *img_color_picker, *img_color_picker_thumb, *img_color_picker_val; +static SDL_Surface *img_paintwell, *img_color_sel, *img_color_mix; +static int color_picker_x, color_picker_y, color_picker_v; static int color_mixer_reset; static SDL_Surface *img_title_on, *img_title_off, *img_title_large_on, *img_title_large_off; @@ -2093,6 +2094,9 @@ static int do_new_dialog(void); static int do_new_dialog_add_colors(SDL_Surface * *thumbs, int num_files, int *d_places, char * *d_names, char * *d_exts, int *white_in_palette); static int do_color_picker(void); +static void draw_color_picker_crosshairs(int color_picker_left, int color_picker_top, int color_picker_val_left, int color_picker_val_top); +static void draw_color_picker_values(int l, int t); +static void render_color_picker_palette(void); static int do_color_sel(int temp_mode); static int do_color_mix(void); static void draw_color_mixer_blank_example(void); @@ -21886,7 +21890,8 @@ static int do_color_picker(void) SDL_Event event; SDLKey key; int color_picker_left, color_picker_top; - int back_left, back_top; + int color_picker_val_left, color_picker_val_top; + int back_left, back_top, done_left, done_top; SDL_Rect color_example_dest; SDL_Surface *backup; SDL_Rect r_color_picker; @@ -21895,7 +21900,9 @@ static int do_color_picker(void) valhat_x = valhat_y = hatmotioner = 0; hide_blinking_cursor(); + do_setcursor(cursor_hand); + getpixel_img_color_picker = getpixels[img_color_picker->format->BytesPerPixel]; /* Draw button box: */ @@ -21975,6 +21982,8 @@ static int do_color_picker(void) /* Draw color palette: */ + render_color_picker_palette(); + color_picker_left = r_final.x; color_picker_top = r_final.y; @@ -21989,42 +21998,25 @@ static int do_color_picker(void) r_color_picker.h = dest.h; - /* Draw last color position: */ + /* Draw values: */ - dest.x = color_picker_x + color_picker_left - 3; - dest.y = color_picker_y + color_picker_top - 1; - dest.w = 7; - dest.h = 3; + color_picker_val_left = color_picker_left + img_color_picker->w + 2; + color_picker_val_top = color_picker_top; - SDL_FillRect(screen, &dest, SDL_MapRGB(screen->format, 0, 0, 0)); + draw_color_picker_values(color_picker_val_left, color_picker_val_top); - dest.x = color_picker_x + color_picker_left - 1; - dest.y = color_picker_y + color_picker_top - 3; - dest.w = 3; - dest.h = 7; - SDL_FillRect(screen, &dest, SDL_MapRGB(screen->format, 0, 0, 0)); + /* Draw crosshairs */ - dest.x = color_picker_x + color_picker_left - 2; - dest.y = color_picker_y + color_picker_top; - dest.w = 5; - dest.h = 1; + draw_color_picker_crosshairs(color_picker_left, color_picker_top, color_picker_val_left, color_picker_val_top); - SDL_FillRect(screen, &dest, SDL_MapRGB(screen->format, 255, 255, 255)); - - dest.x = color_picker_x + color_picker_left; - dest.y = color_picker_y + color_picker_top - 2; - dest.w = 1; - dest.h = 5; - - SDL_FillRect(screen, &dest, SDL_MapRGB(screen->format, 255, 255, 255)); /* Determine spot for example color: */ - color_example_dest.x = color_picker_left + img_color_picker->w + 2; + color_example_dest.x = color_picker_left + img_color_picker->w + 2 + img_back->w + 2; color_example_dest.y = color_picker_top + 2; - color_example_dest.w = r_final.w / 2 - 2; + color_example_dest.w = r_final.w / 2 - 2 - img_back->w - 2; color_example_dest.h = r_final.h / 2 - 4; @@ -22055,8 +22047,7 @@ static int do_color_picker(void) /* Show "Back" button */ - back_left = - (((PROMPT_W - 96 * 2) + w * 2 - img_color_picker->w) - img_back->w) / 2 + color_picker_left + img_color_picker->w; + back_left = r_final.x + r_final.w - img_back->w - 2; back_top = color_picker_top + img_color_picker->h - img_back->h - 2; dest.x = back_left; @@ -22069,6 +22060,15 @@ static int do_color_picker(void) SDL_BlitSurface(img_openlabels_back, NULL, screen, &dest); + /* Show "Done" button */ + done_left = back_left - img_yes->w - 2; + done_top = back_top; + + dest.x = done_left; + dest.y = done_top; + + SDL_BlitSurface(img_yes, NULL, screen, &dest); + SDL_Flip(screen); @@ -22114,18 +22114,87 @@ static int do_color_picker(void) { if (event.button.x >= color_picker_left && event.button.x < color_picker_left + img_color_picker->w && - event.button.y >= color_picker_top && event.button.y < color_picker_top + img_color_picker->h) + event.button.y >= color_picker_top && + event.button.y < color_picker_top + img_color_picker->h) { /* Picked a color! */ - chose = 1; - done = 1; - x = event.button.x - color_picker_left; y = event.button.y - color_picker_top; color_picker_x = x; color_picker_y = y; + + /* Update (entire) color box */ + SDL_GetRGB(getpixel_img_color_picker(img_color_picker, x, y), img_color_picker->format, &r, &g, &b); + + SDL_FillRect(screen, &color_example_dest, SDL_MapRGB(screen->format, r, g, b)); + + SDL_UpdateRect(screen, + color_example_dest.x, color_example_dest.y, + color_example_dest.w, color_example_dest.h); + + + /* Reposition hue/sat crosshair */ + dest.x = color_picker_left; + dest.y = color_picker_top; + SDL_BlitSurface(img_color_picker, NULL, screen, &dest); + draw_color_picker_crosshairs(color_picker_left, color_picker_top, color_picker_val_left, color_picker_val_top); + SDL_UpdateRect(screen, dest.x, dest.y, dest.w, dest.h); + } + else if (event.button.x >= color_picker_val_left && + event.button.y >= color_picker_val_top && + event.button.x <= color_picker_val_left + img_back->w && + event.button.y <= color_picker_val_top + img_color_picker_val->h) + { + /* Picked a value from the slider */ + + y = event.button.y - color_picker_val_top; + color_picker_v = y; + + /* Re-render the palette with the new value */ + render_color_picker_palette(); + + /* Update (entire) color box */ + SDL_GetRGB(getpixel_img_color_picker(img_color_picker, color_picker_x, color_picker_y), img_color_picker->format, &r, &g, &b); + + SDL_FillRect(screen, &color_example_dest, SDL_MapRGB(screen->format, r, g, b)); + + SDL_UpdateRect(screen, + color_example_dest.x, color_example_dest.y, + color_example_dest.w, color_example_dest.h); + + + /* Redraw hue/sat palette, and val slider, and redraw crosshairs */ + draw_color_picker_values(color_picker_val_left, color_picker_val_top); + + dest.x = color_picker_left; + dest.y = color_picker_top; + SDL_BlitSurface(img_color_picker, NULL, screen, &dest); + SDL_UpdateRect(screen, dest.x, dest.y, dest.w, dest.h); + + draw_color_picker_crosshairs(color_picker_left, color_picker_top, color_picker_val_left, color_picker_val_top); + + dest.x = color_picker_val_left; + dest.y = color_picker_val_top; + dest.w = img_back->w; + dest.h = img_color_picker_val->h; + SDL_UpdateRect(screen, dest.x, dest.y, dest.w, dest.h); + + dest.x = color_picker_left; + dest.y = color_picker_top; + dest.w = img_color_picker->w; + dest.h = img_color_picker->h; + SDL_UpdateRect(screen, dest.x, dest.y, dest.w, dest.h); + } + else if (event.button.x >= done_left && + event.button.x < done_left + img_yes->w && + event.button.y >= done_top && event.button.y < done_top + img_yes->h) + { + /* Accepting color */ + + chose = 1; + done = 1; } else if (event.button.x >= back_left && event.button.x < back_left + img_back->w && @@ -22153,37 +22222,40 @@ static int do_color_picker(void) x = event.button.x - color_picker_left; y = event.button.y - color_picker_top; - getpixel_img_color_picker = getpixels[img_color_picker->format->BytesPerPixel]; SDL_GetRGB(getpixel_img_color_picker(img_color_picker, x, y), img_color_picker->format, &r, &g, &b); + dest.x = color_example_dest.x + color_example_dest.w / 4; + dest.y = color_example_dest.y + color_example_dest.h / 4; + dest.w = color_example_dest.w / 2; + dest.h = color_example_dest.h / 2; + + SDL_FillRect(screen, &dest, SDL_MapRGB(screen->format, r, g, b)); + + SDL_UpdateRect(screen, dest.x, dest.y, dest.w, dest.h); + } + else + { + /* Revert to current color picker color */ + + SDL_GetRGB(getpixel_img_color_picker(img_color_picker, color_picker_x, color_picker_y), + img_color_picker->format, &r, &g, &b); + SDL_FillRect(screen, &color_example_dest, SDL_MapRGB(screen->format, r, g, b)); SDL_UpdateRect(screen, - color_example_dest.x, - color_example_dest.y, color_example_dest.w, color_example_dest.h); - } - else - { - /* Revert to current color picker color, so we know what it was, - and what we'll get if we go Back: */ + color_example_dest.x, color_example_dest.y, + color_example_dest.w, color_example_dest.h); - SDL_FillRect(screen, &color_example_dest, - SDL_MapRGB(screen->format, - color_hexes[COLOR_PICKER][0], - color_hexes[COLOR_PICKER][1], - color_hexes[COLOR_PICKER][2])); - - SDL_UpdateRect(screen, - color_example_dest.x, - color_example_dest.y, color_example_dest.w, color_example_dest.h); - - - /* Change cursor to arrow (or hand, if over Back): */ + /* Change cursor to arrow (or hand, if over Back or Done): */ if (event.button.x >= back_left && event.button.x < back_left + img_back->w && event.button.y >= back_top && event.button.y < back_top + img_back->h) do_setcursor(cursor_hand); + else if (event.button.x >= done_left && + event.button.x < done_left + img_yes->w && + event.button.y >= done_top && event.button.y < done_top + img_yes->h) + do_setcursor(cursor_hand); else do_setcursor(cursor_arrow); } @@ -22216,8 +22288,7 @@ static int do_color_picker(void) if (chose) { - getpixel_img_color_picker = getpixels[img_color_picker->format->BytesPerPixel]; - SDL_GetRGB(getpixel_img_color_picker(img_color_picker, x, y), img_color_picker->format, &r, &g, &b); + SDL_GetRGB(getpixel_img_color_picker(img_color_picker, color_picker_x, color_picker_y), img_color_picker->format, &r, &g, &b); color_hexes[COLOR_PICKER][0] = r; color_hexes[COLOR_PICKER][1] = g; @@ -22238,6 +22309,112 @@ static int do_color_picker(void) } +static void render_color_picker_palette(void) +{ + int x, y; + Uint8 r, g, b; + void (*putpixel) (SDL_Surface *, int, int, Uint32); + + putpixel = putpixels[img_color_picker->format->BytesPerPixel]; + for (y = 0; y < img_color_picker->h; y++) + { + for (x = 0; x < img_color_picker->w; x++) + { + hsvtorgb((((float) y * 360.0) / ((float) img_color_picker->h)), + ((float) x / ((float) img_color_picker->w)), + 1.0 - (((float) color_picker_v) / ((float) img_color_picker_val->h)), + &r, &g, &b); + putpixel(img_color_picker, x, y, + SDL_MapRGBA(img_color_picker->format, r, g, b, 255)); + } + } +} + + +static void draw_color_picker_crosshairs(int color_picker_left, int color_picker_top, int color_picker_val_left, int color_picker_val_top) +{ + SDL_Rect dest; + int ctr_x; + + /* Hue/Saturation (the big rectangle) */ + + dest.x = color_picker_x + color_picker_left - 3; + dest.y = color_picker_y + color_picker_top - 1; + dest.w = 7; + dest.h = 3; + + SDL_FillRect(screen, &dest, SDL_MapRGB(screen->format, 0, 0, 0)); + + dest.x = color_picker_x + color_picker_left - 1; + dest.y = color_picker_y + color_picker_top - 3; + dest.w = 3; + dest.h = 7; + + SDL_FillRect(screen, &dest, SDL_MapRGB(screen->format, 0, 0, 0)); + + dest.x = color_picker_x + color_picker_left - 2; + dest.y = color_picker_y + color_picker_top; + dest.w = 5; + dest.h = 1; + + SDL_FillRect(screen, &dest, SDL_MapRGB(screen->format, 255, 255, 255)); + + dest.x = color_picker_x + color_picker_left; + dest.y = color_picker_y + color_picker_top - 2; + dest.w = 1; + dest.h = 5; + + SDL_FillRect(screen, &dest, SDL_MapRGB(screen->format, 255, 255, 255)); + + + /* Value (the slider) */ + + ctr_x = color_picker_val_left + img_back->w / 2; + + dest.x = ctr_x - 3; + dest.y = color_picker_v + color_picker_val_top - 1; + dest.w = 7; + dest.h = 3; + + SDL_FillRect(screen, &dest, SDL_MapRGB(screen->format, 0, 0, 0)); + + dest.x = ctr_x - 1; + dest.y = color_picker_v + color_picker_val_top - 3; + dest.w = 3; + dest.h = 7; + + SDL_FillRect(screen, &dest, SDL_MapRGB(screen->format, 0, 0, 0)); + + dest.x = ctr_x - 2; + dest.y = color_picker_v + color_picker_val_top; + dest.w = 5; + dest.h = 1; + + SDL_FillRect(screen, &dest, SDL_MapRGB(screen->format, 255, 255, 255)); + + dest.x = ctr_x; + dest.y = color_picker_v + color_picker_val_top - 2; + dest.w = 1; + dest.h = 5; + + SDL_FillRect(screen, &dest, SDL_MapRGB(screen->format, 255, 255, 255)); +} + + +static void draw_color_picker_values(int l, int t) +{ + SDL_Rect dest; + + dest.x = l; + dest.y = t; + dest.w = img_color_picker_val->w; + dest.h = img_color_picker_val->h; + + SDL_BlitSurface(img_color_picker_val, NULL, screen, &dest); + SDL_UpdateRect(screen, dest.x, dest.y, dest.w, dest.h); +} + + enum { COLOR_MIXER_BTN_RED, COLOR_MIXER_BTN_YELLOW, @@ -25954,13 +26131,14 @@ static void setup_colors(void) /* Add "Color Picker" color: */ - color_names[NUM_COLORS] = strdup(gettext("Pick a color.")); + color_names[NUM_COLORS] = strdup(gettext("Pick a color. The square shows all hues at varying levels of saturation. Use the slider to change the value.")); color_hexes[NUM_COLORS] = (Uint8 *) malloc(sizeof(Uint8) * 3); - color_hexes[NUM_COLORS][0] = 0; - color_hexes[NUM_COLORS][1] = 0; - color_hexes[NUM_COLORS][2] = 0; - color_picker_x = 0; - color_picker_y = 0; + color_hexes[NUM_COLORS][0] = 255; + color_hexes[NUM_COLORS][1] = 255; + color_hexes[NUM_COLORS][2] = 255; + color_picker_x = 0; /* Saturation */ + color_picker_y = 0; /* Hue */ + color_picker_v = 0; /* Value */ NUM_COLORS++; /* Add "Color Mixer" color: */ @@ -26926,6 +27104,7 @@ static void setup(void) show_progress_bar(screen); img_color_picker = loadimagerb(DATA_PREFIX "images/ui/color_picker.png"); + img_color_picker_val = loadimagerb(DATA_PREFIX "images/ui/color_picker_val.png"); /* Create toolbox and selector labels: */