From a3adeee4ca08764b8e78282c4b1cd57a0d830c0d Mon Sep 17 00:00:00 2001 From: lecoanet Date: Mon, 25 Jun 2001 11:20:03 +0000 Subject: Modification des gradients --- generic/Color.c | 683 ++++++++++++++++++++++++-------------------------------- 1 file changed, 297 insertions(+), 386 deletions(-) (limited to 'generic/Color.c') diff --git a/generic/Color.c b/generic/Color.c index 443a3e6..64707b5 100644 --- a/generic/Color.c +++ b/generic/Color.c @@ -37,6 +37,7 @@ #include +#include #include "Types.h" #include "Image.h" @@ -139,37 +140,19 @@ typedef struct { } ValueKey; -typedef struct _ColorGradient { - Screen *screen; /* Screen on which the gradient will be used. */ - Visual *visual; /* Visual for all windows and pixmaps using - * the gradient. */ - int depth; /* Number of bits per pixel of drawables where - * the gradient will be used. */ - Colormap colormap; /* Colormap out of which pixels are - * allocated. */ - 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; - - /* * Maximum size of a color name including the \0. */ #define COLOR_NAME_SIZE 128 - /* - * Maximum intensity for a color. + * Maximum size of a gradient name including the \0. */ -#define MAX_INTENSITY 65535 +#define GRADIENT_NAME_SIZE 512 /* - * Number of steps in a border gradient (should be odd). + * Maximum intensity for a color. */ -#define BORDER_STEPS (RELIEF_STEPS*2+1) +#define MAX_INTENSITY 65535 /* * Hash table to map from a gradient's values (color, etc.) to a @@ -779,6 +762,7 @@ ZnFreeColor(XColor *color) /* Color to be released. Must have been * *---------------------------------------------------------------------- */ +#if 0 static void RgbToHsv(int r, int g, @@ -868,29 +852,30 @@ HsvToRgb(ZnReal h, break; } } - +#endif /* *---------------------------------------------------------------------- * - * RealizeColorGradient -- + * ZnRealizeGradient -- * - * 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 ZnColorGradientColor, so that the + * This procedure allocate the shades still unallocated in + * a gradient. The milestone colors are always allocated + * during the gradient's creation. + * It's called lazily by ZnGetGradientColor, so that the * colors aren't allocated until something is actually drawn * with them. * *---------------------------------------------------------------------- */ -static void -RealizeColorGradient(ColorGradient *grad, - Tk_Window tkwin) +void +ZnRealizeGradient(ZnGradient *grad, + Tk_Window tkwin) { - int i, num_colors, num_colors_2; - XColor *base, *first, *last, color; + int i, j, num_colors, num_shades; + int red_range, green_range, blue_range; + ZnGradientColor *first, *last; + XColor color; if (grad->realized) { return; @@ -899,177 +884,97 @@ RealizeColorGradient(ColorGradient *grad, /*printf("realizing gradient with %d(%d) colors\n", grad->num_colors, BORDER_STEPS);*/ num_colors = grad->num_colors; - num_colors_2 = num_colors/2; - first = grad->colors[0]; - last = grad->colors[num_colors-1]; - - /* - * Fill the in between colors. For a border gradient, this - * is done in two steps, first compute the colors between the - * base and the lightest, then the colors between base and the - * darkest. This ensure that the gradient will go through base. - * For others gradients proceed from lightest to darkest. - */ - 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");*/ - } -#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); - } - } -#endif - } -#if 1 - else { - int red_range, green_range, blue_range; + num_shades = grad->num_shades; + for (i = 0; i < grad->num_colors-1; i++) { + first = grad->colors[i]; + last = grad->colors[i+1]; /*printf("first color : %d %d %d, last color : %d %d %d\n", - first->red, first->green, first->blue, - last->red, last->green, last->blue);*/ - red_range = (int) last->red - (int) first->red; - green_range = (int) last->green - (int) first->green; - blue_range = (int) last->blue - (int) first->blue; - for (i = 1; i < num_colors-1; i++) { - color.red =(int) first->red + red_range * i / (num_colors-1); - color.green = (int) first->green + green_range * i / (num_colors-1); - color.blue = (int) first->blue + blue_range * i / (num_colors-1); - 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); + first->shades[0]->red, first->shades[0]->green, first->shades[0]->blue, + last->shades[0]->red, last->shades[0]->green, last->shades[0]->blue);*/ + red_range = (int) last->shades[0]->red - (int) first->shades[0]->red; + green_range = (int) last->shades[0]->green - (int) first->shades[0]->green; + blue_range = (int) last->shades[0]->blue - (int) first->shades[0]->blue; + for (j = 1; j < num_shades; j++) { + color.red =(int) first->shades[0]->red + red_range * j/num_shades; + color.green = (int) first->shades[0]->green + green_range * j/num_shades; + color.blue = (int) first->shades[0]->blue + blue_range * j/num_shades; + first->shades[j] = ZnGetColorByValue(tkwin, &color); } } -#endif - grad->realized = True; -} - -/* - *---------------------------------------------------------------------- - * - * ZnColorGradientSpan -- - * - *---------------------------------------------------------------------- - */ -int -ZnColorGradientSpan(ZnColorGradient gradient) -{ - return ((ColorGradient *) gradient)->num_colors; + grad->realized = True; } /* *---------------------------------------------------------------------- * - * ZnColorGradientColor -- + * ZnGetGradientColor -- * *---------------------------------------------------------------------- */ XColor * -ZnColorGradientColor(Tk_Window tkwin, - ZnColorGradient gradient, - int color_index) +ZnGetGradientColor(Tk_Window tkwin, + ZnGradient *grad, + ZnReal position) { - ColorGradient *grad = (ColorGradient *) gradient; + int index, min, max; + ZnGradientColor *color, *next_color; + XColor *shade; + ZnReal tt; + + if (!grad->realized) { + ZnRealizeGradient(grad, tkwin); + } - if (color_index < 0) { - color_index += grad->num_colors; + if (grad->num_colors == 1) { + return grad->colors[0]->shades[0]; } - if (color_index >= grad->num_colors) { - color_index = grad->num_colors-1; + if (position < 0.0) { + shade = grad->colors[0]->shades[0]; } - if (!grad->realized) { - RealizeColorGradient(grad, tkwin); + else if (position >= 100.0) { + shade = grad->colors[grad->num_colors-1]->shades[0]; } - return grad->colors[color_index]; + else { + min = 0; + max = grad->num_colors-1; + index = (max + min) / 2; + while (max - min != 1) { + if (grad->colors[index]->position < position) { + min = index; + } + else { + max = index; + } + index = (max + min) / 2; + } + color = grad->colors[index]; + next_color = grad->colors[index+1]; + tt = ((position - (ZnReal) color->position) / + (ZnReal) ((next_color->position - color->position) / grad->num_shades)); + index = REAL_TO_INT(tt); + shade = color->shades[index]; + } + + return shade; } /* - *---------------------------------------------------------------------- + *-------------------------------------------------------------- * - * ZnColorGradientMidColor -- + * ZnGradientFlat -- * - *---------------------------------------------------------------------- + * Returns true if the gradient is defined by a single + * color. + * + *-------------------------------------------------------------- */ -XColor * -ZnColorGradientMidColor(Tk_Window tkwin, - ZnColorGradient gradient) +ZnBool +ZnGradientFlat(ZnGradient *grad) { - ColorGradient *grad = (ColorGradient *) gradient; - - if (!grad->realized) { - RealizeColorGradient(grad, tkwin); - } - return grad->colors[grad->num_colors/2]; + return (grad->num_colors == 1); } @@ -1090,7 +995,7 @@ ZnColorGradientMidColor(Tk_Window tkwin, * 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 - * ZnColorGradientColor asserts that all the colors + * ZnGetGradientColor 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 @@ -1099,177 +1004,94 @@ ZnColorGradientMidColor(Tk_Window tkwin, * Side effects: * Data structures, etc. are allocated. * It is the caller's responsibility to eventually call - * ZnFreeColorGradient to release the resources. + * ZnFreeGradient to release the resources. * *-------------------------------------------------------------- */ -ZnColorGradient +ZnGradient * ZnGetReliefGradient(Tcl_Interp *interp, Tk_Window tkwin, Tk_Uid name) { - GradientKey key; - Tcl_HashEntry *hash; - ColorGradient *grad; - int i, new; - XColor *base, color; - - if (!initialized) { - ColorInit(); - } + XColor *base, light_color, dark_color; + char color_name[COLOR_NAME_SIZE]; + int tmp1, tmp2; + base = ZnGetColor(interp, tkwin, name); /* - * First, check to see if there's already a gradient that will work - * for this request. + * Compute the border gradient. + * + * Always consider that we are dealing with a color display with + * enough colors available. If the colormap is full (stressed) + * then just pray, the susbstitution algorithm may return something + * adequate ;-). + * + * The extremum colors get computed using whichever formula results + * in the greatest change in color: + * 1. Lighter color is half-way to white, darker color is half + * way to dark. + * 2. Lighter color is 40% brighter than base, darker color + * is 40% darker than base. + * The first approach works better for unsaturated colors, the + * second for saturated ones. + * + * NOTE: Colors are computed with integers not color shorts which + * may lead to overflow errors. */ - name = Tk_GetUid(name); - key.name = name; - key.colormap = Tk_Colormap(tkwin); - key.screen = Tk_Screen(tkwin); + tmp1 = (30 * (int) base->red)/100; + tmp2 = ((int) base->red)/2; + light_color.red = MIN(tmp1, tmp2); + tmp1 = (30 * (int) base->green)/100; + tmp2 = ((int) base->green)/2; + light_color.green = MIN(tmp1, tmp2); + tmp1 = (30 * (int) base->blue)/100; + tmp2 = ((int) base->blue)/2; + light_color.blue = MIN(tmp1, tmp2); - 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++; + tmp1 = MAX_INTENSITY;/*(170 * (int) base->red)/10;*/ + if (tmp1 > MAX_INTENSITY) { + tmp1 = MAX_INTENSITY; } - else { - /*printf("GetReliefGradient: Creating color gradient for %s\n", name);*/ - /* - * No satisfactory gradient exists yet. Initialize a new one. - */ - base = ZnGetColor(interp, tkwin, name); - if (base == NULL) { - Tcl_AppendResult(interp, " in border gradient", NULL); - Tcl_DeleteHashEntry(hash); - return NULL; - } + tmp2 = (MAX_INTENSITY + (int) base->red)/2; + dark_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; + dark_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; + dark_color.blue = MAX(tmp1, tmp2); - grad = (ColorGradient *) ZnMalloc(sizeof(ColorGradient) + - 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; - /* - * BORDER_STEPS should be odd, the base color - * takes the center position (assuming that the number - * of colors is odd). - */ - grad->colors[BORDER_STEPS/2] = base; + sprintf(color_name, "#%2d%2d%2d|#%2d%2d%2d|#%2d%2d%2d%%%d", + light_color.red, light_color.green, light_color.blue, + base->red, base->green, base->blue, + dark_color.red, dark_color.green, dark_color.blue, + RELIEF_STEPS); - /* - * Compute the border gradient. - * - * Always consider that we are dealing with a color display with - * enough colors available. If the colormap is full (stressed) - * then just pray, the susbstitution algorithm may return something - * adequate ;-). - * - * The extremum colors get computed using whichever formula results - * in the greatest change in color: - * 1. Lighter color is half-way to white, darker color is half - * way to dark. - * 2. Lighter color is 40% brighter than base, darker color - * is 40% darker than base. - * The first approach works better for unsaturated colors, the - * second for saturated ones. - * - * NOTE: Colors are computed with integers not color shorts which - * may lead to overflow errors. - */ -#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); - } -#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); - } -#endif - - /* - * Now init the in between colors to let RealizeColorGradient know - * what it has to do. - */ - for (i = BORDER_STEPS/2-1; i > 0; i--) { - grad->colors[i] = NULL; - } - for (i = BORDER_STEPS/2+1; i < BORDER_STEPS-1; i++) { - grad->colors[i] = NULL; - } - Tcl_SetHashValue(hash, grad); - } - - /* - * Delay the allocation of colors until they are actually - * needed for drawing. - */ - return (ZnColorGradient) grad; + return ZnGetGradient(interp, tkwin, color_name); } /* *-------------------------------------------------------------- * - * ZnGetColorGradient -- + * ZnGetGradient -- * * 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] + * used to display a gradient. * * Results: * The return value is a token for a data structure * describing a gradient. This token may be passed * to the drawing routines. This function allocate - * the two end colors in an attempt to use only + * the milestone colors in an attempt to use only * actually needed resources. The function - * ZnColorGradientColor asserts that all the colors + * ZnGetGradientColor 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 @@ -1278,32 +1100,32 @@ ZnGetReliefGradient(Tcl_Interp *interp, * Side effects: * Data structures, etc. are allocated. * It is the caller's responsibility to eventually call - * ZnFreeColorGradient to release the resources. + * ZnFreeGradient to release the resources. * *-------------------------------------------------------------- */ -ZnColorGradient -ZnGetColorGradientByValue(ZnColorGradient gradient) +ZnGradient * +ZnGetGradientByValue(ZnGradient *grad) { - ColorGradient *grad; - - grad = (ColorGradient *) gradient; grad->ref_count++; - return gradient; + return grad; } -ZnColorGradient -ZnGetColorGradient(Tcl_Interp *interp, - Tk_Window tkwin, - Tk_Uid name) +ZnGradient * +ZnGetGradient(Tcl_Interp *interp, + Tk_Window tkwin, + Tk_Uid name) { GradientKey key; Tcl_HashEntry *hash; - ColorGradient *grad; - int i, new, steps, num_tok; - XColor *first, *last; - char name_first[COLOR_NAME_SIZE], name_last[COLOR_NAME_SIZE]; + ZnGradient *grad; + int i, j, new, num_colors, num_shades; + char type, *scan_ptr; + int num_tok, angle; + int x, y; + char color_name[COLOR_NAME_SIZE]; + char buffer[GRADIENT_NAME_SIZE]; if (!initialized) { ColorInit(); @@ -1320,70 +1142,159 @@ ZnGetColorGradient(Tcl_Interp *interp, hash = Tcl_CreateHashEntry(&gradient_table, (char *) &key, &new); if (!new) { - grad = (ColorGradient *) Tcl_GetHashValue(hash); + grad = (ZnGradient *) Tcl_GetHashValue(hash); grad->ref_count++; } else { /* * No satisfactory gradient exists yet. Initialize a new one. */ - 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; + if ((name[0] == '%') || (name[0] == '/') || (name[0] == '(')) { + goto grad_err2; } - first = ZnGetColor(interp, tkwin, Tk_GetUid(name_first)); - if (first == NULL) { - grad_err2: - Tcl_AppendResult(interp, " in gradient", NULL); - goto grad_err; + + strcpy(buffer, name); + /* + * Try to obtain how many shades sould be drawn. + */ + num_shades = DEFAULT_NUM_SHADES; + if ((scan_ptr = strchr(buffer, '%'))) { + sscanf(scan_ptr, "%%%d", &num_shades); + /*printf("num shades = %d\n", num_shades);*/ + *scan_ptr = '\0'; } - if (num_tok != 1) { - last = ZnGetColor(interp, tkwin, Tk_GetUid(name_last)); - if (last == NULL) { - ZnFreeColor(first); - goto grad_err2; + /* + * Keep num_shades even. + */ + num_shades /= 2; + num_shades *= 2; + /* + * Then look at the gradient type. + */ + type = ZN_AXIAL_GRADIENT; + angle = 0; + if ((scan_ptr = strchr(buffer, '/'))) { + num_tok = sscanf(scan_ptr, "/%d", &angle); + if (num_tok != 1) { + grad_err2: + Tcl_DeleteHashEntry(hash); + Tcl_AppendResult(interp, "incorrect gradient format \"", + name, "\",", NULL); + return NULL; } + *scan_ptr = '\0'; } - else { - last = ZnGetColor(interp, tkwin, Tk_GetUid(name_first)); - steps = 2; + else if ((scan_ptr = strchr(buffer, '('))) { + num_tok = sscanf(scan_ptr, "(%d %d", &x, &y); + if (num_tok == 2) { + type = ZN_RADIAL_GRADIENT; + } + else { + goto grad_err2; + } + *scan_ptr = '\0'; } - /* - * Gradients span an odd number of colors. + * Next count the colors. */ - if (steps % 2 == 0) { - steps++; + scan_ptr = buffer; + num_colors = 1; + while ((scan_ptr = strchr(scan_ptr, '|'))) { + num_colors++; + scan_ptr++; } - - grad = (ColorGradient *) ZnMalloc(sizeof(ColorGradient) + - sizeof(XColor *)*(steps-1)); + /* + * Create the gradient structure. + */ + grad = (ZnGradient *) ZnMalloc(sizeof(ZnGradient) + + sizeof(ZnGradientColor *)*(num_colors-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->colors[0] = first; - grad->colors[steps-1] = last; - for (i = 1; i < steps-1; i++) { - grad->colors[i] = NULL; + grad->num_shades = num_shades; + grad->num_colors = num_colors; + grad->type = type; + if (type == ZN_AXIAL_GRADIENT) { + grad->g.angle = angle; + } + else { + grad->g.c.x = x; + grad->g.c.y = y; } - grad->num_colors = steps; grad->realized = False; - grad->relief = False; grad->hash = hash; Tcl_SetHashValue(hash, grad); + + scan_ptr = strtok(buffer, "|"); + for (i = 0; i < num_colors; i++) { + if (i != num_colors - 1) { + grad->colors[i] = (ZnGradientColor *) ZnMalloc(sizeof(ZnGradientColor) + + sizeof(XColor *)*(num_shades-1)); + } + else { + grad->colors[i] = (ZnGradientColor *) ZnMalloc(sizeof(ZnGradientColor)); + } + num_tok = sscanf(scan_ptr, "%s %d %d", color_name, &grad->colors[i]->position, + &grad->colors[i]->control); + if (num_tok == 0) { + Tcl_AppendResult(interp, "incorrect gradient format \"", + name, "\",", NULL); + grad_err: + Tcl_DeleteHashEntry(hash); + for (j = i; j >= 0; j--) { + ZnFree(grad->colors[j]); + } + ZnFree(grad); + return NULL; + } + grad->colors[i]->shades[0] = ZnGetColor(interp, tkwin, Tk_GetUid(color_name)); + if (grad->colors[i]->shades[0] == NULL) { + Tcl_AppendResult(interp, " in gradient,", NULL); + goto grad_err; + } + if (i != num_colors - 1) { + for (j = 1; j < num_shades-1; j++) { + grad->colors[i]->shades[j] = NULL; + } + } + if (i == 0) { + grad->colors[i]->position = 0; + } + else if (i == num_colors - 1) { + grad->colors[i]->position = 100; + } + else if (num_tok == 1) { + grad->colors[i]->position = 0; + } + if ((num_tok > 1) && (i > 0)) { + if ((grad->colors[i]->position > 100) || + (grad->colors[i]->position < 0) || + (grad->colors[i]->position < grad->colors[i-1]->position)) { + Tcl_AppendResult(interp, "incorrect color position in gradient \"", + name, "\",", NULL); + goto grad_err; + } + } + if (num_tok != 3) { + grad->colors[i]->control = 50; + } + else if ((grad->colors[i]->control < 0) || + (grad->colors[i]->control > 100)) { + Tcl_AppendResult(interp, "incorrect color control in gradient \"", + name, "\",", NULL); + goto grad_err; + } + scan_ptr = strtok(NULL, "|"); + } } /* * Delay the allocation of colors until they are actually * needed for drawing. */ - return (ZnColorGradient) grad; + return grad; } @@ -1393,9 +1304,7 @@ ZnGetColorGradient(Tcl_Interp *interp, * ZnNameOfColorGradient -- * * Given a gradient, return a textual string identifying - * the gradient. This can be either a single color (for - * gradients allocated by ZnGetReliefGradient) or a - * full gradient spec: color1:color2:steps. + * the gradient. * * Results: * The return value is the string that was used to create @@ -1407,10 +1316,8 @@ ZnGetColorGradient(Tcl_Interp *interp, *-------------------------------------------------------------- */ char * -ZnNameOfColorGradient(ZnColorGradient gradient) +ZnNameOfGradient(ZnGradient *grad) { - ColorGradient *grad = (ColorGradient *) gradient; - return ((GradientKey *) grad->hash->key.words)->name; } @@ -1418,7 +1325,7 @@ ZnNameOfColorGradient(ZnColorGradient gradient) /* *-------------------------------------------------------------- * - * ZnFreeColorGradient -- + * ZnFreeGradient -- * * This procedure is called when a gradient is no longer * needed. It frees the resources associated with the @@ -1434,19 +1341,23 @@ ZnNameOfColorGradient(ZnColorGradient gradient) *-------------------------------------------------------------- */ void -ZnFreeColorGradient(ZnColorGradient gradient) +ZnFreeGradient(ZnGradient *grad) { - ColorGradient *grad = (ColorGradient *) gradient; - int i; + int i, j; grad->ref_count--; if (grad->ref_count == 0) { - for (i = 0; i < grad->num_colors; i++) { - if (grad->colors[i] != NULL) { - ZnFreeColor(grad->colors[i]); + Tcl_DeleteHashEntry(grad->hash); + for (i = 0; i < grad->num_colors-1; i++) { + for (j = 0; j < grad->num_shades; j++) { + if (grad->colors[i]->shades[j] != NULL) { + ZnFreeColor(grad->colors[i]->shades[j]); + } } + ZnFree(grad->colors[i]); } - Tcl_DeleteHashEntry(grad->hash); + ZnFreeColor(grad->colors[grad->num_colors-1]->shades[0]); + ZnFree(grad->colors[grad->num_colors-1]); ZnFree(grad); } } -- cgit v1.1