aboutsummaryrefslogtreecommitdiff
path: root/generic/Color.c
diff options
context:
space:
mode:
authorlecoanet2001-06-25 11:20:03 +0000
committerlecoanet2001-06-25 11:20:03 +0000
commita3adeee4ca08764b8e78282c4b1cd57a0d830c0d (patch)
tree45ce35e7184460623d82f84842f63326466e3374 /generic/Color.c
parente3c6410aaa3aa3257d40a506b496c4cba137ae0c (diff)
downloadtkzinc-a3adeee4ca08764b8e78282c4b1cd57a0d830c0d.zip
tkzinc-a3adeee4ca08764b8e78282c4b1cd57a0d830c0d.tar.gz
tkzinc-a3adeee4ca08764b8e78282c4b1cd57a0d830c0d.tar.bz2
tkzinc-a3adeee4ca08764b8e78282c4b1cd57a0d830c0d.tar.xz
Modification des gradients
Diffstat (limited to 'generic/Color.c')
-rw-r--r--generic/Color.c683
1 files changed, 297 insertions, 386 deletions
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 <malloc.h>
+#include <string.h>
#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);
}
}