pkg://xcol-1.7.tgz:19840/
xcol-1.7/xcol.c
downloads
/****************************************************************
* *
* xcol - program to edit color-name-occurrences in textfiles *
* *
* Written by Helmut Hoenig, Feb. 1990. *
* University of Kaiserslautern, Germany *
* *
****************************************************************
* *
* additinal changes: Sep. 1995. *
* e-mail: Helmut.Hoenig@hub.de *
* *
****************************************************************/
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/cursorfont.h>
#include <sys/param.h>
#include <stdio.h>
#include <strings.h>
#include <ctype.h>
/*----------------------------------------------------------------------------*/
#define COLOR_FONT "-adobe-times-bold-r-normal--18-*-iso8859-1"
#define TEXT_FONT "-adobe-times-bold-r-normal--12-*-iso8859-1"
#define DEFAULT_FONT "-*-*-*-R-*-*-*-120-*-*-*-*-ISO8859-1"
#define RGB_FILE "/usr/lib/X11/rgb.txt"
/* MAX_??? - definitions are used in the definition of some local arrays,
where I didn't want to make complicated memory allocation. */
#define MAX_CELLS 256 /* number of cells, used by the programm*/
#define MAX_COLS 1000 /* colors in rgb.txt-file */
#define MAX_COLOR_LINES 400 /* color occurrences in a textfile */
#define MAX_LINE_LENGTH 1000 /* linelength of textfile */
/*----------------------------------------------------------------------------*/
/* switch on/off some bugs ?? */
#define CHG_TEXT_WINDOW_COLORMAP
#define _RECOLOR_CURSOR
/* variables for parameters (default is set) */
int reverse = 0;
int BO_def = 0;
int darkness=50;
int gran =11;
int original= 0;
/* X-Data */
Display *display;
Screen *screen;
XFontStruct *finfo;
GC gc;
int cells;
/* the grey-pixmap is used to get an impression of mixing the foreground
* and background color of a color-line.
*/
#define grey_width 16
#define grey_height 16
static char grey_bits[] = {
0x55, 0x55, 0xaa, 0xaa, 0x55, 0x55, 0xaa, 0xaa,
0x55, 0x55, 0xaa, 0xaa, 0x55, 0x55, 0xaa, 0xaa,
0x55, 0x55, 0xaa, 0xaa, 0x55, 0x55, 0xaa, 0xaa,
0x55, 0x55, 0xaa, 0xaa, 0x55, 0x55, 0xaa, 0xaa};
Pixmap grey_pixmap;
Cursor mw_cursor; /* Cursor in main-window */
Cursor tw_cursor; /* Cursor in text-window */
Cursor subsel_cursor; /* Cursor during selection of associated colors */
Cursor text_cursor; /* Cursor while looking in the source-file */
Cursor quest_cursor; /* Cursor while asking for write-confirmation */
Cursor updown_cursor; /* Cursor while making association */
/* Mainwindow-Data */
Window mw; /* Window-Id */
unsigned int dx, dy; /* current size of the window */
int BO=14; /* current size of the color-boxes in the window */
/* Textwindow-Data */
Window tw = 0;
XFontStruct *tinfo; /* Structure of the textfont */
int char_width, char_height;/* char-size depending on the font */
char *tw_message[2]; /* messages in header and footer-line */
int twidth; /* width in pixel */
int tw_lines; /* height in lines (header&footer not included) */
int act_line=0; /* active-line */
int act_offset=0; /* first color-line (when not all lines fit in the window) */
/* Subwindow-Data (little window for selected color) */
Window subw; /* Window-Id */
int sdx, sdy; /* current size of subwindow */
int subcols; /* number of associated colors in the subwindow */
/* Color-Management */
Colormap my_map=0;
int my_pixel[MAX_CELLS]; /* flag: 0 = pixel not used in my program */
int only_mine; /* flag: 1 = allocations only in own map */
#define NotAllocated (-1L)
#define Undefined (-2L)
typedef struct _color_def {
int r, g, b; /* rgb-value from the 'rbg.txt'-file */
char *name; /* name from the 'rgb.txt'-file */
int x, y; /* position in main window */
unsigned long pixel; /* allocated pixel for the color */
struct _color_def *associated; /* colors with different intensity (e.g. 'blue' -> 'blue4' ... ) */
struct _color_def *brother; /* colors with different name (e.g. 'OldLace' -> 'old lace') */
} ColorDef;
typedef struct _color_strings {
char *name;
int length;
ColorDef *def;
} ColorString;
ColorDef *color[MAX_COLS]; /* field with the definitions of the colors */
ColorString cname[MAX_COLS]; /* sorted field with the names of all colors */
ColorString *first[256]; /* 'Hash-Table', points to the first name
that starts with the given letter. */
int color_names; /* number of color-names
= entries in the 'rgb.txt'-file */
int color_number; /* number of 'different' colors
= number of colors shown in the cube */
#define BLACK_STRING "black"
#define WHITE_STRING "white"
#define GREY_STRING "gray"
ColorDef std_black = { 0, 0, 0, BLACK_STRING };
ColorDef std_white = { 255, 255, 255, WHITE_STRING };
ColorDef std_grey = { 192, 192, 192, GREY_STRING };
unsigned long white, black, grey; /* pixel-values (in my_map !!) */
ColorDef *back_def; /* default background in textwindow */
/*----------------------------------------------------------------------------*/
typedef struct _text_line { /* structure to store the text-file */
char *contents;
struct _text_line *next;
struct _text_line *previous;
} TextLine;
typedef struct _color_line { /* structure for a line with color-entry */
TextLine *line; /* pointer to the textline */
ColorDef *color; /* the color defined in the line */
ColorDef *help; /* a help-color for the background */
int reverse; /* flag to display line in reverse */
int pos_in_line; /* position of the color-name in the line */
int assoc; /* corresponding color-line, when a
'foreground-background'-association
was found (or entered) */
} ColorLine;
char *file_name; /* name of the text-file */
TextLine *loaded_text; /* Pointer to the first line */
ColorLine line[MAX_COLOR_LINES]; /* array of the color-lines */
int color_lines; /* number of the color-lines */
int longest_colored; /* length of the longest color-line */
char space_char[256]; /* flag, which chars should be recognized
as spaces */
/********************************************************************************
* parsing the text-file (not very efficient, but who cares) *
********************************************************************************/
void set_default_spaces()
{
memset( space_char, 0, (int)sizeof(space_char) );
space_char[ ' ' ] = space_char[ '\t' ] = space_char[ '\n' ] =
space_char[ ':' ] = space_char[ '"' ] = 1;
}
int strncase_equal( s1, s2, n )
register char *s1;
register char *s2;
register int n;
/* the function is NOT correct, since just proves, if strings are equal
when the 5th bit of their characters is ignored.
*/
{
while(n--)
{ if ( ((*s1++)^(*s2++))&((unsigned char)~32) ) return(1);
}
return(0);
}
int strcase_equal( s1, s2 )
char *s1,*s2;
{
int n1,n2;
n1 = strlen(s1);
n2 = strlen(s2);
if (n1!=n2) return(-1);
else return(strncase_equal( s1, s2, n1 ));
}
string_exchange( cline, new_color )
ColorLine *cline;
ColorDef *new_color;
/* replaces the color-string in a color-line */
{
char new_line[MAX_LINE_LENGTH];
int pos;
pos = cline->pos_in_line;
strncpy( &new_line[0], cline->line->contents, pos );
strcpy( &new_line[pos], new_color->name );
strcat( new_line, &cline->line->contents[pos+strlen(cline->color->name)] );
free( cline->line->contents );
cline->line->contents = (char *)malloc((unsigned) strlen( new_line )+1 );
strcpy( cline->line->contents, new_line );
}
void check_colors( in_line )
TextLine *in_line;
/* checks, if a color exists in the given line and possibly adds
* the line to the list of color-lines.
*/
{
int i, c;
char lett;
char check;
ColorString *col;
unsigned char *act_line = in_line->contents;
int alen;
alen=c=strlen(act_line);
while(c>0)
{
c--;
while( (c>0) && !(space_char[act_line[c-1]])) c--;
lett = act_line[c];
if (isalpha(lett))
{
if (isupper(lett)) lett = tolower( lett );
/* compares both cases */
for (i=0;i<2;i++)
{ for (col=first[lett];col<first[lett+1];col++)
{
check = (c+col->length<alen)?act_line[c+col->length]:0;
if (space_char[check])
{ if ((strncase_equal( &act_line[c], col->name, col->length )==0 ))
{ line[color_lines].line = in_line;
line[color_lines].color= col->def;
line[color_lines].help = back_def;
line[color_lines].pos_in_line = c;
line[color_lines].reverse = 0;
line[color_lines].assoc = -1;
if (strstr(in_line->contents,"GlobalBackground")) {
back_def = col->def;
line[color_lines].assoc = -2;
}
if (original)
{ string_exchange( &line[color_lines], col->def );
}
if (XTextWidth( tinfo, act_line, strlen(act_line) )>longest_colored)
longest_colored = XTextWidth( tinfo, act_line, strlen(act_line) );
color_lines++;
return;
}
}
}
lett = toupper( lett );
}
}
}
}
int spc_line( search_string, line, name, length )
char *search_string;
TextLine *line;
char *name;
int *length;
/* searches for the search-string in the given line. If it exists, the name
* in front of the search-string is copied to name and its length is returned.
*/
{
int c, sl, cs;
c = strlen( line->contents );
sl = strlen(search_string);
while( c>0 )
{ if (strncase_equal( search_string, &line->contents[c], sl )==0)
{ cs=c;
do
{ cs--;
if (isspace(line->contents[cs])) break;
}
while(cs>0);
*length = c-cs;
if (cs)
{ (*length)--; cs++;
}
strncpy( name, &line->contents[cs], *length );
name[*length]='\0';
return(1);
}
c--;
}
return(0);
}
void find_assocs()
/* tries to find 'Foreground-Background'-Associations in the Color-Lines */
{
int i, j;
char name1[100], name2[100];
int length1, length2;
for (i=0;i<color_lines;i++)
{ if (spc_line("foreground", line[i].line, name1, &length1))
{ for (j=i+1;j>=i-1;j-=2)
{ if ((j>=0)&&(j<color_lines))
{ if (spc_line("background", line[j].line, name2, &length2))
{
if (strcmp(name1, name2)==0)
{ line[i].reverse=0;
line[i].help = line[j].color;
line[i].assoc= j;
line[j].reverse=1;
line[j].help = line[i].color;
line[j].assoc= i;
}
}
}
}
}
else if ((spc_line("background", line[i].line, name1, &length1))&&(line[i].assoc<0))
{ for (j=i+1;j>=i-1;j-=2)
{ if ((j>=0)&&(j<color_lines))
{ if (spc_line("border", line[j].line, name2, &length2))
{
if (strcmp(name1, name2)==0)
{ line[i].reverse=1;
line[i].help = line[j].color;
line[i].assoc= j;
line[j].reverse=0;
line[j].help = line[i].color;
line[j].assoc= i;
}
}
}
}
}
}
}
int load_file( fname )
char *fname;
/* loads the text-file and tries to find color-entries in each line */
{
FILE *fp;
TextLine *act, *next;
char linebuffer[MAX_LINE_LENGTH];
/* load the file with colors */
longest_colored = 0;
color_lines = 0;
fp = fopen( fname, "r" );
if (fp==NULL)
{ fprintf( stderr, "can't load file '%s'.\n", fname );
return(0);
}
loaded_text = act = NULL;
while (fgets( linebuffer, sizeof linebuffer, fp )!=NULL)
{ next = (TextLine *)malloc((unsigned)sizeof(TextLine));
next->contents = (char *)malloc((unsigned)strlen(linebuffer)+1);
strcpy( next->contents, linebuffer );
check_colors( next );
if (act==NULL)
{ loaded_text=act = next;
next->previous = NULL;
}
else
{ act->next = next;
next->previous = act;
act = next;
}
}
fclose( fp );
act->next=NULL;
return(1);
}
int write_file( fname )
char *fname;
{
FILE *fp;
TextLine *act;
fp = fopen( fname, "w" );
if (fp==NULL) return(-1);
act = loaded_text;
while( act )
{ if (fputs( act->contents, fp )==EOF)
{ fprintf(stderr, "write error on file '%s'\n", fname);
fclose(fp);
return(-2);
}
act = act->next;
}
fclose( fp );
return(0);
}
/********************************************************************************
* allocating, freeing, sorting, searching COLORS. *
********************************************************************************/
ColorDef *find_color( name )
char *name;
/* searches in the tree of colordefinitions for the named color */
{
ColorDef *erg, *assoc;
int i;
for (i=0;i<color_number;i++)
{ erg = color[i];
do
{
if (strcase_equal(erg->name, name)==0) {
erg->pixel = color[i]->pixel; /* just to be sure that the pixel is set */
return( erg );
}
assoc = erg->associated;
while( assoc )
{ if (strcase_equal(assoc->name, name)==0) return( assoc );
assoc = assoc->associated;
}
erg = erg->brother;
}
while (erg);
}
return(NULL);
}
void load_color( act )
ColorDef *act;
/* allocates a pixel for the color, if it is not already allocated. When it's
* still possible to allocate pixels in the DefaultColormap, this is done and
* the same color is stored in both maps. If no more cells are available in
* the DefaultColormap, the program continues working only in its own map.
*/
{
XColor scr;
long pixel;
if (act->pixel==NotAllocated)
{ if (!only_mine)
{ if ( (!XAllocColorCells( display, DefaultColormapOfScreen(screen), True,
NULL, 0, (unsigned long*)&pixel, 1 )) || (pixel>=cells) )
{
for (pixel=0;pixel<cells;pixel++)
{
if (my_pixel[pixel])
{ XFreeColors( display, DefaultColormapOfScreen(screen),
(unsigned long*)&pixel, 1, 0 );
}
}
only_mine=1;
#ifdef CHG_TEXT_WINDOW_COLORMAP
/* when switched on, all windows (not only the textwindow), are displayed
* in my Colormap, when the DefaultColormap hasn't got any more cells available.
* Try the option -gran100 and search for the 'gray'-color in the main-window
* to reach the extremes of the program.
*/
if (tw)
{ XSetWindowColormap( display, tw, my_map );
}
#endif
}
}
if (only_mine)
{ for (pixel=cells-1;pixel>=0;pixel--)
{ if (my_pixel[pixel]==0) break;
}
/* the reaction to an overflow in the color-map is hard, but
* I can't think of an easy solution for that problem.
*/ if (pixel<0)
{ fprintf( stderr, "You did it. The Colormap if full.\n");
if (CellsOfScreen(screen)>MAX_CELLS)
{ fprintf( stderr, "Compile the program again with the\n");
fprintf( stderr, "MAX_CELLS-macro set to an higher value.\n");
}
exit(0);
}
}
act -> pixel = pixel;
scr.pixel = pixel;
scr.flags = DoRed | DoGreen | DoBlue;
scr.red = act->r << 8;
scr.green = act->g << 8;
scr.blue = act->b << 8;
XStoreColor( display, my_map, &scr );
if (!only_mine)
XStoreColor( display, DefaultColormapOfScreen(screen), &scr );
}
my_pixel[act->pixel]++;
}
void unload_color( act )
ColorDef *act;
/* The color is not used anymore. It is possible that the color was loaded
* more than once and therefor, the cell can't be freed.
*/
{
if (act->pixel==NotAllocated) return;
if ((--my_pixel[act->pixel])==0)
{ if (!only_mine)
{ XFreeColors( display, DefaultColormapOfScreen(screen),
&act->pixel, 1, 0 );
}
act->pixel=NotAllocated;
}
}
void load_text_colors()
/* to load all colors used in the color-lines of the text-file */
{
int i;
for (i=0;i<color_lines;i++)
{ load_color( line[i].color );
load_color( line[i].help );
}
}
void exchange( old, new )
ColorDef **old;
ColorDef *new;
/* correct exchanging of a loaded color */
{
if (*old)
{ unload_color( *old );
}
load_color( new );
*old = new;
}
/*----------------------------------------------------------------------------*/
/*
* functions to sort the colors
*/
int color_name_sort( p1, p2 )
ColorString *p1, *p2;
{
return(strcmp(p1->name, p2->name));
}
int color_sort( p1, p2 )
ColorDef **p1, **p2;
{
char *s1, *s2;
if ((*p1)->b!=(*p2)->b) return(((*p1)->b>(*p2)->b)?1:-1);
if ((*p1)->g!=(*p2)->g) return(((*p1)->g>(*p2)->g)?1:-1);
if ((*p1)->r!=(*p2)->r) return(((*p1)->r>(*p2)->r)?1:-1);
s1 = index((*p1)->name, ' ');
s2 = index((*p2)->name, ' ');
s1 = s2 = NULL;
if (s1)
{ if (s2) return(strcmp((*p1)->name, (*p2)->name));
else return(1);
}
else
{ if (s2) return(-1);
else return(strcmp((*p1)->name, (*p2)->name));
}
}
int color_sort_r( p1, p2 )
ColorDef **p1, **p2;
{
if ((*p1)->b!=(*p2)->b) return(((*p1)->b>(*p2)->b)?-1:1);
if ((*p1)->g!=(*p2)->g) return(((*p1)->g>(*p2)->g)?-1:1);
if ((*p1)->r!=(*p2)->r) return(((*p1)->r>(*p2)->r)?-1:1);
return(0);
}
void brother_sort( first )
ColorDef **first;
{
ColorDef *list[1000];
int length;
length = 0;
list[length] = *first;
while(list[length]->brother)
{ list[length+1] = list[length]->brother;
length++;
}
qsort( (char *)list, length+1, sizeof(ColorDef *), color_sort );
list[length]->brother = NULL;
while(length>0)
{ list[length-1]->brother = list[length];
length--;
}
*first = list[0];
}
void associated_sort( first )
ColorDef *first;
{
ColorDef *list[1000];
int length;
length = 0;
list[length] = first;
while(list[length]->associated)
{ list[length+1] = list[length]->associated;
length++;
}
qsort( (char *)&list[1], length, sizeof(ColorDef *), color_sort );
list[length]->associated = NULL;
while(length>0)
{ list[length-1]->associated = list[length];
length--;
}
}
/*----------------------------------------------------------------------------*/
/*
* functions to load the color-file and build the tree with colordefinitions
*/
char *cut_digits( name )
char *name;
/* cuts digits from a color-string. returns a pointer to a static string
* which of course must not be freed. if there where no digits, the original
* pointer is returned.
*/
{
static char short_name[40];
int i;
i = strlen(name);
if ((i>39)||(!isdigit(name[i-1]))||!strncmp(name,"CSO_rgb",7))
return(name);
strcpy( short_name, name );
i--;
while ((i>0)&&(isdigit(short_name[i])))
{ short_name[i] = '\0';
i--;
}
return(short_name);
}
void next_name( act )
ColorDef *act;
/* collects color-names for the hash-table */
{
if (act->pixel==Undefined)
{ fprintf(stderr, "%s not defined.\n", act->name);
return;
}
cname[color_names].name = act->name;
cname[color_names].length = strlen(act->name);
cname[color_names].def = act;
color_names++;
}
ColorDef *make_entry( new )
ColorDef *new;
/* allocates space for the data of a new color */
{
ColorDef *erg;
erg = (ColorDef *)malloc((unsigned) sizeof(ColorDef) );
memcpy( (char *)erg, (char *)new, sizeof(ColorDef) );
erg -> associated = NULL;
erg -> brother = NULL;
erg -> pixel = NotAllocated;
return( erg );
}
void new_color( new )
ColorDef *new;
/* searches for overlaps in the color-field and stores the new color */
{
char *search_name;
ColorDef *act;
ColorDef *help;
int i;
int subname = 0;
search_name = cut_digits( new->name );
subname = (search_name!=new->name);
act = find_color( search_name );
if (act) {
if (subname) /* found and associated entry */
{ help = act->associated;
act->associated = make_entry( new );
act->associated->associated = help;
}
else /* strange: color declared twice ? */
{ if (act->pixel==Undefined)
{ memcpy( (char *)act, (char *)new, sizeof(ColorDef)-2*sizeof(ColorDef *) );
act->pixel = NotAllocated;
}
else
{
help = act->brother;
act->brother = make_entry( new );
act->brother->brother = help;
}
}
}
else {
for (i=0;i<color_number;i++)
{ if ( (new->r==color[i]->r) && (new->g==color[i]->g) && (new->b==color[i]->b) ) break;
}
if (i<color_number)
{ help = color[i]->brother;
color[i]->brother = make_entry( new );
color[i]->brother->brother = help;
}
else
{ if (subname) /* indexed name found before original */
{ act = (ColorDef *)malloc((unsigned) sizeof(ColorDef) );
memset( (char *)act, (char)-1, sizeof(ColorDef) );
act->pixel = Undefined;
act->name = (char *)malloc((unsigned) strlen(search_name)+1 );
strcpy( act->name, search_name );
act->associated = make_entry( new );
act->brother = NULL;
color[color_number++] = act;
}
else /* found new color */
{ color[color_number++] = make_entry( new );
}
}
}
}
load_standard( act )
ColorDef *act;
{
XColor exact_def;
if (XParseColor( display, DefaultColormapOfScreen(screen), act->name,
&exact_def ))
{ act->r = exact_def.red >> 8;
act->g = exact_def.green >> 8;
act->b = exact_def.blue >> 8;
}
new_color( act );
}
/*----------------------------------------------------------------------------*/
update_map()
/* sets unused pixels in my_map to the colors (with different intensity)
* of the DefaultColormap.
*/
{
XColor qcols[MAX_CELLS];
int i, j;
j=0;
for (i=0;i<cells;i++)
{ if (my_pixel[i]==0) qcols[j++].pixel=i;
}
XQueryColors( display, DefaultColormapOfScreen(screen), qcols, j );
for (i=0;i<j;i++)
{ qcols[i].red = ((long)qcols[i].red *darkness)/100;
qcols[i].green = ((long)qcols[i].green*darkness)/100;
qcols[i].blue = ((long)qcols[i].blue *darkness)/100;
qcols[i].flags = DoRed | DoGreen | DoBlue;
}
XStoreColors( display, my_map, qcols, j );
}
create_new_map()
/* get an own colormap */
{
int i;
XColor qcols[MAX_CELLS];
unsigned long pixel[MAX_CELLS];
/* allocate new colormap and copy the darkened colors of the default-map */
my_map = XCreateColormap( display, mw,
XDefaultVisualOfScreen(screen), AllocAll);
if (my_map==(Colormap)0)
{ fprintf(stderr, "can't create colormap.\n" );
exit(0);
}
memset( (char *)my_pixel, (char)0, sizeof(my_pixel) );
/* copy the default-map */
for (i=0;i<cells;i++) qcols[i].pixel = i;
XQueryColors( display, DefaultColormapOfScreen(screen), qcols, cells );
for (i=0;i<cells;i++)
{ qcols[i].red = ((long)qcols[i].red *darkness)/100;
qcols[i].green = ((long)qcols[i].green*darkness)/100;
qcols[i].blue = ((long)qcols[i].blue *darkness)/100;
qcols[i].flags = DoRed | DoGreen | DoBlue;
}
XStoreColors( display, my_map, qcols, cells );
/* try to allocate the color_cells in the default-map */
if (XAllocColorCells( display, DefaultColormapOfScreen(screen), True,
NULL, 0, pixel, color_number ))
{ int high_value=0;
/* store the colors into my map and into and into the default-colormap
* as there are enough cells for both.
*/
for (i=0;i<color_number;i++)
{ qcols[i].pixel = pixel[i];
qcols[i].flags = DoRed | DoGreen | DoBlue;
qcols[i].red = color[i]->r << 8;
qcols[i].green = color[i]->g << 8;
qcols[i].blue = color[i]->b << 8;
color[i]->pixel = pixel[i];
if (pixel[i]>=cells)
{ high_value=1;
break;
}
my_pixel[pixel[i]]=1;
}
if (high_value)
{ XFreeColors( display, DefaultColormapOfScreen(screen),
pixel, color_number, 0 );
only_mine = 1;
}
else
{
XStoreColors( display, DefaultColormapOfScreen(screen), qcols, color_number );
XStoreColors( display, my_map, qcols, color_number );
only_mine = 0;
}
}
else only_mine = 1;
if (only_mine)
{
/* pixels are just used from high to low numbers */
for (i=0;i<color_number;i++)
{
qcols[i].pixel = cells-i-1;
qcols[i].flags = DoRed | DoGreen | DoBlue;
qcols[i].red = color[i]->r << 8;
qcols[i].green = color[i]->g << 8;
qcols[i].blue = color[i]->b << 8;
color[i]->pixel = cells-i-1;
my_pixel[cells-i-1]=1;
}
XStoreColors( display, my_map, qcols, color_number );
/* afterwards, all free pixels of the default-map are allocated
* and set to the values of the new colormap.
*/
i=0;
while( XAllocColorCells( display, DefaultColormapOfScreen(screen), True,
NULL, 0, &pixel[i], 1 ) )
{ qcols[i].pixel = pixel[i];
i++;
}
XQueryColors( display, my_map, qcols, i );
XStoreColors( display, DefaultColormapOfScreen(screen), qcols, i );
XFreeColors( display, DefaultColormapOfScreen(screen), pixel, i, 0 );
only_mine = 1;
}
/* the pixels for black, white have to be used from my_map, since
* the entries of the DefaultColormap are possibly darkened.
*/
black = find_color( BLACK_STRING )->pixel;
my_pixel[black]++;
white = find_color( WHITE_STRING )->pixel;
my_pixel[white]++;
grey = find_color( GREY_STRING )->pixel;
my_pixel[grey]++;
}
destroy_colormap()
/* not used */
{
unsigned long pixel[MAX_CELLS];
int i, j;
ColorDef *assoc, *erg;
XFreeColormap( display, my_map );
j=0;
if (!only_mine)
{ for (i=0;i<cells;i++)
{ if (my_pixel[i]) pixel[j++] = i;
}
XFreeColors( display, DefaultColormapOfScreen(screen), pixel, j, 0 );
}
my_map = 0;
memset( (char *)my_pixel, (char)0, sizeof(my_pixel) );
for (i=0;i<color_number;i++)
{ erg = color[i];
do
{ erg->pixel = NotAllocated;
assoc = erg->associated;
while( assoc )
{ assoc->pixel = NotAllocated;
assoc = assoc->associated;
}
erg = erg->brother;
}
while (erg);
}
}
/********************************************************************************
* Textwindow-Functions *
********************************************************************************/
void draw_message( num )
int num;
/* draws upper (0) or lower (1) message-entry */
{
int y;
y = (num)?(tw_lines+1)*char_height:0;
XClearArea( display, tw, 0, y, twidth, char_height, False );
XSetForeground( display, gc, white );
if (tw_message[num])
{ XSetFont( display, gc, tinfo->fid );
XDrawString( display, tw, gc,
0, y+tinfo->ascent,
tw_message[num], strlen( tw_message[num] ) );
}
if (num) XDrawLine( display, tw, gc, 0, y, twidth, y );
else XDrawLine( display, tw, gc, 0, char_height-1, twidth, char_height-1 );
}
void set_message( msg, num )
char *msg;
int num;
/* sets upper or lower message entry */
{
if (tw_message[num]) free(tw_message[num]);
if (msg)
{ tw_message[num] = (char *)malloc((unsigned) strlen(msg)+1 );
strcpy( tw_message[num], msg );
}
else tw_message[num]=NULL;
draw_message( num );
}
void reset_messages()
{
char mess[20];
if (act_offset)
{ sprintf( mess, "*** UP (%d) ***", act_offset);
set_message( mess, 0 );
}
else set_message( " click right button here to write file.", 0 );
if (act_offset+tw_lines<color_lines)
{ sprintf( mess, "*** DOWN (%d) ***", color_lines-act_offset-tw_lines);
set_message( mess, 1 );
}
else set_message( (char *)NULL, 1 );
}
void draw_string( i )
int i;
/* draws a color-line */
{
int j;
int y;
int p1,p2;
unsigned long fg_pixel, bg_pixel, help;
j=i-act_offset;
if ((tw==(Window)0)||(j<0)||(j>=tw_lines)) return;
y=(j+1)*char_height;
fg_pixel = line[i].color->pixel;
if (fg_pixel==NotAllocated)
{ fprintf(stderr, "fg_pixel of %s not allocated.\n", line[i].line->contents);
}
bg_pixel = line[i].help->pixel;
if (bg_pixel==NotAllocated)
{ fprintf(stderr, "bg_pixel of %s not allocated.\n", line[i].line->contents);
}
if (line[i].reverse)
{ help = fg_pixel;
fg_pixel = bg_pixel;
bg_pixel = help;
}
/* clearing the background */
XSetForeground(display, gc, bg_pixel);
XFillRectangle( display, tw, gc, 0, y, twidth, char_height);
XSetFont( display, gc, tinfo->fid );
XSetForeground( display, gc, fg_pixel );
p1 = line[i].pos_in_line;
p2 = p1 + strlen( line[i].color->name );
p1 = XTextWidth( tinfo, line[i].line->contents, p1 )+2*char_width;
p2 = XTextWidth( tinfo, line[i].line->contents, p2 )+2*char_width;
XDrawString( display, tw, gc,
2*char_width, y+tinfo->ascent,
line[i].line->contents, strlen(line[i].line->contents)-1 );
XSetForeground( display, gc, fg_pixel );
XDrawLine( display, tw, gc, p1, y+char_height-2, p2, y+char_height-2 );
/* draws the pixmap (at least some planes of it) */
XSetState( display, gc, (unsigned long)AllPlanes, (unsigned long)0,
GXxor, fg_pixel^bg_pixel );
XCopyArea( display, grey_pixmap, tw, gc, 0, 0, char_width, char_height, twidth-3*char_width, y );
XSetState( display, gc, fg_pixel, bg_pixel,
GXcopy, (unsigned long)AllPlanes );
if (i==act_line)
{ XDrawRectangle( display, tw, gc, 0, y, twidth-1, char_height-1);
XFillRectangle( display, tw, gc, 0, y, 2*char_width, char_height);
XFillRectangle( display, tw, gc, twidth-2*char_width, y, 2*char_width, char_height);
XSetForeground( display, gc, bg_pixel );
}
else XSetForeground( display, gc, fg_pixel );
/* drawing indicator 'bg', 'fg', or 'R' */
if (line[i].reverse)
{ if (line[i].assoc>=0)
{ XDrawString( display, tw, gc, 0, y+tinfo->ascent, "bg", 2 );
}
else
{ XSetForeground( display, gc, black );
XSetBackground( display, gc, white );
XDrawImageString( display, tw, gc, 0, y+tinfo->ascent, "R", 1 );
}
}
else
{ if (line[i].assoc>=0)
XDrawString( display, tw, gc, 0, y+tinfo->ascent, "fg", 2 );
}
}
void change_color( act_line, new_color )
int act_line;
ColorDef *new_color;
/* complete change of the color in the given line */
{
int i;
if (act_line<0) return;
/* change the string */
string_exchange( &line[act_line], new_color );
/* allocate the color */
exchange( &line[act_line].color, new_color );
/* update the window (exchange corresponding color too) */
draw_string(act_line);
if (line[act_line].assoc>=0)
{ exchange( &line[line[act_line].assoc].help, new_color );
draw_string(line[act_line].assoc);
}
if (line[act_line].assoc==-2)
{ for (i=0;i<color_lines;i++) {
if (line[i].assoc==-1)
{ exchange( &line[i].help, new_color );
draw_string(i);
}
}
}
}
redraw_tw( l1, l2 )
int l1, l2;
/* redraws parts of the text-window */
{
int i;
if (l1==0)
{ draw_message( 0 );
l1++;
}
if (l2>tw_lines)
{ draw_message( 1 );
l2=tw_lines;
}
for (i=l1;i<=l2;i++) draw_string( act_offset+i-1 );
}
/*----------------------------------------------------------------------------*/
void show_string( row, text )
int row;
TextLine *text;
{
if (text)
{ XSetForeground( display, gc, white );
XFillRectangle( display, tw, gc, 0, row*char_height, twidth, char_height );
XSetForeground( display, gc, black );
XDrawString( display, tw, gc,
2*char_width, row*char_height+tinfo->ascent,
text->contents, strlen(text->contents) );
}
else
{ XSetForeground( display, gc, black );
XFillRectangle( display, tw, gc, 0, row*char_height, twidth, char_height );
}
}
void show_text( i )
int i;
/* shows the part of the text, where line i occurred. The old contents of the
* text-window is stored in a pixmap if possible.
*/
{
TextLine *upper,*lower;
int upper_i,lower_i;
XEvent event;
Pixmap back;
back = XCreatePixmap( display, tw, twidth, (tw_lines+2)*char_height, DefaultDepthOfScreen(screen) );
if (back)
{ XCopyArea( display, tw, back, gc,
0, 0, twidth, (tw_lines+2)*char_height,
0, 0 );
}
XGrabPointer(display, tw, False,
ButtonPressMask|ButtonReleaseMask, GrabModeAsync, GrabModeAsync,
tw, text_cursor, CurrentTime );
XSetFont( display, gc, tinfo->fid );
upper = line[i].line;
upper_i = i-act_offset+1;
XSetForeground( display, gc, grey );
XFillRectangle( display, tw, gc, 0, upper_i*char_height, twidth, char_height );
XSetForeground( display, gc, black );
XDrawString( display, tw, gc,
2*char_width, upper_i*char_height+tinfo->ascent,
upper->contents, strlen(upper->contents) );
lower = upper;
upper = upper;
lower_i = upper_i + 1;
upper_i--;
while( ( upper_i>=0 )||(lower_i<=tw_lines+1) )
{ if ( upper_i>=0 )
{ if (upper) upper=upper->previous;
show_string( upper_i--, upper );
}
if (lower_i<=tw_lines+1)
{ if (lower) lower=lower->next;
show_string( lower_i++, lower );
}
}
XWindowEvent( display, tw, ButtonPressMask|ButtonReleaseMask, &event );
XUngrabPointer( display, CurrentTime );
if (back)
{ XCopyArea( display, back, tw, gc,
0, 0, twidth, (tw_lines+2)*char_height,
0, 0 );
XFreePixmap( display, back );
}
else redraw_tw( 0, tw_lines+1 );
}
/*----------------------------------------------------------------------------*/
void write_quest( num )
int num;
/* waits for a confirmation before the file is written with backup. */
{
XEvent event;
set_message( " confirm writing with right button !", num );
XBell( display, 10 );
XGrabPointer(display, tw, False,
ButtonPressMask|LeaveWindowMask, GrabModeAsync, GrabModeAsync, None, quest_cursor, CurrentTime );
XWindowEvent( display, tw, ButtonPressMask|LeaveWindowMask, &event );
if ((event.xany.type==ButtonPress)&&(event.xbutton.button==Button3))
{ char back_name[MAXPATHLEN];
strcpy( back_name, file_name );
strcat( back_name, "~" );
if (rename( file_name, back_name ))
{ set_message(" can't create backup. writing aborted.", num);
}
else
{ if (write_file( file_name ))
set_message(" writing failed.", num);
else set_message(" file written with backup.", num);
}
}
else set_message(" writing aborted.", num);
XUngrabPointer( display, CurrentTime );
}
/*----------------------------------------------------------------------------*/
void new_assoc( act )
int act;
/* the function waits, until the button is released or the mouse is moved
* into an associated line. If both lines were already connected, they get
* disconnected. If no line was connected, the first line will get the
* foreground and the second line the background of the association.
*/
{
XEvent event;
int new;
if (line[act].assoc>=0)
{ set_message( " move to associated line to disconnect.", 0 );
}
else set_message( " move to background to connect.", 0 );
XGrabPointer(display, tw, False,
ButtonReleaseMask|PointerMotionMask, GrabModeAsync, GrabModeAsync, tw, updown_cursor, CurrentTime );
new = act;
do
{ XWindowEvent( display, tw, ButtonReleaseMask|PointerMotionMask, &event );
if (event.xany.type==MotionNotify)
{ new = (event.xmotion.y/char_height)+act_offset-1;
if (new!=act) break;
}
}
while( event.xany.type!=ButtonRelease );
if (new==act)
{ if (line[act].assoc<0)
{ line[act].reverse^=1;
}
else
{ ColorDef *help;
help = line[act].color;
change_color( act, line[line[act].assoc].color );
change_color( line[act].assoc, help );
}
reset_messages();
}
else
{ if (line[act].assoc<0)
{ if (line[new].assoc<0)
{ set_message( " new association set.", 0 );
XBell( display, 5 );
line[act].assoc = new;
exchange( &line[act].help, line[new].color );
line[act].reverse = 0;
line[new].assoc = act;
exchange( &line[new].help, line[act].color );
line[new].reverse = 1;
draw_string( new );
draw_string( act );
}
else
{ set_message( " line already connected.", 0 );
XBell( display, 10 );
}
}
else
{ if (line[act].assoc==new)
{ set_message( " disconnected.", 0 );
XBell( display, 5 );
line[act].assoc = -1;
line[new].assoc = -1;
draw_string( new );
draw_string( act );
}
else
{ set_message( " lines not associated.", 0 );
XBell( display, 10 );
}
}
}
while (event.xany.type!=ButtonRelease)
{ XWindowEvent( display, tw, ButtonReleaseMask, &event );
}
XUngrabPointer( display, CurrentTime );
}
/*----------------------------------------------------------------------------*/
void tw_event( event )
XEvent *event;
/* event-execution for the text-window */
{
switch( event->xany.type )
{
case ConfigureNotify:
{ XEvent help;
int tw_new;
tw_new = (event->xconfigure.height/char_height)-2;
if ((twidth==event->xconfigure.width)&&(tw_lines==tw_new)) break;
twidth = event->xconfigure.width;
tw_lines = tw_new;
if (tw_lines>color_lines) tw_lines=color_lines;
if (act_offset+tw_lines>color_lines)
act_offset = color_lines-tw_lines;
redraw_tw( 0, tw_lines+1 );
XSync(display, 0);
while( XCheckWindowEvent( display, tw, ExposureMask, &help ) );
break;
}
case KeyPress:
{ char sign;
KeySym keysym;
XLookupString(&event->xkey, &sign, 1, &keysym, NULL);
if (sign=='q') exit(0);
break;
}
case Expose:
{ XEvent help;
int first, first2;
int last, last2;
first = event->xexpose.y/char_height;
last = (event->xexpose.y + event->xexpose.height)/char_height+1;
while( XCheckWindowEvent( display, tw, ExposureMask, &help ) )
{ first2 = help.xexpose.y/char_height;
last2 = (help.xexpose.y + help.xexpose.height)/char_height+1;
if (first2 < first) first = first2;
if (last2 > last) last = last2;
}
redraw_tw( first, last );
break;
}
case ButtonPress:
{ int i;
int old_act;
int offset_delta;
i= (event->xbutton.y / char_height)-1;
/* has the header or footer of the textwindow been selected ? */
if (i<0)
{ if (event->xbutton.button==Button3)
{ write_quest(0);
return;
}
else if (act_offset)
{ offset_delta=(event->xbutton.button==Button1)?1:10;
if (act_offset-offset_delta<0)
offset_delta = act_offset;
act_offset -= offset_delta;
XCopyArea( display, tw, tw, gc,
0, char_height, twidth, (tw_lines-offset_delta)*char_height,
0, (offset_delta+1)*char_height );
redraw_tw( 1, offset_delta+1 );
}
else XBell(display, 10);
break;
}
if (i>=tw_lines)
{ if (event->xbutton.button==Button3)
{ write_quest(1);
return;
}
else if (act_offset+tw_lines<color_lines)
{ offset_delta=(event->xbutton.button==Button1)?1:10;
if (act_offset+offset_delta>color_lines-tw_lines)
offset_delta = color_lines-act_offset-tw_lines;
act_offset += offset_delta;
XCopyArea( display, tw, tw, gc,
0, (offset_delta+1)*char_height,
twidth, (tw_lines-offset_delta)*char_height,
0, char_height );
redraw_tw( tw_lines-offset_delta+1, tw_lines );
}
else XBell(display, 10);
break;
}
i+=act_offset;
/* action on a textline depending on the button */
switch(event->xbutton.button)
{
case Button2:
old_act = act_line;
act_line = -1;
draw_string( old_act );
new_assoc( i );
act_line=i;
draw_string( act_line );
return;
case Button1:
old_act = act_line;
act_line = i;
draw_string( old_act );
draw_string( act_line );
break;
case Button3:
old_act = act_line;
act_line = i;
draw_string( old_act );
show_text( act_line );
draw_string( act_line );
break;
}
} /* end case ButtonPress */
} /* end switch(type) */
reset_messages();
}
/*----------------------------------------------------------------------------*/
Window create_textwindow( fname )
char *fname;
{
Window tw;
XSizeHints hints;
XWMHints normal_hints;
XClassHint class_hints;
static char *iname = "TextView";
char wname[MAXPATHLEN+10];
char *name_ptr;
/* parsing the geometry */
hints.flags = PSize | PMaxSize | PMinSize | PResizeInc;
if (color_lines<4) hints.min_height = (color_lines+2) * (char_height);
else hints.min_height = 7 * (char_height);
hints.min_width = 20 * char_width;
if (color_lines>50) tw_lines = 25;
else tw_lines = color_lines;
hints.width = longest_colored+ 6 * char_width;
hints.height= (tw_lines+2) * (char_height);
act_offset = 0;
hints.max_height = (color_lines+2) * (char_height);
hints.max_width = 2*(longest_colored);
hints.width_inc = char_width;
hints.height_inc = char_height;
twidth = hints.width;
/* names */
name_ptr = rindex( fname, '/' );
if (name_ptr) fname = name_ptr+1;
sprintf( wname, "TextView '%s'", fname );
name_ptr = wname;
tw = XCreateSimpleWindow( display, RootWindowOfScreen(screen),
0, 0, hints.width, hints.height, 3, grey, black );
/* class-hints */
class_hints.res_name = "xcol";
class_hints.res_class= "XCol";
/* normal-hint */
normal_hints.flags = StateHint | WindowGroupHint;
normal_hints.initial_state = NormalState;
normal_hints.window_group = mw;
#ifdef XTextProperty
{
XTextProperty window_name, icon_name;
XStringListToTextProperty( &name_ptr, 1, &window_name );
XStringListToTextProperty( &iname, 1, &icon_name );
XSetWMProperties( display, tw, &window_name, &icon_name, (char **)0, 0,
&hints, &normal_hints, &class_hints );
XFree( (char *)window_name.value );
XFree( (char *)icon_name.value );
}
#else
XSetStandardProperties( display, tw, name_ptr, iname, None, (char **)0, 0, &hints );
XSetClassHint( display, tw, &class_hints );
#endif
XSelectInput( display, tw,
ExposureMask | ButtonPressMask | StructureNotifyMask |
KeyPressMask | EnterWindowMask | LeaveWindowMask );
XDefineCursor( display, tw, tw_cursor );
XMapRaised( display, tw );
return( tw );
}
/********************************************************************************
* Subwindow-Functions *
********************************************************************************/
void destroy_subwindow( i )
int i;
/* destroys the tiny subwindow and its associated colors */
{
ColorDef *act;
act = color[i];
while( act->associated )
{ act = act->associated;
unload_color( act );
}
XDestroyWindow( display, subw );
}
void create_subwindow( i )
int i;
/* creates, maps and draws a tiny information-window for the given color */
{
XSetWindowAttributes attrib;
int x, y;
int subs;
int j;
ColorDef *shades[MAX_COLS];
ColorDef *act;
int bord=6;
/* what associated color should be shown ? */
act = color[i];
subs = 0;
shades[subs++] = act;
while( act->associated )
{ act = act->associated;
shades[subs++]=act;
}
if (subs>gran+1)
{ for (j=0;j<(gran);j++)
{ shades[j+1]= shades[1+(j*(subs-2))/(gran-1)];
}
subs=gran+1;
}
for (j=0;j<subs;j++) load_color( shades[j] );
/* compute size */
sdx = XTextWidth( finfo, color[i]->name, strlen(color[i]->name) )+4;
sdy = finfo->ascent + finfo->descent+2;
if (subs>1)
{ int palette_width=8;
sdy += 14;
if (sdx<(subs*palette_width))
{ do
{ sdx=subs*palette_width;
palette_width--;
}
while( (sdx+2*bord>dx)&&(palette_width>3) );
}
subcols = subs;
}
else
{ subcols = subs = 0;
}
/* compute position */
if (color[i]->x < dx/2) x = color[i]->x + BO;
else x = color[i]->x -BO -(2*bord) -sdx;
if (x+sdx+(2*bord)>dx) x = dx - sdx - (2*bord);
if (x<0) x=0;
if (color[i]->y < dy/2) y = color[i]->y + BO;
else y = color[i]->y -BO -(2*bord) -sdy;
/* create, map and draw */
subw = XCreateSimpleWindow( display, mw, x, y, sdx, sdy, bord, color[i]->pixel, black );
attrib.save_under = True;
XChangeWindowAttributes( display, subw, CWSaveUnder, &attrib );
XMapRaised( display, subw );
XSetFont( display, gc, finfo->fid );
XSetForeground( display, gc, white );
XSetBackground( display, gc, black );
XDrawImageString( display, subw, gc,
(sdx-XTextWidth( finfo, color[i]->name, strlen(color[i]->name)))>>1,
finfo->ascent, color[i]->name, strlen( color[i]->name ) );
if (subs)
{ for (j=0;j<subs;j++)
{
XSetForeground( display, gc, shades[j]->pixel );
XFillRectangle( display, subw, gc, 2+j*(sdx-2)/subs, sdy-12, (j+1)*(sdx-2)/subs-(2+j*(sdx-2)/subs), 10);
}
}
}
/*----------------------------------------------------------------------------*/
/* LittleBox draws 2 rectangles around a color-field of the subwindow */
#define LittleBox(col) \
XDrawRectangle( display, subw, gc, \
1+col*(sdx-2)/subcols, sdy-13, \
(col+1)*(sdx-2)/subcols-(2+col*(sdx-2)/subcols)+1, 11); \
XDrawRectangle( display, subw, gc, \
1+col*(sdx-2)/subcols-1, sdy-13-1, \
(col+1)*(sdx-2)/subcols-(2+col*(sdx-2)/subcols)+1+2, 11+2)
void sub_select( line_index, i, help_color )
int line_index, i, help_color;
/* select a sub-color */
{
ColorDef *shades[MAX_COLS];
ColorDef *act;
int subs, j;
XEvent event;
int col_index; /* current index to the shades-field */
int old_col_index; /* last index to the shades-field */
/* collect shades (shades[0] is used for the old value of the color) */
if (help_color) shades[0] = line[line_index].help;
else shades[0] = line[line_index].color;
act = color[i];
subs = 1;
shades[subs++] = act;
while( act->associated )
{ act = act->associated;
shades[subs++]=act;
}
if (subs>gran+1)
{ for (j=0;j<(gran);j++)
{ shades[j+2]= shades[2+(j*(subs-3))/(gran-1)];
}
}
/* first exchange of the color */
col_index = 0;
if (help_color)
{ exchange( &line[line_index].help, shades[col_index+1] );
draw_string( line_index );
}
else change_color( line_index, shades[col_index+1] );
/* if there are no associated colors, the selection is done */
if (subs<=2) return;
col_index=0;
old_col_index=0;
XSetForeground( display, gc, white );
LittleBox( col_index );
/* warp the pointer to the main color of the subwindow */
XWarpPointer( display, None, subw, 0, 0, 0, 0, ((sdx/subcols)>>1)+2, sdy-7 );
XGrabPointer(display, subw, False,
ButtonPressMask | ButtonReleaseMask | PointerMotionMask,
GrabModeAsync, GrabModeAsync,
subw, subsel_cursor, CurrentTime );
do
{ XWindowEvent( display, subw, ButtonPressMask | ButtonReleaseMask | PointerMotionMask, &event );
if (event.xany.type!=ButtonRelease)
{
if (event.xany.type==MotionNotify)
{ while(XCheckMaskEvent(display, PointerMotionMask, &event));
col_index = (event.xmotion.x-1)*subcols/(sdx-2);
if (col_index<0) col_index=0;
if (col_index>=subcols) col_index=subcols-1;
if ((event.xmotion.y<sdy-13)||(event.xmotion.y>sdy-2))
{ col_index = -1;
}
}
else col_index = -1; /* another ButtonPress == abort */
if (old_col_index!=col_index)
{ if (old_col_index>=0)
{ XSetForeground( display, gc, black );
LittleBox( old_col_index );
}
if (col_index>=0)
{ XSetForeground( display, gc, white );
LittleBox( col_index );
}
old_col_index = col_index;
if (help_color)
{ exchange( &line[line_index].help, shades[col_index+1] );
draw_string( line_index );
}
else change_color( line_index, shades[col_index+1] );
}
}
}
while( event.xany.type==MotionNotify );
XUngrabPointer(display, CurrentTime);
XSetForeground( display, gc, black );
LittleBox( old_col_index );
/* warp pointer back to its former position */
XWarpPointer( display, None, mw, 0, 0, 0, 0, shades[1]->x, shades[1]->y );
XSync(display, 1);
}
/********************************************************************************
* main-window-functions *
********************************************************************************/
int act_color( x, y )
int x, y;
/* queries the next color in range of the mouse-pointer */
{
int i;
int min_dist;
int min_i = 0;
int dx1, dy1;
min_dist = dy*dy+dx*dx;
for (i=0;i<color_number;i++)
{ dx1 = abs(color[i]->x-x);
dy1 = abs(color[i]->y-y);
if (dx1*dx1+dy1*dy1<min_dist)
{ min_dist = dx1*dx1+dy1*dy1;
min_i = i;
}
}
if (min_dist<(BO)*(BO))
return(min_i);
else
return(-1);
}
/*----------------------------------------------------------------------------*/
#define XPos(r, g, b) ( (BO>>1)+2+ \
( (reverse) ? (85+(255-r)-((255-b)/3)) \
: (85+r-((b)/3)) \
) * (dx-BO-4)/341 \
)
#define YPos(r, g, b) ( (BO>>1)+2+ \
( (reverse) ? (g+((255-b)>>1)) \
: ((255-g)+(b>>1)) \
) * (dy-BO-4)/384 \
)
void redraw_window()
/* redraws the cube and the color-boxes in the main window */
{
int i, j, op;
int ex[8], ey[8];
int s_dummy;
unsigned int u_dummy;
Window root;
XGetGeometry( display, mw, &root, &s_dummy, &s_dummy, &dx, &dy, &u_dummy, &u_dummy );
if (BO_def)
BO = BO_def;
else
{ BO = (dx/50);
if ((dy/50)>BO) BO=(dy/50);
}
XClearWindow( display, mw );
/* draw the cube */
XSetForeground( display, gc, white );
for (i=0;i<8;i++)
{ ex[i] = XPos( ((i&1)?255:0), ((i&2)?255:0), ((i&4)?255:0) );
ey[i] = YPos( ((i&1)?255:0), ((i&2)?255:0), ((i&4)?255:0) );
}
for (i=0;i<8;i++)
{ for (j=0;j<3;j++)
{ op = i^(1<<j);
if (op<i)
XDrawLine(display, mw, gc, ex[i], ey[i], ex[op], ey[op]);
}
}
/* draw the boxes */
for (i=0;i<color_number;i++)
{
color[i]->x = XPos(color[i]->r, color[i]->g, color[i]->b);
color[i]->y = YPos(color[i]->r, color[i]->g, color[i]->b);
XSetForeground( display, gc, color[i]->pixel );
XFillRectangle( display, mw, gc,
color[i]->x-(BO>>1), color[i]->y-(BO>>1), BO, BO);
}
XFlush(display);
}
/*----------------------------------------------------------------------------*/
mw_event( event )
XEvent *event;
{
static int new_i;
static int old_i= -1;
switch( event->xany.type )
{
case Expose:
while(XCheckWindowEvent( display, mw, ExposureMask, event ));
if (event->xexpose.count==0) redraw_window();
break;
case MotionNotify:
while( XCheckWindowEvent( display, mw, PointerMotionMask, event ) );
new_i = act_color( event->xmotion.x, event->xmotion.y );
if ((old_i!=new_i)&&(old_i>=0))
{ destroy_subwindow(old_i);
old_i = -1;
}
if (old_i!=new_i)
{ create_subwindow(new_i);
old_i = new_i;
}
break;
case EnterNotify:
update_map();
break;
case LeaveNotify:
if (old_i>=0)
{ destroy_subwindow(old_i);
old_i = -1;
}
break;
case ButtonPress:
switch (event->xbutton.button)
{
case Button1:
{ if ((tw)&&(old_i>=0))
{ sub_select( act_line, old_i, 0 );
}
else
{ if (old_i>=0)
{ sub_select( 0, old_i, 0 );
XStoreBytes( display, line[0].color->name, strlen(line[0].color->name) );
XBell(display, 10);
}
}
break; /* end switch(button) */
}
case Button2:
{ if ((tw)&&(act_line>=0)&&(old_i>=0))
{ if (line[act_line].assoc<0)
sub_select( act_line, old_i, 1 );
else sub_select( line[act_line].assoc, old_i, 0 );
}
break; /* end switch(button) */
}
case Button3:
{ ColorDef *act;
char *short_name;
char *name;
char name_copy[30];
int name_length;
name = short_name = NULL;
if ((tw)&&(act_line>=0))
{ short_name = cut_digits( line[act_line].color->name );
}
else
{ if (tw==(Window)0)
{ name = XFetchBytes( display, &name_length );
if (name_length<28)
{ strncpy( name_copy, name, name_length );
name_copy[ name_length ] = '\0';
short_name = cut_digits( name );
}
XFree( name );
}
}
if (short_name)
{ act = find_color( short_name );
if (act)
XWarpPointer( display, None, mw, 0, 0, 0, 0,
XPos( act->r, act->g, act->b ), YPos( act->r, act->g, act->b ) );
}
if (name) XFree(name);
break; /* end switch(button) */
}