/* $Id: Color.c,v 1.2 1997/06/10 15:29:11 archer Exp $
 *	COLOR.C - Managing interface colors
 */
#include <ctype.h>
#include <Widget/WidgetsP.h>
#include <Widget/colorsP.h>
#include <Widget/Perror.h>


/**
 ** Private types: These are used only by color allocator
 **/
typedef struct color_s {
	struct color_s	*next;
	XColor		value;
	char		name[2];	/* variable lenght! */
} color_t;


/**
 ** Private variables
 **/
static color_t	*lookup;


/**
 ** Internal: HEXA
 **	Quick'n dirty hexa to unsigned conversion
 **/
static unsigned int hexa(char *h, int d, int pad)
{
unsigned int	v;
char		c;
/*
 * Loop on D characters
 */
	v = 0;
	while (d-- > 0) {
		c = *h++;
/*
 * Complete by replicating trailing digit
 */
		if (d == 0 && pad) {
			h--;
			pad--;
			d++;
		}
/*
 * New digit
 */
		v <<= 4;
		if (isdigit(c)) {
			v += c - '0';
			continue;
		}
		v += 9;
		v += c & 7;
	}
/*
 * Final result
 */
	return v;
}


/**
 ** Internal: GRAYED
 **	Allocate the appropriate B&W in monochrome environment
 **/
static void grayed(color_t *into)
{
long	g;
/*
 * Light intensity
 */
	g  = into->value.red;
	g += into->value.green;
	g += into->value.blue;
/*
 * Above threshold?
 */
	if (g >= 0x18000)
		into->value.pixel = x11__white_pixel;
	else
		into->value.pixel = x11__black_pixel;
}


/**
 ** Internal: COLOR_RGB_NAME
 **	Find a color from rgb naming
 */
static X11_color color_rgb_name(Colormap cmap, char *spec, color_t *into)
{
color_t	*l;
int	d;
/*
 * Four possible formats of #xxx specification
 */
	d = strlen(spec) / 3;
	into->value.red   = hexa(spec    , d, 4-d);
	into->value.green = hexa(spec+d  , d, 4-d);
	into->value.blue  = hexa(spec+d+d, d, 4-d);
/*
 * Lookup an existing value?
 */
	for (l = into->next; l; l = l->next)
		if (into->value.red   == l->value.red &&
		    into->value.green == l->value.green &&
		    into->value.blue  == l->value.blue) {
			into->value.pixel = l->value.pixel;
			return l->value.pixel;
		}
/*
 * Monochrome?
 */
	if (x11__is_monochrome)
		grayed(into);
	else {
/*
 * Allocate color
 */
		XAllocColor(x11__screen, cmap, &into->value);
/*** HACK ***/
	}
	return into->value.pixel;
}


/**
 ** X11_COLOR_BY_NAME
 **/
X11_color X11_ColorByName(char *name, X11_color def)
{
Colormap	cmap;
color_t		*c;
XColor		trash;

	if (!name)
		return def;
/*
 * Color is already known?
 */
	for (c = lookup; c; c = c->next)
		if (strcasecmp(c->name, name) == 0)
			return c->value.pixel;
/*
 * New specification
 */
	c = (color_t *)malloc(sizeof(*c)+strlen(name));
	if (!c)
		X11_Perror("Allocating color name");
	strcpy(c->name, name);
	c->next = lookup;
	lookup  = c;
	c->value.pixel = def;
/*
 * RGB specification?
 */
	cmap = DefaultColormap(x11__screen, DefaultScreen(x11__screen));
	if (*name == '#')
		return color_rgb_name(cmap, name+1, c);
/*
 * Allocate a new color
 */
	if (!XAllocNamedColor(x11__screen, cmap, name, &c->value, &trash))
		return def;
/*
 * Lookup on list
 */
	if (x11__is_monochrome)
		grayed(c);
	return c->value.pixel;
}


/**
 ** X11_COLOR_RESOURCE
 **	Color found by ressource name
 **/
X11_color x11__color_resource(char *name, X11_color fallback)
{
	return X11_ColorByName(x11__resource_value(name), fallback);
}


/**
 ** X11_COLOR_INIT
 **	Initialize by loading the colors
 **/
void x11__color_init(void)
{
char		*s;
X11_color	pix_b, pix_a;
/*
 * Monochrome defaults
 */
	x11__widget_root->border_color =
	x11__widget_root->focus_color  =
	x11__widget_root->active_bk    =
	x11__widget_root->br_color     =
	x11__widget_root->foreground   = x11__black_pixel;
	x11__widget_root->active_fg    =
	x11__widget_root->tl_color     =
	x11__widget_root->background   = x11__white_pixel;
/*
 * Values
 */
	s = x11__resource_value("Monochrome");
	if (s && strncasecmp(s, "on", 2) == 0)
		x11__is_monochrome = True;
/*
 * Default for colors
 */
	if (!x11__is_monochrome) {
		pix_b = X11_ColorByName("#aaaaaa", 0xffffffff);
		pix_a = X11_ColorByName("#999999", 0xffffffff);
		if (pix_a == 0xffffffff ||
		    pix_b == 0xffffffff)
			x11__is_monochrome = True;
	}
/*
 * Apply colors if all found and no monochrome
 */
	if (!x11__is_monochrome) {
		x11__widget_root->background = pix_b;
		x11__widget_root->active_bk  = pix_a;
		x11__widget_root->active_fg  = x11__black_pixel;
	}
}
