aboutsummaryrefslogtreecommitdiff
path: root/generic/Color.c
diff options
context:
space:
mode:
authorlecoanet2000-03-23 14:17:58 +0000
committerlecoanet2000-03-23 14:17:58 +0000
commit409564a0ba44ba14748b0a505b2e1e8fa1453b3f (patch)
tree2ce08ce3d2c9092a7cd75a39e2dde39ff7a5c6c5 /generic/Color.c
parent3b0e88db7f876e82b8796b810a7fbcbcc815a600 (diff)
downloadtkzinc-409564a0ba44ba14748b0a505b2e1e8fa1453b3f.zip
tkzinc-409564a0ba44ba14748b0a505b2e1e8fa1453b3f.tar.gz
tkzinc-409564a0ba44ba14748b0a505b2e1e8fa1453b3f.tar.bz2
tkzinc-409564a0ba44ba14748b0a505b2e1e8fa1453b3f.tar.xz
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.
Diffstat (limited to 'generic/Color.c')
-rw-r--r--generic/Color.c367
1 files changed, 289 insertions, 78 deletions
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);
}