/* @(#)colors.c	17.1 (ESO-IPG) 01/25/02 17:26:32 */
/*---------------------------------------------------------------------
 * $Date: 2003-06-04 14:49:18 $             $Revision: 1.1.1.1 $
 *---------------------------------------------------------------------
 * 
 *
 *             Copyright (c) 1988, Visual Edge Software Ltd.
 *
 * ALL  RIGHTS  RESERVED.  Permission  to  use,  copy,  modify,  and
 * distribute  this  software  and its documentation for any purpose
 * and  without  fee  is  hereby  granted,  provided  that the above
 * copyright  notice  appear  in  all  copies  and  that  both  that
 * copyright  notice and this permission notice appear in supporting
 * documentation,  and that  the name of Visual Edge Software not be
 * used  in advertising  or publicity  pertaining to distribution of
 * the software without specific, written prior permission. The year
 * included in the notice is the year of the creation of the work.
 *-------------------------------------------------------------------*/

#include <stdio.h>
#include <string.h>
#include <ctype.h>
#ifdef USE_STDLIB
#include <stdlib.h>
#endif

#include <X11/IntrinsicP.h>
#include <X11/StringDefs.h>
#include <X11/Xos.h>
#include <X11/Xutil.h>

#include "global.h"
#include "dstring.h"
#include "valloc.h"
#include "uimx_cat.h"
#include "misc1_ds.h"

#define HASHSIZE 256

typedef struct _ctbl
{	XColor		color;
	dstring		name;
	struct _ctbl	*nextc, *nextp;
} colortbl;

/* CG */
char    *UxStripLeadingAndTrailingSpaces(char *str);

static void 	string_to_xcolor UXPROTO((XrmValuePtr, Cardinal *, XrmValuePtr,
					  XrmValuePtr));

/* Xt provides a XtRString to XtRPixel converter */
#ifdef NOT_NEEDED
static void 	string_to_pixel  UXPROTO((XrmValuePtr, Cardinal *, XrmValuePtr,
					  XrmValuePtr));
#endif

static void	add_color  UXPROTO((char*, XColor*));

#ifdef MOTIF_WIDGETS

/* bugfix 739; CVEje00856, 857 & 880; XtConvertArgRec for colormap is    */
/* different in Motif 	 */
/* bugfix 1103: In X11R4, addressing is XtWidgetBaseOffset    */

static XtConvertArgRec cvtarg[]=
{{ XtWidgetBaseOffset, (caddr_t) XtOffset(Widget, core.colormap), sizeof(Colormap)}};

#else

static XtConvertArgRec cvtarg[]=
{{ XtBaseOffset, (caddr_t) XtOffset(Widget, core.colormap), sizeof(Colormap)}};

#endif /* MOTIF_WIDGETS */

static colortbl	*chash[HASHSIZE];
static colortbl *phash[HASHSIZE];
static int	depth, cells;


/* X/OPEN message catalog macros. These will make the code more compact. */
#define CGETS(ms,ds_ms)                 UxCatGets(MC_MISC1,ms,ds_ms)

/******************************************************************************
 ==== LOCAL ==================================================================
*******************************************************************************
NAME:		int		hash_name(name)

INPUT:		char		*name		- name to hash

RETURN:		hash value

DESCRIPTION:	return the hash value for a color name

CREATION:	Jun 21/1989
REVISIONS:	--
-----------------------------------------------------------------------------*/

static int hash_name(name)
	char		*name;
{
	int		UxHash= 0;

	if(name == NULL)
		return(0);

	while(*name)
		UxHash+= *(name++);

	return(UxHash%HASHSIZE);
}

/******************************************************************************
 ==== LOCAL ==================================================================
*******************************************************************************
NAME:		colortbl	*lookup_by_pixel(pixel)

INPUT:		int		pixel		- pixel to find

RETURN:		color entry

DESCRIPTION:	lookup a color entry using its pixel value as the key

CREATION:	Jun 21/1989
REVISIONS:	--
-----------------------------------------------------------------------------*/

static colortbl *lookup_by_pixel(pixel)
	int		pixel;
{
	colortbl	*pntr;

	for(pntr= phash[pixel%HASHSIZE]; pntr != NULL; pntr= pntr->nextp)
		if(pntr->color.pixel == pixel)
			return(pntr);

	return(NULL);
}
	
/******************************************************************************
 ==== LOCAL ==================================================================
*******************************************************************************
NAME:		colortbl	*lookup_by_name(name)

INPUT:		char		*name		- color name

RETURN:		color entry

DESCRIPTION:	lookup a color entry using its name as the key

CREATION:	Jun 21/1989
REVISIONS:	--
-----------------------------------------------------------------------------*/

static colortbl *lookup_by_name(name)
	char		*name;
{
	colortbl	*pntr;
	int		UxHash;

	UxHash= hash_name(name);

	for(pntr= chash[UxHash]; pntr != NULL; pntr= pntr->nextc)
		if(!strcmp(dnstr(pntr->name), name))
			return(pntr);

	return(NULL);
}
	
