aboutsummaryrefslogtreecommitdiff
path: root/generic/Color.c
diff options
context:
space:
mode:
Diffstat (limited to 'generic/Color.c')
-rw-r--r--generic/Color.c1220
1 files changed, 0 insertions, 1220 deletions
diff --git a/generic/Color.c b/generic/Color.c
deleted file mode 100644
index 2165c99..0000000
--- a/generic/Color.c
+++ /dev/null
@@ -1,1220 +0,0 @@
-/*
- * Color.c -- Color management module.
- *
- * Authors : Patrick Lecoanet.
- * Creation date : Thu Dec 16 15:41:53 1999
- *
- * $Id$
- */
-
-/*
- * Copyright (c) 1999 - 2005 CENA, Patrick Lecoanet --
- *
- * See the file "Copyright" for information on usage and redistribution
- * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
- *
- */
-
-/*
- * Most of this file is derived from Tk color code and thus
- * also copyrighted:
- *
- * Copyright (c) 1991-1994 The Regents of the University of California.
- * Copyright (c) 1994-1995 Sun Microsystems, Inc.
- *
- */
-
-
-#include <string.h>
-#include <stdlib.h>
-
-#include "Types.h"
-#include "Image.h"
-#include "Color.h"
-#include "Geo.h"
-#include "Transfo.h"
-
-
-/*
- * Maximum size of a color name including the \0.
- */
-#define COLOR_NAME_SIZE 32
-
-/*
- * Maximum intensity for a color.
- */
-#define MAX_INTENSITY 65535
-
-/*
- * Hash table to map from a gradient's values (color, etc.) to a
- * gradient structure for those values.
- */
-static Tcl_HashTable gradient_table;
-
-static int initialized = 0; /* 0 means static structures haven't been
- * initialized yet. */
-
-
-/*
- *----------------------------------------------------------------------
- *
- * ColorInit --
- *
- * Initialize the structure used for color management.
- *
- * Results:
- * None.
- *
- * Side effects:
- * Read the code.
- *
- *----------------------------------------------------------------------
- */
-static void
-ColorInit()
-{
- initialized = 1;
- Tcl_InitHashTable(&gradient_table, TCL_STRING_KEYS);
-}
-
-
-/*
- *----------------------------------------------------------------------
- *
- * ZnGetGradientColor
- * ZnInterpGradientColor --
- *
- *----------------------------------------------------------------------
- */
-XColor *
-ZnGetGradientColor(ZnGradient *grad,
- ZnReal position,
- unsigned short *alpha)
-{
- int index, min, max;
- XColor *shade=NULL;
-
- if ((grad->num_actual_colors == 1) || (position <= 0.0)) {
- if (alpha) {
- *alpha = grad->actual_colors[0].alpha;
- }
- return grad->actual_colors[0].rgb;
- }
- if (position >= 100.0) {
- if (alpha) {
- *alpha = grad->actual_colors[grad->num_actual_colors-1].alpha;
- }
- shade = grad->actual_colors[grad->num_actual_colors-1].rgb;
- }
- else {
- min = 0;
- max = grad->num_actual_colors-1;
- index = (max + min) / 2;
- while (max - min != 1) {
- /*printf("color index %d, min: %d, max: %d\n", index, min, max);*/
- if (grad->actual_colors[index].position < position) {
- min = index;
- }
- else {
- max = index;
- }
- index = (max + min) / 2;
- }
- shade = grad->actual_colors[index].rgb;
- if (alpha) {
- *alpha = grad->actual_colors[index].alpha;
- }
- }
-
- return shade;
-}
-
-void
-ZnInterpGradientColor(ZnGradient *grad,
- ZnReal position,
- XColor *color,
- unsigned short *alpha)
-{
- int index, min, max;
- ZnGradientColor *gc1, *gc2;
- ZnReal rel_pos;
-
- if ((grad->num_actual_colors == 1) || (position <= 0.0)) {
- *alpha = grad->actual_colors[0].alpha;
- *color = *grad->actual_colors[0].rgb;
- }
- else if (position >= 100.0) {
- *alpha = grad->actual_colors[grad->num_actual_colors-1].alpha;
- *color = *grad->actual_colors[grad->num_actual_colors-1].rgb;
- }
- else {
- min = 0;
- max = grad->num_actual_colors-1;
- index = (max + min) / 2;
- while (max - min != 1) {
- /*printf("color index %d, min: %d, max: %d\n", index, min, max);*/
- if (grad->actual_colors[index].position < position) {
- min = index;
- }
- else {
- max = index;
- }
- index = (max + min) / 2;
- }
- gc1 = &grad->actual_colors[index];
- gc2 = &grad->actual_colors[index+1];
- rel_pos = (position - gc1->position) * 100.0 / (gc2->position - gc1->position);
-
- if (rel_pos > gc1->control) {
- rel_pos = (rel_pos - gc1->control) * 100.0 / (100.0 - gc1->control);
- color->red = gc1->mid_rgb->red +
- (unsigned short) ((gc2->rgb->red - gc1->mid_rgb->red) * rel_pos / 100.0);
- color->green = gc1->mid_rgb->green +
- (unsigned short) ((gc2->rgb->green - gc1->mid_rgb->green) * rel_pos / 100.0);
- color->blue = gc1->mid_rgb->blue +
- (unsigned short) ((gc2->rgb->blue - gc1->mid_rgb->blue) * rel_pos / 100.0);
- *alpha = gc1->mid_alpha +
- (unsigned short) ((gc2->alpha - gc1->mid_alpha) * rel_pos / 100.0);
- }
- else {
- rel_pos = rel_pos * 100.0 / gc1->control;
- color->red = gc1->rgb->red +
- (unsigned short) ((gc1->mid_rgb->red - gc1->rgb->red) * rel_pos / 100.0);
- color->green = gc1->rgb->green +
- (unsigned short) ((gc1->mid_rgb->green - gc1->rgb->green) * rel_pos / 100.0);
- color->blue = gc1->rgb->blue +
- (unsigned short) ((gc1->mid_rgb->blue - gc1->rgb->blue) * rel_pos / 100.0);
- *alpha = gc1->alpha +
- (unsigned short) ((gc1->mid_alpha - gc1->alpha) * rel_pos / 100.0);
- }
- }
-}
-
-
-/*
- *--------------------------------------------------------------
- *
- * ZnGradientFlat --
- *
- * Returns true if the gradient is defined by a single
- * color.
- *
- *--------------------------------------------------------------
- */
-ZnBool
-ZnGradientFlat(ZnGradient *grad)
-{
- return (grad->num_actual_colors == 1);
-}
-
-
-/*
- *--------------------------------------------------------------
- *
- * ZnGetReliefGradient --
- *
- * Create a data structure containing a range of colors
- * used to display a 3D border. Name contains the base
- * color for the border. This is a slight variation on
- * the syntax of a gradient that make life easier in this
- * simple case.
- *
- * Results:
- * The return value is a token for a data structure
- * describing a gradient. This token may be passed
- * to the drawing routines.
- * If an error prevented the gradient from being created
- * then NULL is returned and an error message will be
- * left in interp.
- *
- * Side effects:
- * Data structures, etc. are allocated.
- * It is the caller's responsibility to eventually call
- * ZnFreeGradient to release the resources.
- *
- *--------------------------------------------------------------
- */
-ZnGradient *
-ZnGetReliefGradient(Tcl_Interp *interp,
- Tk_Window tkwin,
- Tk_Uid name,
- unsigned short alpha)
-{
- XColor *base, light_color, dark_color, color;
- char color_name[COLOR_NAME_SIZE];
- char buffer[COLOR_NAME_SIZE*(3+2*ZN_RELIEF_STEPS)];
- int j, tmp1, tmp2;
- int red_range, green_range, blue_range;
-
- base = Tk_GetColor(interp, tkwin, name);
- /*
- * 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.
- */
- tmp1 = (30 * (int) base->red)/100;
- tmp2 = ((int) base->red)/2;
- dark_color.red = MIN(tmp1, tmp2);
- tmp1 = (30 * (int) base->green)/100;
- tmp2 = ((int) base->green)/2;
- dark_color.green = MIN(tmp1, tmp2);
- tmp1 = (30 * (int) base->blue)/100;
- tmp2 = ((int) base->blue)/2;
- dark_color.blue = MIN(tmp1, tmp2);
-
- tmp1 = MAX_INTENSITY;/*(170 * (int) base->red)/10;*/
- if (tmp1 > MAX_INTENSITY) {
- tmp1 = MAX_INTENSITY;
- }
- tmp2 = (MAX_INTENSITY + (int) base->red)/2;
- light_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;
- light_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;
- light_color.blue = MAX(tmp1, tmp2);
-
- buffer[0] = 0;
- sprintf(color_name, "#%02x%02x%02x;%d|",
- dark_color.red/256, dark_color.green/256, dark_color.blue/256, alpha);
- red_range = (int) base->red - (int) dark_color.red;
- green_range = (int) base->green - (int) dark_color.green;
- blue_range = (int) base->blue - (int) dark_color.blue;
- strcat(buffer, color_name);
- for (j = 1; j < ZN_RELIEF_STEPS; j++) {
- color.red =(int) dark_color.red + red_range * j/ZN_RELIEF_STEPS;
- color.green = (int) dark_color.green + green_range * j/ZN_RELIEF_STEPS;
- color.blue = (int) dark_color.blue + blue_range * j/ZN_RELIEF_STEPS;
- sprintf(color_name, "#%02x%02x%02x;%d %d|",
- color.red/256, color.green/256, color.blue/256, alpha, 50/ZN_RELIEF_STEPS*j);
- strcat(buffer, color_name);
- }
- sprintf(color_name, "#%02x%02x%02x;%d 50|",
- base->red/256, base->green/256, base->blue/256, alpha);
- strcat(buffer, color_name);
- red_range = (int) light_color.red - (int) base->red;
- green_range = (int) light_color.green - (int) base->green;
- blue_range = (int) light_color.blue - (int) base->blue;
- for (j = 1; j < ZN_RELIEF_STEPS; j++) {
- color.red = (int) base->red + red_range * j/ZN_RELIEF_STEPS;
- color.green = (int) base->green + green_range * j/ZN_RELIEF_STEPS;
- color.blue = (int) base->blue + blue_range * j/ZN_RELIEF_STEPS;
- sprintf(color_name, "#%02x%02x%02x;%d %d|",
- color.red/256, color.green/256, color.blue/256, alpha, 50+50/ZN_RELIEF_STEPS*j);
- strcat(buffer, color_name);
- }
- sprintf(color_name, "#%02x%02x%02x;%d",
- light_color.red/256, light_color.green/256, light_color.blue/256, alpha);
- strcat(buffer, color_name);
-
- /*printf("gradient relief: %s \n", buffer);*/
- return ZnGetGradient(interp, tkwin, buffer);
-}
-
-
-/*
- *--------------------------------------------------------------
- *
- * ZnNameGradient
- * ZnDeleteGradientName --
- *
- * Save a gradient under a name or suppress the gradient
- * name binding. The save function returns false if the
- * name is already in use.
- *
- *--------------------------------------------------------------
- */
-ZnBool
-ZnNameGradient(Tcl_Interp *interp,
- Tk_Window tkwin,
- char *grad_descr,
- char *name)
-{
- Tcl_HashEntry *hash;
- int new;
- ZnGradient *grad;
- XColor color;
-
- /*
- * First try to find if the name interfere with a color name,
- * this must be avoided. Gradients may be described by a single
- * color name and gradient descriptions / names share the same
- * name space.
- */
- if (XParseColor(Tk_Display(tkwin), Tk_Colormap(tkwin), name, &color)) {
- Tcl_AppendResult(interp, "gradient name \"", name,
- "\", is a color name", NULL);
- return False;
- }
- grad = ZnGetGradient(interp, tkwin, grad_descr);
- if (!grad) {
- Tcl_AppendResult(interp, "gradient specification \"", grad_descr,
- "\", is invalid", NULL);
- return False;
- }
- hash = Tcl_CreateHashEntry(&gradient_table, Tk_GetUid(name), &new);
- if (!new) {
- ZnFreeGradient(grad);
- Tcl_AppendResult(interp, "gradient name \"", name,
- "\", is already in use", NULL);
- return False;
- }
- else {
- Tcl_SetHashValue(hash, grad);
- }
-
- return True;
-}
-
-ZnBool
-ZnGradientNameExists(char *name)
-{
- if (!initialized) {
- return False;
- }
- return Tcl_FindHashEntry(&gradient_table, Tk_GetUid(name)) != NULL;
-}
-
-void
-ZnDeleteGradientName(char *name)
-{
- Tcl_HashEntry *hash;
-
- if (!initialized) {
- return;
- }
-
- hash = Tcl_FindHashEntry(&gradient_table, Tk_GetUid(name));
- if (hash) {
- Tcl_DeleteHashEntry(hash);
- ZnFreeGradient((ZnGradient *) Tcl_GetHashValue(hash));
- }
-}
-
-static void
-InterpolateGradientColor(Tk_Window tkwin,
- ZnGradientColor *gc1, /* First color */
- ZnGradientColor *gc2, /* Next color */
- ZnGradientColor *gc_interp,/* New interpolated color */
- ZnGradientColor *gc_adjust,/* Adjusted first color.
- * Needed if interested in
- * the range color1 interp
- * color. */
- int interp_pos,
- int min_pos,
- int span)
-{
- ZnReal pos1, pos2, ipos, interp_rel_pos, tmp;
- XColor rgb;
-
- //printf("interp_pos: %d, min_pos: %d, span: %d\n ", interp_pos, min_pos, span);
- pos1 = ((ZnReal)gc1->position-(ZnReal)min_pos)/(ZnReal)span;
- pos2 = ((ZnReal)gc2->position-(ZnReal)min_pos)/(ZnReal)span;
- ipos = ((ZnReal)interp_pos-(ZnReal)min_pos)/(ZnReal)span;
- interp_rel_pos = (ipos-pos1)*100/(pos2-pos1);
-
- //printf("pos1: %g, pos2: %g, interp_rel_pos: %g\n", pos1, pos2, interp_rel_pos);
- if (interp_rel_pos < gc1->control) {
- tmp = interp_rel_pos * 100.0 / gc1->control;
- //printf("rgb : %d, mid rgb : %d\n\n", gc1->rgb, gc1->mid_rgb);
- rgb.red = (unsigned short) (gc1->rgb->red + (gc1->mid_rgb->red - gc1->rgb->red) * tmp / 100.0);
- rgb.green = (unsigned short) (gc1->rgb->green + (gc1->mid_rgb->green - gc1->rgb->green) * tmp / 100.0);
- rgb.blue = (unsigned short) (gc1->rgb->blue + (gc1->mid_rgb->blue - gc1->rgb->blue) * tmp / 100.0);
- gc_interp->alpha = (unsigned char) (gc1->alpha + (gc1->mid_alpha - gc1->alpha) * tmp / 100.0);
- }
- else if (interp_rel_pos > gc1->control) {
- tmp = (interp_rel_pos - gc1->control) * 100.0 / (100.0 - gc1->control);
- rgb.red = (unsigned short) (gc1->mid_rgb->red + (gc2->rgb->red - gc1->mid_rgb->red)*tmp / 100.0);
- rgb.green = (unsigned short) (gc1->mid_rgb->green + (gc2->rgb->green - gc1->mid_rgb->green)*tmp / 100.0);
- rgb.blue = (unsigned short) (gc1->mid_rgb->blue + (gc2->rgb->blue - gc1->mid_rgb->blue)*tmp / 100.0);
- gc_interp->alpha = (unsigned char) (gc1->mid_alpha + (gc2->alpha - gc1->mid_alpha)*tmp / 100.0);
- }
- else {
- rgb = *gc1->mid_rgb;
- gc_interp->alpha = gc1->mid_alpha;
- }
- gc_interp->rgb = Tk_GetColorByValue(tkwin, &rgb);
-
- if (!gc_adjust) {
- /*
- * Interested in the segment from the interpolated color
- * to color 2.
- */
- gc_interp->position = 0;
- if (interp_rel_pos < gc1->control) {
- gc_interp->control = gc1->control - (int) interp_rel_pos;
- gc_interp->mid_rgb = Tk_GetColorByValue(tkwin, gc1->mid_rgb);
- gc_interp->mid_alpha = gc1->mid_alpha;
- }
- else {
- rgb.red = gc_interp->rgb->red+(gc2->rgb->red-gc_interp->rgb->red)/2;
- rgb.green = gc_interp->rgb->green+(gc2->rgb->green-gc_interp->rgb->green)/2;
- rgb.blue = gc_interp->rgb->blue+(gc2->rgb->blue-gc_interp->rgb->blue)/2;
- gc_interp->mid_rgb = Tk_GetColorByValue(tkwin, &rgb);
- gc_interp->mid_alpha = gc_interp->alpha + (gc2->alpha - gc_interp->alpha)/2;
- gc_interp->control = 50;
- }
- }
- else {
- /*
- * Interested in the segment from color 1 (color adjusted) to
- * the interpolated color.
- */
- gc_interp->position = 100;
- gc_interp->mid_rgb = NULL;
- gc_interp->mid_alpha = 100;
- if (interp_rel_pos <= gc1->control) {
- rgb.red = gc1->rgb->red+(gc_interp->rgb->red-gc1->rgb->red)/2;
- rgb.green = gc1->rgb->green+(gc_interp->rgb->green-gc1->rgb->green)/2;
- rgb.blue = gc1->rgb->blue+(gc_interp->rgb->blue-gc1->rgb->blue)/2;
- Tk_FreeColor(gc_adjust->mid_rgb);
- gc_adjust->mid_rgb = Tk_GetColorByValue(tkwin, &rgb);
- gc_adjust->mid_alpha = gc1->alpha + (gc_interp->alpha - gc1->alpha)/2;
- gc_adjust->control = 50;
- }
- }
- //printf("out of InterpolateGradientColor\n");
-}
-
-
-static void
-ReduceGradient(Tk_Window tkwin,
- ZnGradient *grad)
-{
- ZnReal dx, dy, len, angle;
- ZnTransfo t;
- ZnPoint pbbox[4], pgrad[4];
- ZnReal maxx, minx, span, start_in_new, end_in_new;
- int minx100, maxx100, span100;
- int i, j, first_color, last_color;
- ZnBool interpolate_first, interpolate_last;
-
- //printf("In ReduceGradient\n");
- dx = grad->e.x - grad->p.x;
- dy = grad->e.y - grad->p.y;
- len = sqrt(dx*dx+dy*dy);
- angle = acos(dx/len);
- if (dy < 0) {
- angle = 2*M_PI - angle;
- }
- grad->angle = (int) -ZnRadDeg(angle);
-
- if (grad->type == ZN_CONICAL_GRADIENT) {
- unchanged:
- grad->actual_colors = grad->colors_in;
- grad->num_actual_colors = grad->num_colors_in;
- return;
- }
-
- ZnTransfoSetIdentity(&t);
- ZnTranslate(&t, -grad->p.x, -grad->p.y, False);
- ZnRotateRad(&t, -angle);
- ZnScale(&t, 1/len, 1/len);
- pbbox[0].x = -50;
- pbbox[0].y = 50;
- pbbox[1].x = 50;
- pbbox[1].y = 50;
- pbbox[2].x = 50;
- pbbox[2].y = -50;
- pbbox[3].x = -50;
- pbbox[3].y = -50;
- ZnTransformPoints(&t, pbbox, pgrad, 4);
- maxx = minx = pgrad[0].x;
- for (i = 1; i < 4; i++) {
- if (pgrad[i].x > maxx) {
- maxx = pgrad[i].x;
- }
- if (pgrad[i].x < minx) {
- minx = pgrad[i].x;
- }
- }
-
- span = maxx-minx;
- if (grad->type == ZN_RADIAL_GRADIENT) {
- start_in_new = 0;
- end_in_new = 100/span;
- }
- else {
- start_in_new = -minx*100/span;
- end_in_new = (1-minx)*100/span;
- }
-
- //printf("minx: %g, maxx: %g, start%%: %g, end%%: %g\n",
- // minx, maxx, start_in_new, end_in_new);
-
- /*
- * Gradient is unchanged
- */
- if ((ABS(start_in_new) < PRECISION_LIMIT) &&
- (ABS(end_in_new-100.0) < PRECISION_LIMIT)) {
- goto unchanged;
- }
- //printf("start_in_new: %g, end_in_new: %g\n", start_in_new, end_in_new);
- if ((start_in_new > 100.0) || (end_in_new < 0.0)) {
- grad->num_actual_colors = 1;
- grad->actual_colors = ZnMalloc(sizeof(ZnGradientColor));
- grad->actual_colors[0].position = 0;
- grad->actual_colors[0].mid_rgb = NULL;
- if (end_in_new < 0.0) {
- grad->actual_colors[0].alpha = grad->colors_in[grad->num_colors_in-1].alpha;
- grad->actual_colors[0].rgb = Tk_GetColorByValue(tkwin, grad->colors_in[grad->num_colors_in-1].rgb);
- }
- else {
- grad->actual_colors[0].alpha = grad->colors_in[0].alpha;
- grad->actual_colors[0].rgb = Tk_GetColorByValue(tkwin, grad->colors_in[0].rgb);
- }
- return;
- }
-
- grad->num_actual_colors = grad->num_colors_in;
- interpolate_first = False;
- minx100 = (int) (minx*100);
- maxx100 = (int) (maxx*100);
- span100 = (int) (span*100);
-
- if (start_in_new < 0.0) {
- /*
- * The gradient starts outside the bbox,
- * Find the color at the bbox edge. First
- * find the correct gradient segment and then
- * interpolate to get the color.
- */
- first_color = 1;
- while ((first_color < (int) grad->num_colors_in) &&
- (grad->colors_in[first_color].position < minx100)) {
- first_color++;
- grad->num_actual_colors--;
- }
- if (grad->colors_in[first_color].position == minx100) {
- grad->num_actual_colors--;
- }
- else {
- interpolate_first = True;
- /*printf("interpolate first color\n");*/
- }
- }
- else {
- first_color = 0;
- if (grad->type != ZN_RADIAL_GRADIENT) {
- grad->num_actual_colors++;
- }
- }
- interpolate_last = False;
- if (end_in_new > 100.0) {
- /*
- * The gradient ends outside the bbox,
- * Find the color at the bbox edge. First
- * find the correct gradient segment and then
- * interpolate to get the color.
- */
- last_color = grad->num_colors_in-2;
- while ((last_color >= 0) &&
- (grad->colors_in[last_color].position > maxx100)) {
- last_color--;
- grad->num_actual_colors--;
- }
- if (grad->colors_in[last_color].position == maxx100) {
- grad->num_actual_colors--;
- }
- else {
- interpolate_last = True;
- /*printf("interpolate last color\n");*/
- }
- }
- else {
- last_color = grad->num_colors_in-1;
- grad->num_actual_colors++;
- }
-
- grad->actual_colors = ZnMalloc(grad->num_actual_colors*sizeof(ZnGradientColor));
- j = 0;
- if (interpolate_first) {
- //printf("Interpolate first color, index: %d\n", first_color);
- InterpolateGradientColor(tkwin,
- &grad->colors_in[first_color-1],
- &grad->colors_in[first_color],
- &grad->actual_colors[j],
- NULL,
- minx100, minx100, span100);
- j++;
- }
- else if ((first_color == 0) && (grad->type != ZN_RADIAL_GRADIENT)) {
- grad->actual_colors[j] = grad->colors_in[0];
- grad->actual_colors[j].rgb = Tk_GetColorByValue(tkwin, grad->colors_in[0].rgb);
- if (grad->colors_in[0].mid_rgb) {
- grad->actual_colors[j].mid_rgb = Tk_GetColorByValue(tkwin, grad->colors_in[0].mid_rgb);
- }
- grad->actual_colors[0].position = 0;
- grad->actual_colors[0].control = 50;
- j++;
- /*printf("adding a color at start\n");*/
- }
-
- /*printf("first color: %d, last color: %d, num colors: %d\n",
- first_color, last_color, grad->num_actual_colors);*/
- for (i = first_color; i <= last_color; i++, j++) {
- grad->actual_colors[j] = grad->colors_in[i];
- grad->actual_colors[j].rgb = Tk_GetColorByValue(tkwin, grad->colors_in[i].rgb);
- if (grad->colors_in[i].mid_rgb) {
- grad->actual_colors[j].mid_rgb = Tk_GetColorByValue(tkwin, grad->colors_in[i].mid_rgb);
- }
- grad->actual_colors[j].position = (grad->colors_in[i].position-minx100)*100/span100;
- grad->actual_colors[j].control = grad->colors_in[i].control;
- /*printf("i: %d, j: %d, minx: %d, span: %d, position av: %d position ap: %d\n",
- i, j, minx100, span100, grad->colors_in[i].position, grad->actual_colors[j].position);*/
- }
-
- if (interpolate_last) {
- //printf("Interpolate last color\n");
- InterpolateGradientColor(tkwin,
- &grad->colors_in[last_color],
- &grad->colors_in[last_color+1],
- &grad->actual_colors[j],
- &grad->actual_colors[j-1],
- maxx100, minx100, span100);
- }
- else if (last_color == ((int) grad->num_colors_in)-1) {
- i = grad->num_colors_in-1;
- grad->actual_colors[j] = grad->colors_in[i];
- grad->actual_colors[j].rgb = Tk_GetColorByValue(tkwin, grad->colors_in[i].rgb);
- if (grad->colors_in[i].mid_rgb) {
- grad->actual_colors[j].mid_rgb = Tk_GetColorByValue(tkwin, grad->colors_in[i].mid_rgb);
- }
- /*printf("adding a color at end\n");*/
- }
- grad->actual_colors[j].position = 100;
- //for (i=0; i<grad->num_actual_colors; i++) printf("control %d: %d\n", i, grad->actual_colors[i].control);
- //printf("Out of ReduceGradient\n");
-}
-
-
-/*
- *--------------------------------------------------------------
- *
- * ZnGetGradient --
- *
- * Create a data structure containing a range of colors
- * used to display a gradient.
- *
- * The gradient should have the following syntax:
- *
- * gradient := [graddesc|]color[|....|color]
- * where the | are real characters not meta-syntax.
- *
- * graddesc := =type args
- * where type := axial | radial | path
- *
- * If type = axial
- * args := angle (0..360) | xs ys xe ye (reals)
- *
- * The first form define the axial gradiant by its slope.
- * With this syntax the gradient fits the whole shape.
- * This is a backward compatible syntax.
- * The second form specifies a vector which will be used
- * to draw the gradient. The vector defines both the angle
- * and the gradient area. Parts of the shape that lie before
- * the vector origin are filled with the first color and
- * parts that lie after the vector end are filled with the
- * last color.
- *
- * If type = radial or path
- * args := xs ys [xe ye] (reals)
- *
- * The vector specified by the 4 coordinates defines the
- * gradient area. Parts of the shape that lie before
- * the vector origin are filled with the first color and
- * parts that lie after the vector end are filled with the
- * last color. The vector end may be omitted, in such case
- * the gradient fits exactly the whole shape to be filled,
- * this is backward compatible with older gradients.
- *
- * color := colorvalue | colorvalue position |
- * colorvalue control position
- * where position and control are in (0..100)
- *
- * colorvalue := (colorname | #rgb | cievalue)[;alpha]
- * where alpha is in (0..100)
- *
- * Results:
- * The return value is a token for a data structure
- * describing a gradient. This token may be passed
- * to the drawing routines.
- * If an error prevented the gradient from being created
- * then NULL is returned and an error message will be
- * left in interp.
- *
- * Side effects:
- * Data structures, etc. are allocated.
- * It is the caller's responsibility to eventually call
- * ZnFreeGradient to release the resources.
- *
- *--------------------------------------------------------------
- */
-ZnGradient *
-ZnGetGradientByValue(ZnGradient *grad)
-{
- grad->ref_count++;
- return grad;
-}
-
-
-static int
-ParseRealList(const char *str,
- const char *stop,
- ZnReal *list,
- int max)
-{
- int num;
- char *end;
-
- num = 0;
- while ((num < max) && (str != stop)) {
- list[num] = strtod(str, &end);
- if (end == str) {
- /* A syntax error occured, return a 0 count
- * as a hint for the caller.
- */
- return 0;
- }
- num++;
- str = end+strspn(end, " \t");
- }
- return num;
-}
-
-ZnGradient *
-ZnGetGradient(Tcl_Interp *interp,
- Tk_Window tkwin,
- Tk_Uid desc)
-{
- #define SEGMENT_SIZE 64
- Tcl_HashEntry *hash;
- ZnGradient *grad;
- unsigned int i, j, nspace, num_colors;
- unsigned int size, num_coords=0;
- char type;
- char const *scan_ptr, *next_ptr, *str_ptr;
- ZnReal angle, position, control;
- ZnReal coords[4];
- char *color_ptr, *end, segment[SEGMENT_SIZE];
- ZnGradientColor *first, *last;
- XColor color;
- int new, red_range, green_range, blue_range;
- ZnBool simple;
-
- //printf("ZnGetGradient : %s\n", desc);
- if (!desc || !*desc) {
- return NULL;
- }
- if (!initialized) {
- ColorInit();
- }
-
- /*
- * First, check to see if there's already a gradient that will work
- * for this request.
- */
- desc = Tk_GetUid(desc);
-
- /*printf("get gradient: %s\n", desc);*/
- hash = Tcl_CreateHashEntry(&gradient_table, desc, &new);
- if (!new) {
- grad = (ZnGradient *) Tcl_GetHashValue(hash);
- grad->ref_count++;
- return grad;
- }
-
- /*
- * No satisfactory gradient exists yet. Initialize a new one.
- */
- type = ZN_AXIAL_GRADIENT;
- angle = 0.0;
- /*
- * Skip the trailing spaces.
- */
- while (*desc == ' ') {
- desc++;
- }
- /*
- * Count the sections in the description. It should give
- * the number of colors plus may be the gradient description.
- */
- scan_ptr = desc;
- /*
- * If the first section is the gradient description, start color
- * counts up from zero.
- */
- num_colors = (*scan_ptr == '=') ? 0 : 1;
- while ((scan_ptr = strchr(scan_ptr, '|'))) {
- num_colors++;
- scan_ptr++;
- }
- if (num_colors == 0) {
- Tcl_AppendResult(interp, "gradient should have at least one color \"",
- desc, "\",", NULL);
- grad_err1:
- Tcl_DeleteHashEntry(hash);
- /*printf("ZnGetGradient error : %s\n", desc);*/
- return NULL;
- }
- /*
- * Then look at the gradient type.
- */
- scan_ptr = desc;
- /*
- * next_ptr can't be NULL in the following code,
- * we checked that at least one color was specified
- * after the gradient description.
- */
- next_ptr = strchr(scan_ptr, '|');
- if (*scan_ptr == '=') {
- scan_ptr++;
- if ((*scan_ptr == 'a') && (strncmp(scan_ptr, "axial", 5) == 0)) {
- scan_ptr += 5;
- num_coords = ParseRealList(scan_ptr, next_ptr, coords, 4);
- if ((num_coords != 1) && (num_coords != 4)) {
- grad_err3:
- Tcl_AppendResult(interp, "invalid gradient parameter \"",
- desc, "\",", NULL);
- goto grad_err1;
- }
- angle = (int) coords[0];
- }
- else if ((*scan_ptr == 'c') && (strncmp(scan_ptr, "conical", 7) == 0)) {
- scan_ptr += 7;
- type = ZN_CONICAL_GRADIENT;
- num_coords = ParseRealList(scan_ptr, next_ptr, coords, 4);
- if ((num_coords < 1) && (num_coords > 4)) {
- goto grad_err3;
- }
- angle = (int) coords[0];
- }
- else if (((*scan_ptr == 'r') && (strncmp(scan_ptr, "radial", 6) == 0)) ||
- ((*scan_ptr == 'p') && (strncmp(scan_ptr, "path", 4) == 0))) {
- if (*scan_ptr == 'r') {
- type = ZN_RADIAL_GRADIENT;
- scan_ptr += 6;
- }
- else {
- type = ZN_PATH_GRADIENT;
- scan_ptr += 4;
- }
- num_coords = ParseRealList(scan_ptr, next_ptr, coords, 4);
- if ((num_coords != 2) && (num_coords != 4)) {
- goto grad_err3;
- }
- }
- else {
- Tcl_AppendResult(interp, "invalid gradient type \"",
- desc, "\"", NULL);
- goto grad_err1;
- }
- scan_ptr = next_ptr + 1;
- next_ptr = strchr(scan_ptr, '|');
- }
-
- /*
- * Create the gradient structure.
- */
- grad = (ZnGradient *) ZnMalloc(sizeof(ZnGradient) +
- sizeof(ZnGradientColor)*(num_colors-1));
- grad->ref_count = 1;
- simple = True;
- grad->num_colors_in = num_colors;
- grad->type = type;
- grad->p.x = grad->p.y = grad->e.x = grad->e.y = 0.0;
- grad->angle = 0;
-
- switch (type) {
- case ZN_AXIAL_GRADIENT:
- if ((num_coords == 4) &&
- ((coords[0] != coords[2]) || (coords[1] != coords[3]))) {
- grad->p.x = coords[0];
- grad->p.y = coords[1];
- simple = False;
- grad->e.x = coords[2];
- grad->e.y = coords[3];
- }
- else {
- grad->angle = (int) angle;
- }
- break;
- case ZN_CONICAL_GRADIENT:
- if ((num_coords == 4) &&
- ((coords[0] != coords[2]) || (coords[1] != coords[3]))) {
- grad->p.x = coords[0];
- grad->p.y = coords[1];
- simple = False;
- grad->e.x = coords[2];
- grad->e.y = coords[3];
- }
- else if (num_coords == 2) {
- grad->p.x = coords[0];
- grad->p.y = coords[1];
- }
- else if (num_coords == 3) {
- grad->p.x = coords[0];
- grad->p.y = coords[1];
- grad->angle = (int) coords[2];
- }
- else {
- grad->angle = (int) angle;
- }
- break;
- case ZN_RADIAL_GRADIENT:
- grad->p.x = coords[0];
- grad->p.y = coords[1];
- if ((num_coords == 4) &&
- ((coords[0] != coords[2]) || (coords[1] != coords[3]))) {
- simple = False;
- grad->e.x = coords[2];
- grad->e.y = coords[3];
- }
- break;
- case ZN_PATH_GRADIENT:
- grad->p.x = coords[0];
- grad->p.y = coords[1];
- break;
- }
- grad->hash = hash;
- Tcl_SetHashValue(hash, grad);
-
- for (i = 0; i < num_colors; i++) {
- grad->colors_in[i].alpha = 100;
- /*
- * Try to parse the color name.
- */
- nspace = strspn(scan_ptr, " \t");
- scan_ptr += nspace;
- str_ptr = strpbrk(scan_ptr, " \t|");
- if (str_ptr) {
- size = str_ptr - scan_ptr;
- }
- else {
- size = strlen(scan_ptr);
- }
- if (size > (SEGMENT_SIZE-1)) {
- Tcl_AppendResult(interp, "color name too long in gradient \"",
- desc, "\",", NULL);
- grad_err2:
- for (j = 0; j < i; j++) {
- Tk_FreeColor(grad->colors_in[j].rgb);
- }
- ZnFree(grad);
- goto grad_err1;
- }
- strncpy(segment, scan_ptr, size);
- segment[size] = 0;
- scan_ptr += size;
- /*
- * Try to parse the color position.
- */
- grad->colors_in[i].position = 0;
- grad->colors_in[i].control = 50;
- position = strtod(scan_ptr, &end);
- if (end != scan_ptr) {
- grad->colors_in[i].position = (int) position;
- scan_ptr = end;
- /*
- * Try to parse the control point
- */
- control = strtod(scan_ptr, &end);
- if (end != scan_ptr) {
- grad->colors_in[i].control = (int) control;
- scan_ptr = end;
- }
- }
- nspace = strspn(scan_ptr, " \t");
- if ((scan_ptr[nspace] != 0) && (scan_ptr+nspace != next_ptr)) {
- Tcl_AppendResult(interp, "incorrect color description in gradient \"",
- desc, "\",", NULL);
- goto grad_err2;
- }
-
- color_ptr = strchr(segment, ';');
- if (color_ptr) {
- *color_ptr = 0;
- }
- grad->colors_in[i].rgb = Tk_GetColor(interp, tkwin, Tk_GetUid(segment));
- if (grad->colors_in[i].rgb == NULL) {
- Tcl_AppendResult(interp, "incorrect color value in gradient \"",
- desc, "\",", NULL);
- goto grad_err2;
- }
- if (color_ptr) {
- color_ptr++;
- grad->colors_in[i].alpha = atoi(color_ptr);
- }
- if (i == 0) {
- grad->colors_in[i].position = 0;
- }
- else if (i == num_colors - 1) {
- grad->colors_in[i].position = 100;
- }
- if ((i > 0) &&
- ((grad->colors_in[i].position > 100) ||
- (grad->colors_in[i].position < grad->colors_in[i-1].position))) {
- Tcl_AppendResult(interp, "incorrect color position in gradient \"",
- desc, "\",", NULL);
- goto grad_err2;
- }
- if (grad->colors_in[i].control > 100) {
- grad->colors_in[i].control = 100;
- }
- if (grad->colors_in[i].alpha > 100) {
- grad->colors_in[i].alpha = 100;
- }
- if (next_ptr) {
- scan_ptr = next_ptr + 1;
- next_ptr = strchr(scan_ptr, '|');
- }
- }
-
- /*
- * Compute the mid alpha and mid color values. These will be
- * used by the gradient rendering primitives when a control
- * is not at mid range. The last color has no mid_* values.
- */
- for (i = 0; i < grad->num_colors_in-1; i++) {
- first = &grad->colors_in[i];
- last = &grad->colors_in[i+1];
- red_range = (int) last->rgb->red - (int) first->rgb->red;
- green_range = (int) last->rgb->green - (int) first->rgb->green;
- blue_range = (int) last->rgb->blue - (int) first->rgb->blue;
- color.red =(int) first->rgb->red + red_range/2;
- color.green = (int) first->rgb->green + green_range/2;
- color.blue = (int) first->rgb->blue + blue_range/2;
- first->mid_rgb = Tk_GetColorByValue(tkwin, &color);
- first->mid_alpha = first->alpha + (last->alpha-first->alpha)/2;
- }
- grad->colors_in[grad->num_colors_in-1].mid_rgb = NULL;
-
- /*
- * If the gradient is 'simple' ie. described by a single point
- * or an angle for axial gradients, the processing is finished.
- * If not, we have to reduce the gradient to a simple one by adding
- * or suppressing colors and adjusting the relative position of
- * each remaining color.
- */
- if (simple) {
- grad->num_actual_colors = grad->num_colors_in;
- grad->actual_colors = grad->colors_in;
- }
- else if (type != ZN_PATH_GRADIENT) {
- ReduceGradient(tkwin, grad);
- }
-
- //printf("num in: %d, num actual: %d\n", grad->num_colors_in,grad->num_actual_colors);
- //printf("ZnGetGradient end : %s\n", desc);
- return grad;
-}
-
-
-/*
- *--------------------------------------------------------------
- *
- * ZnNameOfGradient --
- *
- * Given a gradient, return a textual string identifying
- * the gradient.
- *
- * Results:
- * The return value is the string that was used to create
- * the gradient.
- *
- * Side effects:
- * None.
- *
- *--------------------------------------------------------------
- */
-char *
-ZnNameOfGradient(ZnGradient *grad)
-{
- return (char *) grad->hash->key.words;
-}
-
-
-/*
- *--------------------------------------------------------------
- *
- * ZnFreeGradient --
- *
- * This procedure is called when a gradient is no longer
- * needed. It frees the resources associated with the
- * gradient. After this call, the caller should never
- * again use the gradient.
- *
- * Results:
- * None.
- *
- * Side effects:
- * Resources are freed.
- *
- *--------------------------------------------------------------
- */
-void
-ZnFreeGradient(ZnGradient *grad)
-{
- unsigned int i;
-
- grad->ref_count--;
- if (grad->ref_count == 0) {
- Tcl_DeleteHashEntry(grad->hash);
- for (i = 0; i < grad->num_colors_in; i++) {
- Tk_FreeColor(grad->colors_in[i].rgb);
- if (grad->colors_in[i].mid_rgb) {
- Tk_FreeColor(grad->colors_in[i].mid_rgb);
- }
- }
- if (grad->actual_colors != grad->colors_in) {
- for (i = 0; i < grad->num_actual_colors; i++) {
- Tk_FreeColor(grad->actual_colors[i].rgb);
- if (grad->actual_colors[i].mid_rgb) {
- Tk_FreeColor(grad->actual_colors[i].mid_rgb);
- }
- }
- ZnFree(grad->actual_colors);
- }
- ZnFree(grad);
- }
-}
-
-
-/*
- *--------------------------------------------------------------
- *
- * ZnComposeAlpha --
- *
- * This procedure takes two alpha values in percent and
- * returns the composite value between 0 and 65535.
- *
- *--------------------------------------------------------------
- */
-int
-ZnComposeAlpha(unsigned short alpha1,
- unsigned short alpha2)
-{
- return (alpha1*alpha2/100)*65535/100;
-}