From 409564a0ba44ba14748b0a505b2e1e8fa1453b3f Mon Sep 17 00:00:00 2001 From: lecoanet Date: Thu, 23 Mar 2000 14:17:58 +0000 Subject: Correction d'un bug dans le partage des gradients de couleur du � la non utilisation d'un Uid. D�sormais Tk_GetUid est systematiquement appel�e par pr�caution. Remplacement de ZnColorGradientPixel par ZnColorGradientColor plus g�n�rale. Ajout de ZnColorGradientMidColor pour r�cup�rer la couleur centrale d'un gradient. --- generic/Color.c | 367 ++++++++++++++++++++++++++++++++++++++++++++------------ generic/Color.h | 5 +- 2 files changed, 292 insertions(+), 80 deletions(-) (limited to 'generic') diff --git a/generic/Color.c b/generic/Color.c index a30e01c..7958314 100644 --- a/generic/Color.c +++ b/generic/Color.c @@ -150,6 +150,7 @@ typedef struct _ColorGradient { int ref_count; Tcl_HashEntry *hash; ZnBool realized; + ZnBool relief; int num_colors; /* Number of steps in the gradient. */ XColor *colors[1]; /* Colors of the gradient. */ } ColorGradient; @@ -490,6 +491,7 @@ ZnGetColor(Tcl_Interp *interp, * First, check to see if there's already a mapping for this color * name. */ + name = Tk_GetUid(name); name_key.name = name; name_key.colormap = Tk_Colormap(tkwin); name_key.display = Tk_Display(tkwin); @@ -763,13 +765,112 @@ ZnFreeColor(XColor *color) /* Color to be released. Must have been /* *---------------------------------------------------------------------- * + * RgbToHsv + * HsvToRgb -- + * + *---------------------------------------------------------------------- + */ +static void +RgbToHsv(int r, + int g, + int b, + ZnReal *h, + ZnReal *s, + ZnReal *v) +{ + ZnReal max, min, range, rc, gc, bc; + + max = (r > g) ? ((b > r) ? b : r) : ((b > g) ? b : g); + min = (r < g) ? ((b < r) ? b : r) : ((b < g) ? b : g); + range = max - min; + if (max == 0) { + *s = 0.0; + } + else { + *s = range / max; + } + if (*s == 0) { + *h = 0; + } + else { + rc = (max - r) / range; + gc = (max - g) / range; + bc = (max - b) / range; + *h = (max == r) ? (0.166667*(bc-gc)) : ((max == g) ? (0.166667*(2+rc-bc)) : (0.166667*(4+gc-rc))); + } + *v = max/65535.0; +} + +static void +HsvToRgb(ZnReal h, + ZnReal s, + ZnReal v, + unsigned short *r, + unsigned short *g, + unsigned short *b) +{ + int lv, i, p, q, t; + ZnReal f; + + lv = (int) (65535 * v); + if (s == 0) { + *r = *g = *b = lv; + return; + } + h *= 6.0; + if (h >= 6.0) { + h = 0.0; + } + i = (int) h; + f = h - i; + p = (int) (65535 * v * (1 - s)); + q = (int) (65535 * v * (1 - (s * f))); + t = (int) (65535 * v * (1 - (s * (1 - f)))); + switch (i) { + case 0: + *r = lv; + *g = t; + *b = p; + break; + case 1: + *r = q; + *g = lv; + *b = p; + break; + case 2: + *r = p; + *g = lv; + *b = t; + break; + case 3: + *r = p; + *g = q; + *b = lv; + break; + case 4: + *r = t; + *g = p; + *b = lv; + break; + case 5: + *r = lv; + *g = p; + *b = q; + break; + } +} + + +/* + *---------------------------------------------------------------------- + * * RealizeColorGradient -- * * This procedure allocate the colors still unallocated in * a gradient. The first and last colors are always allocated * during the gradient's creation. For 3D gradients the center * color is also allocated. - * It's called lazily by ZnColorGradientPixel, so that the + * It's called lazily by ZnColorGradientColor, so that the * colors aren't allocated until something is actually drawn * with them. * @@ -781,7 +882,6 @@ RealizeColorGradient(ColorGradient *grad, { int i, num_colors, num_colors_2; XColor *base, *first, *last, color; - int red_range, green_range, blue_range; if (grad->realized) { return; @@ -801,38 +901,74 @@ RealizeColorGradient(ColorGradient *grad, * darkest. This ensure that the gradient will go through base. * For others gradients proceed from lightest to darkest. */ - if ((num_colors == BORDER_STEPS) && - (grad->colors[BORDER_STEPS/2])) { - base = grad->colors[BORDER_STEPS/2]; - red_range = (int) base->red - (int) first->red; - green_range = (int) base->green - (int) first->green; - blue_range = (int) base->blue - (int) first->blue; - for (i = BORDER_STEPS/2-1; i > 0; i--) { - color.red = (int) first->red + red_range * i / (num_colors_2); - color.green = (int) first->green + green_range * i / (num_colors_2); - color.blue = (int) first->blue + blue_range * i / (num_colors_2); - grad->colors[i] = ZnGetColorByValue(tkwin, &color); - /*printf("getting color %x %x %x\n", color.red, color.green, color.blue);*/ - } - red_range = (int) last->red - (int) base->red; - green_range = (int) last->green - (int) base->green; - blue_range = (int) last->blue - (int) base->blue; - for (i = BORDER_STEPS/2-1; i > 0; i--) { - color.red = (int) base->red + red_range * i / (num_colors_2); - color.green = (int) base->green + green_range * i / (num_colors_2); - color.blue = (int) base->blue + blue_range * i / (num_colors_2); - /*printf("getting color %x %x %x\n", color.red, color.green, color.blue);*/ - grad->colors[BORDER_STEPS/2+i] = ZnGetColorByValue(tkwin, &color); + if (grad->relief) { +#if 1 + { + int red_range, green_range, blue_range; + + base = grad->colors[BORDER_STEPS/2]; + red_range = (int) base->red - (int) first->red; + green_range = (int) base->green - (int) first->green; + blue_range = (int) base->blue - (int) first->blue; + for (i = BORDER_STEPS/2-1; i > 0; i--) { + color.red = (int) first->red + red_range * i / num_colors_2; + color.green = (int) first->green + green_range * i / num_colors_2; + color.blue = (int) first->blue + blue_range * i / num_colors_2; + grad->colors[i] = ZnGetColorByValue(tkwin, &color); + /*printf("getting color %x %x %x\n", color.red, color.green, color.blue);*/ + } + red_range = (int) last->red - (int) base->red; + green_range = (int) last->green - (int) base->green; + blue_range = (int) last->blue - (int) base->blue; + for (i = BORDER_STEPS/2-1; i > 0; i--) { + color.red = (int) base->red + red_range * i / num_colors_2; + color.green = (int) base->green + green_range * i / num_colors_2; + color.blue = (int) base->blue + blue_range * i / num_colors_2; + /*printf("getting color %x %x %x\n", color.red, color.green, color.blue);*/ + grad->colors[BORDER_STEPS/2+i] = ZnGetColorByValue(tkwin, &color); + } + /*printf("base %x %x %x\n", grad->colors[BORDER_STEPS/2]->red, + grad->colors[BORDER_STEPS/2]->green, grad->colors[BORDER_STEPS/2]->blue); + printf("relief pixels: "); + for (i = 0; i < BORDER_STEPS; i++) { + printf("%d ", ZnPixel(grad->colors[i])); + } + printf("\n");*/ } - /*printf("base %x %x %x\n", grad->colors[BORDER_STEPS/2]->red, - grad->colors[BORDER_STEPS/2]->green, grad->colors[BORDER_STEPS/2]->blue); - printf("relief pixels: "); - for (i = 0; i < BORDER_STEPS; i++) { - printf("%d ", ZnPixel(grad->colors[i])); +#else + { + ZnReal h1, h2, h3; + ZnReal v1, v2, v3; + ZnReal s1, s2, s3; + ZnReal ds, dv; + + base = grad->colors[BORDER_STEPS/2]; + RgbToHsv(first->red, first->green, first->blue, &h1, &s1, &v1); + RgbToHsv(base->red, base->green, base->blue, &h2, &s2, &v2); + RgbToHsv(last->red, last->green, last->blue, &h3, &s3, &v3); + dv = v2 - v1; + for (i = BORDER_STEPS/2-1; i > 0; i--) { + HsvToRgb(h2, + s2, + v1 + (dv * i / num_colors_2), + &color.red, &color.green, &color.blue); + grad->colors[i] = ZnGetColorByValue(tkwin, &color); + } + ds = s3 - s2; + for (i = BORDER_STEPS/2-1; i > 0; i--) { + HsvToRgb(h2, + s1 - (ds * i / num_colors_2), + v2, + &color.red, &color.green, &color.blue); + grad->colors[BORDER_STEPS/2+i] = ZnGetColorByValue(tkwin, &color); + } } - printf("\n");*/ +#endif } +#if 1 else { + int red_range, green_range, blue_range; + red_range = (int) last->red - (int) first->red; green_range = (int) last->green - (int) first->green; blue_range = (int) last->blue - (int) first->blue; @@ -843,6 +979,24 @@ RealizeColorGradient(ColorGradient *grad, grad->colors[i] = ZnGetColorByValue(tkwin, &color); } } +#else + else { + ZnReal h1, h2, v1, v2, s1, s2, dh, ds, dv; + + RgbToHsv(first->red, first->green, first->blue, &h1, &s1, &v1); + RgbToHsv(last->red, last->green, last->blue, &h2, &s2, &v2); + dh = h2 - h1; + ds = s2 - s1; + dv = v2 - v1; + for (i = 1; i < num_colors-1; i++) { + HsvToRgb(h1 + (dh * i / (num_colors-1)), + s1 + (ds * i / (num_colors-1)), + v1 + (dv * i / (num_colors-1)), + &color.red, &color.green, &color.blue); + grad->colors[i] = ZnGetColorByValue(tkwin, &color); + } + } +#endif grad->realized = True; } @@ -864,13 +1018,13 @@ ZnColorGradientSpan(ZnColorGradient gradient) /* *---------------------------------------------------------------------- * - * ZnColorGradientPixel -- + * ZnColorGradientColor -- * *---------------------------------------------------------------------- */ -int -ZnColorGradientPixel(ZnColorGradient gradient, - Tk_Window tkwin, +XColor * +ZnColorGradientColor(Tk_Window tkwin, + ZnColorGradient gradient, int color_index) { ColorGradient *grad = (ColorGradient *) gradient; @@ -884,7 +1038,27 @@ ZnColorGradientPixel(ZnColorGradient gradient, if (!grad->realized) { RealizeColorGradient(grad, tkwin); } - return ZnPixel(grad->colors[color_index]); + return grad->colors[color_index]; +} + + +/* + *---------------------------------------------------------------------- + * + * ZnColorGradientMidColor -- + * + *---------------------------------------------------------------------- + */ +XColor * +ZnColorGradientMidColor(Tk_Window tkwin, + ZnColorGradient gradient) +{ + ColorGradient *grad = (ColorGradient *) gradient; + + if (!grad->realized) { + RealizeColorGradient(grad, tkwin); + } + return grad->colors[grad->num_colors/2]; } @@ -905,7 +1079,7 @@ ZnColorGradientPixel(ZnColorGradient gradient, * to the drawing routines. This function allocate * the base color and the two end colors in an attempt * to use only actually needed resources. The function - * ZnColorGradientPixel asserts that all the colors + * ZnColorGradientColor asserts that all the colors * get allocated when needed. * If an error prevented the gradient from being created * then NULL is returned and an error message will be @@ -926,7 +1100,7 @@ ZnGetReliefGradient(Tcl_Interp *interp, GradientKey key; Tcl_HashEntry *hash; ColorGradient *grad; - int i, new, tmp1, tmp2; + int i, new; XColor *base, color; if (!initialized) { @@ -936,17 +1110,20 @@ ZnGetReliefGradient(Tcl_Interp *interp, /* * First, check to see if there's already a gradient that will work * for this request. - */ + */ + name = Tk_GetUid(name); key.name = name; key.colormap = Tk_Colormap(tkwin); key.screen = Tk_Screen(tkwin); hash = Tcl_CreateHashEntry(&gradient_table, (char *) &key, &new); if (!new) { + /* printf("GetReliefGradient: Reusing color gradient for %s\n", name);*/ grad = (ColorGradient *) Tcl_GetHashValue(hash); grad->ref_count++; } else { + /*printf("GetReliefGradient: Creating color gradient for %s\n", name);*/ /* * No satisfactory gradient exists yet. Initialize a new one. */ @@ -958,13 +1135,14 @@ ZnGetReliefGradient(Tcl_Interp *interp, } grad = (ColorGradient *) ZnMalloc(sizeof(ColorGradient) + - sizeof(XColor *)*(BORDER_STEPS-1)); + sizeof(XColor *)*(BORDER_STEPS-1)); grad->screen = Tk_Screen(tkwin); grad->visual = Tk_Visual(tkwin); grad->depth = Tk_Depth(tkwin); grad->colormap = key.colormap; grad->ref_count = 1; grad->realized = False; + grad->relief = True; grad->hash = hash; grad->num_colors = BORDER_STEPS; /* @@ -994,36 +1172,54 @@ ZnGetReliefGradient(Tcl_Interp *interp, * NOTE: Colors are computed with integers not color shorts which * may lead to overflow errors. */ - tmp1 = (60 * (int) base->red)/100; - tmp2 = (MAX_INTENSITY + (int) base->red)/2; - color.red = MIN(tmp1, tmp2); - tmp1 = (60 * (int) base->green)/100; - tmp2 = (MAX_INTENSITY + (int) base->green)/2; - color.green = MIN(tmp1, tmp2); - tmp1 = (60 * (int) base->blue)/100; - tmp2 = (MAX_INTENSITY + (int) base->blue)/2; - color.blue = MIN(tmp1, tmp2); - grad->colors[0] = ZnGetColorByValue(tkwin, &color); - - tmp1 = (14 * (int) base->red)/10; - if (tmp1 > MAX_INTENSITY) { - tmp1 = MAX_INTENSITY; - } - tmp2 = (MAX_INTENSITY + (int) base->red)/2; - color.red = MAX(tmp1, tmp2); - tmp1 = (14 * (int) base->green)/10; - if (tmp1 > MAX_INTENSITY) { - tmp1 = MAX_INTENSITY; +#if 1 + { + int tmp1, tmp2; + + tmp1 = (30 * (int) base->red)/100; + tmp2 = ((int) base->red)/2; + color.red = MIN(tmp1, tmp2); + tmp1 = (30 * (int) base->green)/100; + tmp2 = ((int) base->green)/2; + color.green = MIN(tmp1, tmp2); + tmp1 = (30 * (int) base->blue)/100; + tmp2 = ((int) base->blue)/2; + color.blue = MIN(tmp1, tmp2); + grad->colors[0] = ZnGetColorByValue(tkwin, &color); + + tmp1 = MAX_INTENSITY;/*(170 * (int) base->red)/10;*/ + if (tmp1 > MAX_INTENSITY) { + tmp1 = MAX_INTENSITY; + } + tmp2 = (MAX_INTENSITY + (int) base->red)/2; + color.red = MAX(tmp1, tmp2); + tmp1 = MAX_INTENSITY;/*(170 * (int) base->green)/10;*/ + if (tmp1 > MAX_INTENSITY) { + tmp1 = MAX_INTENSITY; + } + tmp2 = (MAX_INTENSITY + (int) base->green)/2; + color.green = MAX(tmp1, tmp2); + tmp1 = MAX_INTENSITY;/*(170 * (int) base->blue)/10;*/ + if (tmp1 > MAX_INTENSITY) { + tmp1 = MAX_INTENSITY; + } + tmp2 = (MAX_INTENSITY + (int) base->blue)/2; + color.blue = MAX(tmp1, tmp2); + grad->colors[BORDER_STEPS-1] = ZnGetColorByValue(tkwin, &color); } - tmp2 = (MAX_INTENSITY + (int) base->green)/2; - color.green = MAX(tmp1, tmp2); - tmp1 = (14 * (int) base->blue)/10; - if (tmp1 > MAX_INTENSITY) { - tmp1 = MAX_INTENSITY; +#else + { + ZnReal h, s, v, vmin, smin; + + RgbToHsv(base->red, base->green, base->blue, &h, &s, &v); + vmin = v * 0.3; + smin = s * 0.3; + HsvToRgb(h, s, vmin, &color.red, &color.green, &color.blue); + grad->colors[0] = ZnGetColorByValue(tkwin, &color); + HsvToRgb(h, smin, v, &color.red, &color.green, &color.blue); + grad->colors[BORDER_STEPS-1] = ZnGetColorByValue(tkwin, &color); } - tmp2 = (MAX_INTENSITY + (int) base->blue)/2; - color.blue = MAX(tmp1, tmp2); - grad->colors[BORDER_STEPS-1] = ZnGetColorByValue(tkwin, &color); +#endif /* * Now init the in between colors to let RealizeColorGradient know @@ -1054,7 +1250,7 @@ ZnGetReliefGradient(Tcl_Interp *interp, * Create a data structure containing a range of colors * used to display a gradient. Name contains the gradient * description in the form: - * color1:color2:steps + * color1[ color2 steps] * * Results: * The return value is a token for a data structure @@ -1062,7 +1258,7 @@ ZnGetReliefGradient(Tcl_Interp *interp, * to the drawing routines. This function allocate * the two end colors in an attempt to use only * actually needed resources. The function - * ZnColorGradientPixel asserts that all the colors + * ZnColorGradientColor asserts that all the colors * get allocated when needed. * If an error prevented the gradient from being created * then NULL is returned and an error message will be @@ -1106,6 +1302,7 @@ ZnGetColorGradient(Tcl_Interp *interp, * First, check to see if there's already a gradient that will work * for this request. */ + name = Tk_GetUid(name); key.name = name; key.colormap = Tk_Colormap(tkwin); key.screen = Tk_Screen(tkwin); @@ -1119,28 +1316,41 @@ ZnGetColorGradient(Tcl_Interp *interp, /* * No satisfactory gradient exists yet. Initialize a new one. */ - num_tok = sscanf(name, "%s:%s:%d", name_first, name_last, &steps); - if ((num_tok != 3) || (steps < 2)) { + num_tok = sscanf(name, "%s %s %d", name_first, name_last, &steps); + if ((num_tok != 1) && ((num_tok != 3) || (steps < 2))) { Tcl_AppendResult(interp, "incorrect gradient format \"", name, "\"", NULL); grad_err: Tcl_DeleteHashEntry(hash); return NULL; } - first = ZnGetColor(interp, tkwin, name_first); + first = ZnGetColor(interp, tkwin, Tk_GetUid(name_first)); if (first == NULL) { grad_err2: Tcl_AppendResult(interp, " in gradient", NULL); goto grad_err; } - last = ZnGetColor(interp, tkwin, name_last); - if (last == NULL) { - ZnFreeColor(first); - goto grad_err2; + if (num_tok != 1) { + last = ZnGetColor(interp, tkwin, Tk_GetUid(name_last)); + if (last == NULL) { + ZnFreeColor(first); + goto grad_err2; + } + } + else { + last = ZnGetColor(interp, tkwin, Tk_GetUid(name_first)); + steps = 2; + } + + /* + * Gradients span an odd number of colors. + */ + if (steps % 2 == 0) { + steps++; } grad = (ColorGradient *) ZnMalloc(sizeof(ColorGradient) + - sizeof(XColor *)*(steps-1)); + sizeof(XColor *)*(steps-1)); grad->screen = Tk_Screen(tkwin); grad->visual = Tk_Visual(tkwin); grad->depth = Tk_Depth(tkwin); @@ -1148,11 +1358,12 @@ ZnGetColorGradient(Tcl_Interp *interp, grad->ref_count = 1; grad->colors[0] = first; grad->colors[steps-1] = last; - for (i = 0; i < steps-1; i++) { + for (i = 1; i < steps-1; i++) { grad->colors[i] = NULL; } grad->num_colors = steps; grad->realized = False; + grad->relief = False; grad->hash = hash; Tcl_SetHashValue(hash, grad); } diff --git a/generic/Color.h b/generic/Color.h index 53da97b..140c2ea 100644 --- a/generic/Color.h +++ b/generic/Color.h @@ -47,8 +47,9 @@ ZnColorGradient ZnGetColorGradientByValue(ZnColorGradient gradient); ZnColorGradient ZnGetReliefGradient(Tcl_Interp *interp, Tk_Window tkwin, Tk_Uid name); int ZnColorGradientSpan(ZnColorGradient); -int ZnColorGradientPixel(ZnColorGradient gradient, Tk_Window tkwin, - int color_index); +XColor *ZnColorGradientColor(Tk_Window tkwin, ZnColorGradient gradient, + int color_index); +XColor *ZnColorGradientMidColor(Tk_Window tkwin, ZnColorGradient gradient); char *ZnNameOfColorGradient(ZnColorGradient gradient); void ZnFreeColorGradient(ZnColorGradient gradient); -- cgit v1.1