/******************************************************************************
 ==== GLOBAL =================================================================
*******************************************************************************
NAME:		void		UxInit_colors()

DESCRIPTION:	Initialize the colors database and register its resource
		converters with the toolkit

CREATION:	Jun 21/1989
REVISIONS:	15 August 1990	John Albert	OLE MERGE
		-- removed ifdef MOTIF_WIDGETS to update
		   to R3 for OL_WIDGETS.
-----------------------------------------------------------------------------*/

void UxInit_colors()
{
	static int	init= 0;
	XColor		c;

	if(init)
		return;

	init= 1;

	depth= XDefaultDepth(UxDisplay, UxScreen);
	cells= DisplayCells(UxDisplay, UxScreen);

	if(depth == 1)
		cells= 2;

						/* add default colors */
	c.red= c.green= c.blue= 0;
	c.pixel= BlackPixel(UxDisplay, UxScreen);
	add_color("xtdefaultforeground", &c);
	add_color("black", &c);

	c.red= c.green= c.blue= 65535;
	c.pixel= WhitePixel(UxDisplay, UxScreen);
	add_color("xtdefaultbackground", &c);
	add_color("white", &c);

	XtAppAddConverter(UxAppContext, XtRString, XtRColor,
				(XtConverter)string_to_xcolor, cvtarg, 1);
/* Xt provides a XtRString to XtRPixel converter */
#ifdef NOT_NEEDED
	XtAppAddConverter(UxAppContext, XtRString, XtRPixel,
				(XtConverter)string_to_pixel, cvtarg, 1);
#endif
}

/******************************************************************************
 ==== GLOBAL =================================================================
*******************************************************************************
NAME:		char		*UxPixel_to_name(pixel)

INPUT:		Pixel		pixel		- pixel to convert

RETURN:		name associated with pixel

DESCRIPTION:	return the name of the color that corresponds to 'pixel'.
		The return is in a static buffer, therefore the next time
		this routine is called the previous value will be erased.

CREATION:	Jun 21/1989
REVISIONS:	04 1990
		-- if lookup_by_pixel() fails, do not give up.
		   Query the RGB values for that pixel value and construct a
		   color of the form #rrggbb, if possible, or #rrrrggggbbbb
-----------------------------------------------------------------------------*/

char *UxPixel_to_name(pixel)
	Pixel		pixel;
{
	colortbl	*val;
	static char	msg[64];
	XColor cdef;

	val= lookup_by_pixel(pixel);

	if(val != NULL)
		return(dnstr(val->name));

	cdef.pixel = pixel;
	XQueryColor(XtDisplay(UxTopLevel), UxTopLevel->core.colormap, &cdef);

	/* Can we do a color of the form "#rrggbb"?  This tends to be
	 * the best resolution of most displays.
	 */
	if (((cdef.red   & 0xff) == (cdef.red   >> 8)) &&
	    ((cdef.blue  & 0xff) == (cdef.blue  >> 8)) &&
	    ((cdef.green & 0xff) == (cdef.green >> 8))) {

	    /* can do "#rrggbb" */
	    sprintf(msg, "#%02x%02x%02x", cdef.red & 0xff, cdef.green & 0xff,
		    cdef.blue & 0xff);
	} else {
	    /* must do "#rrrrggggbbbb" */
	    sprintf(msg, "#%04x%04x%04x", cdef.red, cdef.green, cdef.blue);
	}

	return(msg);
}

/******************************************************************************
 ==== GLOBAL =================================================================
*******************************************************************************
NAME:		Pixel		UxName_to_pixel(name)

INPUT:		char		*name		- color name

RETURN:		pixel

DESCRIPTION:	return the pixel that is associated with 'name'

CREATION:	Jun 21/1989
REVISIONS:	--
-----------------------------------------------------------------------------*/

Pixel UxName_to_pixel(name)
	char		*name;
{
	colortbl	*val;

	val= lookup_by_name(name);

	if(val == NULL)
		return(BlackPixel(UxDisplay, UxScreen));

	return(val->color.pixel);
}

/******************************************************************************
 ==== LOCAL ==================================================================
*******************************************************************************
NAME:		void		add_color(cname, c)

INPUT:		char		*cname		- color name
		XColor		*c		- color value

DESCRIPTION:	add 'cname' to the color database so that it can be looked up
		by either name or pixel value.

CREATION:	Jun 21/1989
REVISIONS:	--
-----------------------------------------------------------------------------*/

static void add_color(cname, c)
	char		*cname;
	XColor		*c;
{
	int		hashv, phashv;
	colortbl	*tbl;

	tbl= lookup_by_name(cname);

	if(tbl == NULL)
	{	tbl= (colortbl *) UxMalloc(sizeof(colortbl));

		hashv= hash_name(cname);
		phashv= c->pixel%HASHSIZE;

		tbl->color= *c;
		tbl->name= dcreate(cname);
		tbl->nextc= chash[hashv];
		tbl->nextp= phash[phashv];

		chash[hashv]= tbl;
		phash[phashv]= tbl;
	}
	else
		tbl->color= *c;
}

static	void	LowerCase( src, dest)
char	*src;
char	*dest;
{
	while ( *src)
	{
		if ( isupper( *src))
			*dest = tolower( *src);
		else
			*dest = *src;
		src++;
		dest++;
	}
	*dest = '\0';
}
/******************************************************************************
 ==== LOCAL ==================================================================
*******************************************************************************
NAME:		void		string_to_xcolor(args, num_args, from, to)

INPUT:		XrmValuePtr	args		- converter args
		Cardinal	*num_args	- number of args
		XrmValuePtr	from		- convert from...
		XrmValuePtr	to		- convert to...

DESCRIPTION:	This is the resource converter called by the toolkit to
		convert a string name to a color structure. It is registered
		with the toolkit by UxInit_colors.  If the color is not
		yet allocated, this routine tries to allocate it.

CREATION:	Jun 21/1989
REVISIONS:	July 24/90	(see bug798)
		-- skipped leading white spaces, and removed trailing white
		   spaces. (see bug798)
-----------------------------------------------------------------------------*/
static void string_to_xcolor(args, num_args, from, to)
	XrmValuePtr	args;
	Cardinal	*num_args;
	XrmValuePtr	from;
	XrmValuePtr	to;
{
	static XColor   c;
	Colormap	cmap;
	int		rtrn;
	colortbl	*tbl;
	char		name_buf[128];
	char		*ptr;

	if(*num_args != 1)
		XtAppError(UxAppContext,
			CGETS( MS_MISC_NO_COLORMAP, DS_MS_MISC_NO_COLORMAP));

	cmap= *((Colormap *) args[0].addr);

	/* skip leading and strip trailing whitespace */
	ptr=UxStripLeadingAndTrailingSpaces(from->addr);
	
	LowerCase(ptr, name_buf);

	tbl= lookup_by_name(name_buf);

	if(tbl != NULL)
	{	c= tbl->color;
		to->addr= (caddr_t)&c;
		to->size= sizeof(XColor);

		return;
	}

	rtrn= XParseColor(UxDisplay, cmap, (char *)name_buf, &c);

	if(rtrn == 0)
	{	UxStandardError(CGETS( MS_MISC_NO_COLORNAME,
                                DS_MS_MISC_NO_COLORNAME), name_buf);
		to->addr= NULL;
		to->size= 0;

		return;
	}

	rtrn= XAllocColor(UxDisplay, cmap, &c);

	if(rtrn == 0)
	{	if(depth == 1)
		{	/* half color intensity */
			if((c.red > 49152) || (c.green > 49152) ||
			   (c.blue > 49152))
			{	c.red= c.green= c.blue= 65535;
				c.pixel= WhitePixel(UxDisplay, UxScreen);
			}
			else
			{	c.red= c.green= c.blue= 0;
				c.pixel= BlackPixel(UxDisplay, UxScreen);
			}

			add_color(from->addr, &c);

			to->addr= (caddr_t)&c;
			to->size= sizeof(XColor);

			return;
		}
		
		UxInternalError(__FILE__, __LINE__,
				CGETS( MS_MISC_COLORMAP_ALLOC,
                                DS_MS_MISC_COLORMAP_ALLOC), from->addr);
		to->addr= NULL;
		to->size= 0;

		return;
	}

	add_color(from->addr, &c);

	to->addr= (caddr_t)&c;
	to->size= sizeof(XColor);
}

/* Xt provides a XtRString to XtRPixel converter */
#ifdef NOT_NEEDED
/******************************************************************************
 ==== LOCAL ==================================================================
*******************************************************************************
NAME:		void		string_to_pixel(args, num_args, from, to)

INPUT:		XrmValuePtr	args		- converter args
		Cardinal	*num_args	- number of args
		XrmValuePtr	from		- value to convert
		XrmValuePtr	to		- return value

DESCRIPTION:	This is the toolkit resource converter for converter a 
		string color name to a pixel value.  It is registered by
		UxInit_colors.  If the color is not yet allocated it is
		allocated if possible.

CREATION:	Jun 21/1989
REVISIONS:	--
-----------------------------------------------------------------------------*/

static void string_to_pixel(args, num_args, from, to)
	XrmValuePtr	args;
	Cardinal	*num_args;
	XrmValuePtr	from;
	XrmValuePtr	to;
{
	XColor		*c;

	string_to_xcolor(args, num_args, from, to);

	if(to->addr != NULL)
	{	c= (XColor *)to->addr;
		to->addr= (caddr_t)&(c->pixel);
		to->size= sizeof(int);
	}
}
#endif
