/* Side color support for the Mac interface to Xconq.
   Copyright (C) 1997, 1998 Hans Ronne.

Xconq is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.  See the file COPYING.  */

#include "conq.h"
#include "kpublic.h"
#include "macconq.h"

#ifdef NEW_HEADERS
#include <ColorPicker.h>
#else
#include <Picker.h>
#endif

/* --- FUNCTIONS PROTOTYPES -------------------------------------------------*/

extern ImageFamily *get_generic_images PARAMS ((Side *side, char *name));
extern CIconHandle mac_create_cicn(Image *img);
extern void mac_init_cicn(Image *img);
static void build_colors_popup_menu(MenuHandle popMenu);
static void append_color_callback(ImageFamily *imf, int loadnow);
static RGBColor get_color(char *name);					/* Get new color by name */
static RGBColor pick_new_color(RGBColor inColor, char *name); 	/* Use color picker to get a new color */

/* --- EXTERN DEFINED IN MACDRAW.C  -------------------------------------------*/

extern Image **best_terrain_images;

/* --- DEFAULTS FOR NEW MAP PREFERENCES ---------------------------------------*/

int default_sidecolors = TRUE;		/* Use side colors in maps & lists */
int default_iconmasks = TRUE;		/* Use masks for icons  */
int default_boxmasks = TRUE;		/* Use masks for grouping boxes */
int default_textmasks = FALSE;		/* Use masks for text */
int default_featureborders = TRUE;	/* Draw feature (province) borders */
int default_featurenames = TRUE;		/* Draw feature (province) names */
int default_simple_borders = TRUE;	/* Do not draw borders to water or to empty lands */
int default_shorelines = TRUE;		/* Draw shorelines in 3D relief */

// --- USER CONTROL OF EMBLEMS -----------------------------------------

int default_draw_emblems = TRUE;	/* Draw unit emblems in maps and lists. */

// ------------------------------------------------------------------

int default_draw_topline = TRUE;		/* Draw top line boxes in maps */
int default_draw_topunit = TRUE;		/* Draw unit info boxes in maps */
int default_drawothermaps = TRUE;	/* Draw other maps as boxes */
int default_erase_names = FALSE;		/* Draw extra rows to erase name of moving unit */
int default_max_bufx = 600;		/* Horizontal scrolling buffers in offscreen graphics */
int default_max_bufy = 400;		/* Vertical scrolling buffers in offscreen graphics */
int default_optimize_fonts = TRUE;	/* Use optimized font sizes in map content */
int default_power = 5;				/* Default power of new map */

/* --- VARIOUS PREFERENCES -----------------------------------------------------*/

int use_colornames = TRUE;			/* Save and read side colors as colorschemes */
int use_RGB_values = FALSE;		/* Save and read RGB colors in XCol resource */
int show_instructions = TRUE;		/* Show instructions window at start */
int fullsize_map = TRUE;			/* Show full size map window at start */
int unified_cicns = TRUE;			/* Use BitMap as mask for the PixMap */

/* --- COLOR SCHEME DEFAULTS ---------------------------------------------------*/

int default_main_icon_color = 1;		/* Default number (1-3) of sideColor used for icons */ 
int default_half_icon_color = 2;		/* Default number (1-3) of sideColor used for right half of icons */
int default_icon_mask_color = 3;		/* Default number (1-3) of sideColor used for icon masks */
int default_split_icon = TRUE;		/* Default use different colors for right and left halves of icons */
		
/* --- COLORS, COLOR SCHEMES AND COLOR NAMES --------------------------------------*/

RGBColor *featColor;				/* Feature colors by RGB value */
RGBColor *sideColor;				/* sideColor[0-15][1-3] are defined by default color schemes */
							/* sideColor[][0] is not defined, and available for future use */

char **current_colorscheme;		/* Current color schemes by names (red,pink,blue) */
							/* Unlike side->colorscheme defined also for null sides */	

char **default_featColorName;		/* Default feature colors by name (black etc) */
char **default_colorscheme;		/* Default color schemes (red,pink,brown) etc */

char **featColorItemName;			/* Name of item for which featColor is set (Shorelines etc) */
char **featColorName;			/* Name of feature color values (red, green etc) */
char **sideColorName;			/* Name of side color values (red, green etc) */

int *main_icon_color;				/* Number (1-3) of sideColor used for icons */ 
int *half_icon_color;				/* Number (1-3) of sideColor used for right half of icons */
int *icon_mask_color;				/* Number (1-3) of sideColor used for icon masks */
int *split_icon;					/* Use two colors for left and right halves of icons if TRUE */

/* --- FUNCTIONS FOR BUILDING AND HANDLING COLORS AND COLOR SCHEMES ---------------------*/

void 
set_default_colors(void)			/* Default colors used in absence of saved preferences */
{
	int i;

	featColor = (RGBColor *) xmalloc((FEATURES+1) * sizeof(RGBColor));
	featColorItemName = (char **) xmalloc((FEATURES+1) * sizeof(char *));
	featColorName = (char **) xmalloc((FEATURES+1) * sizeof(char *));
	default_featColorName = (char **) xmalloc((FEATURES+1) * sizeof(char *));
	sideColor = (RGBColor *) xmalloc((MAXSIDES+1) * 4 * sizeof(RGBColor));
	sideColorName = (char **) xmalloc((MAXSIDES+1) * 4 * sizeof(char *));
	current_colorscheme = (char **) xmalloc((MAXSIDES+1) * sizeof(char *)); 
	default_colorscheme = (char **) xmalloc((MAXSIDES+1) * sizeof(char *));
	main_icon_color = (int *) xmalloc((MAXSIDES+1) * sizeof(int));
	half_icon_color = (int *) xmalloc((MAXSIDES+1) * sizeof(int));
	icon_mask_color = (int *) xmalloc((MAXSIDES+1) * sizeof(int));
	split_icon = (int *) xmalloc((MAXSIDES+1) * sizeof(int));

	default_colorscheme[0] = "black,black,white";
	default_colorscheme[1] = "blue,blue,pale-turquoise";
	default_colorscheme[2] = "red,red,yellow";
	default_colorscheme[3] = "deep-pink,deep-pink,spring-green";
	default_colorscheme[4] = "straw,straw,saddle-brown";
	default_colorscheme[5] = "red,blue,cyan";
	default_colorscheme[6] = "white,violet,black";
	default_colorscheme[7] = "cyan,cyan,blue";
	default_colorscheme[8] = "yellow,yellow,red";
	default_colorscheme[9] = "green,magenta,medium-blue";
	default_colorscheme[10] = "purple,purple,cyan";
	default_colorscheme[11] = "navy-blue,deep-pink,spring-green";
	default_colorscheme[12] = "lawn-green,lawn-green,deep-pink";
	default_colorscheme[13] = "light-pink,spring-green,midnight-blue";
	default_colorscheme[14] = "dark-green,purple,aquamarine";
	default_colorscheme[15] = "cyan,green-yellow,navy-blue";
	default_featColorName[0] = "dark-orange";		/* Window background outside map. */
	default_featColorName[1] = "black";			/* Fore color */	
	default_featColorName[2] = "pale-turquoise";	/* Mask color */
	default_featColorName[3] = "midnight-blue";	/* Text color */
	default_featColorName[4] = g_grid_color();
	default_featColorName[5] = g_unseen_color();
	default_featColorName[6] = g_shoreline_color();
	default_featColorName[7] = "deep-pink";		/* Feature text and borders */
	default_featColorName[8] = g_frontline_color();
	default_featColorName[9] = g_meridian_color();
	default_featColorName[10] = g_contour_color();
	featColorItemName[0] = "Background";
	featColorItemName[1] = "Fore color";	/* These names are used in the Colors menu */
	featColorItemName[2] = "Mask color";
	featColorItemName[3] = "Text color";
	featColorItemName[4] = "Grid color";
	featColorItemName[5] = "Unseen color";
	featColorItemName[6] = "Shorelines";
	featColorItemName[7] = "Features";
	featColorItemName[8] = "Frontlines";
	featColorItemName[9] = "Meridians";
	featColorItemName[10] = "Contours";
}

void
set_default_side_colors(int e)
{
	/* First reset current colors to default colors */
	side_n(e)->colorscheme = default_colorscheme[e];
	/* Change the current colors */
	set_side_colors(e);
	/* Copy the result back to default colors */
	default_colorscheme[e] = side_n(e)->colorscheme;
	force_overall_update();
	save_preferences();
}

void
set_default_feature_color(int e)
{
	/* First reset current colors to default colors */
	featColorName[e] = default_featColorName[e];
	/* Change the current colors */
	set_feature_color(e);
	/* Copy the result back to default colors */
	default_featColorName[e] = featColorName[e];
	force_overall_update();
	save_preferences();
}

/* Load side colors and feature colors from defaults */

void
init_side_colors(void)
{
	int i;
	char cstring[96];

	for (i = 0; i <= MAXSIDES; i++) {

		/* Use of XCol colors overrides any colorschemes */
		if (!use_RGB_values) {

			/* Set side color names initially to "undefined" */
			set_sideColorName(i, 1, "undefined");
			set_sideColorName(i, 2, "undefined");
			set_sideColorName(i, 3, "undefined");
			/* Use schemes defined in game file if present or else default schemes */
			if (side_n(i) && side_n(i)->colorscheme)
			  current_colorscheme[i] = copy_string(side_n(i)->colorscheme);
			else
			  current_colorscheme[i] = copy_string(default_colorscheme[i]);
				
			dissect_colorscheme(i);
		}

		/* Load color use parameters from their defaults values */
		main_icon_color[i] 	= default_main_icon_color;
		half_icon_color[i] 	= default_half_icon_color;
		icon_mask_color[i] 	= default_icon_mask_color;
		split_icon[i]		= default_split_icon;

		/* Then zero color use parameters if the corresponding color is undefined */
		if (strcmp(get_sideColorName(i, main_icon_color[i]), "undefined") == 0) {
			main_icon_color[i] = 0;
		}
		if (strcmp(get_sideColorName(i, half_icon_color[i]), "undefined") == 0) {
			half_icon_color[i] = 0;
			split_icon[i] = 0;
		}
		if (strcmp(get_sideColorName(i, icon_mask_color[i]), "undefined") == 0) {
			icon_mask_color[i] = 0;
		}
	}
	for (i = 0; i <= FEATURES; i++) {
		/* Load feature colors from their defaults  */
		featColorName[i] = default_featColorName[i];
		featColor[i] = get_color(featColorName[i]);
	}
	/* This is now checked once and for all, instead of every time an area background is drawn. */
	if (strcmp(gridcolor_name, unseencolor_name) == 0
		|| g_terrain_seen() || (dside)->see_all)
			grid_matches_unseen = TRUE;

	blackcolor.red = blackcolor.green = blackcolor.blue = 0;
}

/* This function is based on init_emblem from the X11 interface. */
/* It also tests each name for validity and stores it in an array. */

void
dissect_colorscheme(int sidenum)
{
	char		*colorscheme = current_colorscheme[sidenum];
	char	 	*s, *c;
	char		cbuf[BUFSIZE];
	int 		i, button;
	Str255	pname;

	if (!empty_string(colorscheme)) {
		/* Take spec apart and iterate for multiple colors */
		for (s = colorscheme, c = cbuf, i = 1; i <= 3; ++s) {
			/* Test for end of name or end of scheme */
			if (*s == ',' || *s == '\0') {
				/* Terminate the name string */
				*c = '\0';
				c = cbuf;
				/* First check that the color name is valid. If not, substitute "undefined" */
				if (!valid_imf_name(cbuf)) {
					c2p(cbuf, pname);
					ParamText("\pSorry, Ò", pname, 
							 "\pÓ is not a valid color name. Substituting ÒundefinedÓ.", "\p");
					button = Alert(aOneButtonAlert, NULL);
					strcpy(cbuf, "undefined");
				}
				/* Also replace empty strings with "undefined" but do it silently */
				if (strcmp(cbuf, "") == 0)
				  strcpy(cbuf, "undefined");

				/* Get the color and store the color name in the name array */
				set_sideColorName(sidenum, i, copy_string(cbuf));
				set_sideColor(sidenum, i++, get_color(cbuf)); 

			/* Add one more character */
			} else *c++ = *s;
			/* Test for end of colorscheme */
			if (*s == '\0')
			  break;
		}
	}
}

/* Get a ppat color by its name. Function that call get_color should first check that the name is valid */ 

RGBColor
get_color(char* name)
{
	ImageFamily	*imf;
	Image 		*img;
	MacImage		*macimg;
	PixMapHandle 	pmhandle;
	CTabHandle 	ctabhandle;
	ColorSpec 		*ctdata;

	/* Return black if name is "undefined" */	
	if (strcmp(name, "undefined") == 0)
	     return blackcolor;

	/* Find (or create) the image family. */
	imf = get_generic_images(dside, name);

	/* Needed only in the presence of mac-lib. */ 
    	record_imf_get(imf);			

	/* Get the 1x1 image (color). */
	img = get_img(imf, 1, 1, 0);

	/* Needed only in the presence of mac-lib. */ 
	mac_interp_imf(imf, img, 0);	

	/* Get the resulting mac image. */
	macimg = (MacImage *) img->hook;

	/* Return black if it has no colrpat. */
	if (!macimg->colrpat) 
	      return blackcolor;

	/* Copy colrpat data into macimg->color. */
	pmhandle = (*macimg->colrpat)->patMap;
	ctabhandle = (*pmhandle)->pmTable;
	ctdata = (ColorSpec *) &((*ctabhandle)->ctTable);
	macimg->color.red   	= ctdata[0].rgb.red;
	macimg->color.green 	= ctdata[0].rgb.green;
	macimg->color.blue  	= ctdata[0].rgb.blue;
	macimg->colordefined 	= TRUE;
	
	/* Return the resulting color. */
	return macimg->color;
}	

/* Given an initial color and a name, allow the user to pick a color
   for that name. */

RGBColor  
pick_new_color(RGBColor inColor, char* name) 
{
	RGBColor outColor = inColor;
	Point where = {0};
	char prompt[64];
	Str255 pprompt;
	short button;

	/* Return if the color name is "undefined". */
	if (strcmp(name, "undefined") == 0)
	  return;

	/* Build the prompt. */
	strcpy(prompt, "Define Ò");
	strcat(prompt, name);
	strcat(prompt, "Ó:");
	c2p(prompt, pprompt);

	/* Open the color picker. */
	button = GetColor(where, pprompt, &inColor, &outColor);
	if (button == 1)
	  return outColor;
	else
	  return inColor;
}

/* --- FUNCTIONS FOR READING AND WRITING XCOL RGB DATA ------------------------------*/

/* (should generify all this) */

void
read_xcol(void)
{
	Handle XCol;	/* Special resource used to save RGB colors in prefs file */
	int i, j;		/* Index for loading colors from XCol resource */
	int n = 0;		/* XCol resource counter */

	/* First load the side colors */
	for (i = 0; i <= MAXSIDES; i++) {
		for (j = 1; j <= 3; j++) {

			/* Convert XCol resource data into RGB colors */
			XCol = GetResource('XCol', 128 + n);
			if (XCol != nil) {
			
				sideColor[4 * i + j].red	= *(*XCol + 1); 
				sideColor[4 * i + j].green	= *(*XCol + 3);
				sideColor[4 * i + j].blue	= *(*XCol + 5) ;
				
				sideColor[4 * i + j].red	&= 0x00FF;	/* Necessary to avoid color drift */
				sideColor[4 * i + j].green	&= 0x00FF;	/* Dont ask me why */
				sideColor[4 * i + j].blue	&= 0x00FF;

				sideColor[4 * i + j].red	+= (*(*XCol + 0) << 8);
				sideColor[4 * i + j].green	+= (*(*XCol + 2) << 8);
				sideColor[4 * i + j].blue	+= (*(*XCol + 4) << 8);
				
				n += 1;
			}
		}
	}			

	/* Then load the feature colors */
	for (i = 1; i <= FEATURES; i++) {

		/* Convert XCol resource data into RGB colors */
		XCol = GetResource('XCol', 128 + n);
		if (XCol != nil) {
		
			featColor[i].red   = *(*XCol + 1); 
			featColor[i].green = *(*XCol + 3);
			featColor[i].blue  = *(*XCol + 5) ;
			
			featColor[i].red   &= 0x00FF;	/* Necessary to avoid color drift */
			featColor[i].green &= 0x00FF;	/* Dont ask me why */
			featColor[i].blue  &= 0x00FF;

			featColor[i].red   += (*(*XCol + 0) << 8);
			featColor[i].green += (*(*XCol + 2) << 8);
			featColor[i].blue  += (*(*XCol + 4) << 8);

			n += 1;
		}
	}			
}

void
write_xcol(void)
{
	char cnumber[2], cstring[36];
	Str255 pnumber, pstring;			/* Used to write XCol names in pref file */
	Handle XCol, oldXCol;				/* Special resource used to store RGB colors */
	int i, j;							/* Index for loading XCols into sideColor[] */
	int n = 0;							/* Resource counter */

	/* First write the side colors */
	for (i = 0; i <= MAXSIDES; i++) {
		for (j = 1; j <= 3; j++) {

			/* Convert RGB colors into XCol resource data */
			oldXCol = GetResource('XCol', 128 + n);
			if (oldXCol != nil) RmveResource(oldXCol);
			XCol = NewHandle(6);

			*(*XCol + 1) = sideColor[4 * i + j].red;	
			*(*XCol + 3) = sideColor[4 * i + j].green;	
			*(*XCol + 5) = sideColor[4 * i + j].blue;

			*(*XCol + 0) = sideColor[4 * i + j].red	>> 8;
			*(*XCol + 2) = sideColor[4 * i + j].green	>> 8;
			*(*XCol + 4) = sideColor[4 * i + j].blue	>> 8;

			strcpy(cstring, "Side ");
			NumToString(i, pnumber);
			p2c(pnumber, cnumber);
			strcat(cstring, cnumber);
			strcat(cstring, " color ");
			NumToString(j, pnumber);
			p2c(pnumber, cnumber);
			strcat(cstring, cnumber);
			c2p(cstring, pstring);
			AddResource(XCol, 'XCol', 128 + n, pstring);
			
			n += 1;					
		}
	}

	/* Then write the feature colors */
	for (i = 1; i <= FEATURES; i++) {

		/* Convert RGB colors into XCol resource data */
		oldXCol = GetResource('XCol', 128 + n);
		if (oldXCol != nil) RmveResource(oldXCol);
		XCol = NewHandle(6);

		*(*XCol + 1) = featColor[i].red;	
		*(*XCol + 3) = featColor[i].green;	
		*(*XCol + 5) = featColor[i].blue;

		*(*XCol + 0) = featColor[i].red >> 8;
		*(*XCol + 2) = featColor[i].green >> 8;
		*(*XCol + 4) = featColor[i].blue >> 8;

		c2p(featColorItemName[i], pstring);
		AddResource(XCol, 'XCol', 128 + n, pstring);

		n += 1;					
	}
}

/* --- COLOR MANAGING DIALOGS --------------------------------------------------*/

/* The following three dialogs are used by the Colors menu and also by Preferences : Colorschemes */

/* This monster dialog does just about anything that has to do with side colors. A checkbox at the top enables or 
   disables the use of split icons (two different colors for the left and right half). Three popup menus makes it
   possible to chose three different colors from the available ppat colors in the Images file. The name of the new
   color can also be entered in a text field, followed by a Return. The editflag parameter is used to ensure that
   such a Return is not interpreted as a hit of the OK button. The actual RGB values associated with a given color 
   name can be changed by clicking the color field, where the color itself is displayed. A second row of popup
   menus makes it possible to chose how each color should be used. The half icon color alternative is disabled if 
   the split icon checkbox is unchecked, and the whole menu is disabled if the color is undefined. If a color use is
   picked which already was assigned to another color, that color is switched to "Not in use". At the bottom of the
   dialog box, five sample icons are plotted in real time to illustrate the given choice of colors. */

void
set_side_colors(int e)
{
	char cname[32], tmpName1[32], tmpName2[32], tmpName3[32], tmpScheme[96];
	short tmpUse[4], tmpSplit, editflag, ditem, mitem, button, found, done, i, n;  
	RGBColor tmpColor[4], tmpMain, tmpHalf, tmpMask, tmpBack;
	Handle itemhandle, ppathandle;  
	MenuHandle popMenu, useMenu;
	Rect srcrect, itemrect;
	CIconHandle cicnhandle;
	MacImage *macuimg;
	BitMap bm, mm;		
	GrafPtr oldport;
	Image *uimg;
	Str255 pname;
	DialogPtr win;

	/* Then check for color support */
	if (!hasColorQD) {
		ParamText("\pSorry, your mac does not support colors.", "\p", "\p", "\p");
		button = Alert(aOneButtonAlert, NULL);
		return;
	} 

	/* Get dialog window and popup menus */
	win = GetNewDialog(dSideColor, NULL, (DialogPtr) -1);
	popMenu = GetMenu(mSideColorPopup);
	useMenu = GetMenu(mSideColorUse);

	/* Save the Dialog background color if not white */
	tmpBack = ((CGrafPtr) win)->rgbBkColor;

	/* Load current side color names into temp names */
	strcpy(tmpName1, get_sideColorName(e, 1));
	strcpy(tmpName2, get_sideColorName(e, 2));
	strcpy(tmpName3, get_sideColorName(e, 3));
	
	/* Load current side colors into temp colors */
	tmpColor[1] = get_sideColor(e, 1);
	tmpColor[2] = get_sideColor(e, 2);
	tmpColor[3] = get_sideColor(e, 3);

	/* Also load side colors into tmpMain, tmpHalf & tmpMask */
	tmpMain = get_sideColor(e, main_icon_color[e]);
	tmpHalf = get_sideColor(e, half_icon_color[e]);
	tmpMask = get_sideColor(e, icon_mask_color[e]);

	/* Load color use info into tmpUse[i] */
	for (i = 1; i <= 3; i++) {
		if (main_icon_color[e] == i)
		  tmpUse[i] = miMainIconColor;
		else if (half_icon_color[e] == i)
		  tmpUse[i] = miHalfIconColor;
		else if (icon_mask_color[e] == i)
		  tmpUse[i] = miIconMaskColor;
		else
		  tmpUse[i] = miNotInUse;
	}

	/* Load use of split icons */
	tmpSplit = split_icon[e];

	/* Load temp names into the text fields */
	GetDItem(win, diSideColorName1, NULL, &itemhandle, NULL);
	c2p(tmpName1, pname);
	SetIText(itemhandle, pname);
	GetDItem(win, diSideColorName2, NULL, &itemhandle, NULL);
	c2p(tmpName2, pname);
	SetIText(itemhandle, pname);
	GetDItem(win, diSideColorName3, NULL, &itemhandle, NULL);
	c2p(tmpName3, pname);
	SetIText(itemhandle, pname);

	/* Load all available ppat colors into the popup menu */
	AppendMenu(popMenu, "\pundefined");
	AppendMenu(popMenu, "\p(-");		/* Item separator */

	/* Build the popup menu for new colors. */
	build_colors_popup_menu(popMenu);

	/* Change port and start the main loop */
	GetPort(&oldport);
	SetPort(win);
	done = FALSE;
	editflag = FALSE;
	while (!done) {

		/* Check length of popMenu */
		n = CountMItems(popMenu);

		/* Set popup1 to tmpName1 if found in menu */
		GetDItem(win, diSideColorPopup1, NULL, &itemhandle, NULL);
		SetCtlMax((ControlHandle) itemhandle, n);		/* Important! */
		found = FALSE;
		for (i = 1; i <= n; i++) {
			GetItem(popMenu, i, pname);
			p2c(pname, cname);
			if (strcmp(tmpName1, cname) != 0)
			  continue;
			SetCtlValue((ControlHandle) itemhandle, i);
			found = TRUE;
			break;
		}
		if (!found) {			/* Add tmpName1 to menu if necessary */
			n += 1;
			c2p(tmpName1, pname);
			AppendMenu(popMenu, pname);
			SetCtlMax((ControlHandle) itemhandle, n);	/* Important! */
			SetCtlValue((ControlHandle) itemhandle, n);
		}
		/* Set popup2 to tmpName2 if found in menu */
		GetDItem(win, diSideColorPopup2, NULL, &itemhandle, NULL);
		SetCtlMax((ControlHandle) itemhandle, n);		/* Important! */
		found = FALSE;
		for (i = 1; i <= n; i++) {
			GetItem(popMenu, i, pname);
			p2c(pname, cname);
			if (strcmp(tmpName2, cname) != 0)
			  continue;
			SetCtlValue((ControlHandle) itemhandle, i);
			found = TRUE;
			break;
		}
		if (!found) {			/* Add tmpName2 to menu if necessary */
			n += 1;
			c2p(tmpName2, pname);
			AppendMenu(popMenu, pname);
			SetCtlMax((ControlHandle) itemhandle, n);	/* Important! */
			SetCtlValue((ControlHandle) itemhandle, n);
		}
		/* Set popup3 to tmpName3 if found in menu */
		GetDItem(win, diSideColorPopup3, NULL, &itemhandle, NULL);
		SetCtlMax((ControlHandle) itemhandle, n);		/* Important! */
		found = FALSE;
		for (i = 1; i <= n; i++) {
			GetItem(popMenu, i, pname);
			p2c(pname, cname);
			if (strcmp(tmpName3, cname) != 0)
			  continue;
			SetCtlValue((ControlHandle) itemhandle, i);
			found = TRUE;
			break;
		}
		if (!found) {			/* Add tmpName3 to menu if necessary */
			n += 1;
			c2p(tmpName3, pname);
			AppendMenu(popMenu, pname);
			SetCtlMax((ControlHandle) itemhandle, n);	/* Important! */
			SetCtlValue((ControlHandle) itemhandle, n);
		}

		/* Set undefined colors to default forecolor & maskcolor */
		if (!strcmp(tmpName1, "undefined"))
		  tmpColor[1] = forecolor;
		if (!strcmp(tmpName2, "undefined"))
		  tmpColor[2] = forecolor;
		if (!strcmp(tmpName3, "undefined"))
		  tmpColor[3] = maskcolor;

		/* Set split icons checkbox to correct value */
		GetDItem(win, diSideColorSplit, NULL, &itemhandle, NULL);
		SetCtlValue((ControlHandle) itemhandle, tmpSplit);
		/* Enable or disable the half icon color item in the popup menu */
		if (tmpSplit)
		  EnableItem(useMenu, miHalfIconColor);
		else
		  DisableItem(useMenu, miHalfIconColor);

		/* Set color use popup menus to correct initial values */
		GetDItem(win, diSideColorUse1, NULL, &itemhandle, NULL);
		/* Disable the whole menu if the color is undefined */
		if (!strcmp(tmpName1, "undefined")) {
			tmpUse[1] = miNotInUse;
			HiliteControl((ControlHandle) itemhandle, 255);
		} else
		  HiliteControl((ControlHandle) itemhandle, 0); 
		/* Dont permit half icon color if split icons is unchecked */
		if (!tmpSplit && (tmpUse[1] == miHalfIconColor))
		  tmpUse[1] = miNotInUse;
		SetCtlValue((ControlHandle) itemhandle, tmpUse[1]);

		GetDItem(win, diSideColorUse2, NULL, &itemhandle, NULL);
		/* Disable the whole menu if the color is undefined */
		if (!strcmp(tmpName2, "undefined")) {
			tmpUse[2] = miNotInUse;
			HiliteControl((ControlHandle) itemhandle, 255);
		} else
		  HiliteControl((ControlHandle) itemhandle, 0); 
		/* Dont permit half icon color if split icons is unchecked */
		if (!tmpSplit && (tmpUse[2] == miHalfIconColor))
		  tmpUse[2] = miNotInUse;
		SetCtlValue((ControlHandle) itemhandle, tmpUse[2]);

		GetDItem(win, diSideColorUse3, NULL, &itemhandle, NULL);
		/* Disable the whole menu if the color is undefined */
		if (!strcmp(tmpName3, "undefined")) {
			tmpUse[3] = miNotInUse;
			HiliteControl((ControlHandle) itemhandle, 255);
		} else
		  HiliteControl((ControlHandle) itemhandle, 0); 
		/* Dont permit half icon color if split icons is unchecked */
		if (!tmpSplit && (tmpUse[3] == miHalfIconColor))
		  tmpUse[3] = miNotInUse;
		SetCtlValue((ControlHandle) itemhandle, tmpUse[3]);

		/* Set icon plotting colors */
		tmpMain = forecolor;
		tmpHalf = forecolor;
		tmpMask = maskcolor;
		for (i = 1; i <= 3; i++) {
			if (tmpUse[i] == miMainIconColor)
			  tmpMain = tmpColor[i];
			if (tmpUse[i] == miHalfIconColor)
			  tmpHalf = tmpColor[i];
			if (tmpUse[i] == miIconMaskColor)
			  tmpMask = tmpColor[i];
		}

		/* Open the window now (as late as possible) */
		ShowWindow(win);
		SetCursor(&QD(arrow));
		draw_default_button(win, diSideColorOkButton);
	
		/* Draw background for sample icons */
		GetDItem(win, diSideColorCyan, NULL, NULL, &itemrect);
		ForeColor(cyanColor);
		FillRect(&itemrect, QDPat(black));
		GetDItem(win, diSideColorGreen, NULL, NULL, &itemrect);
		ForeColor(greenColor);
		FillRect(&itemrect, QDPat(black));
		ForeColor(blackColor);
		GetDItem(win, diSideColorFrame, NULL, NULL, &itemrect);
		FrameRect(&itemrect);

		/* Plot 5 sample icons (if available) */
		for (i = 0; i <= 4; i++) {
			/* Skip now if we ran out of unit types */			
			if (i > numutypes - 1) continue;
			/* Get the best unit image from family */
			uimg = best_image(uimages[i], 32, 32);
			macuimg = (MacImage *) uimg->hook;
			/* Get the cicn if it exists */

			/* This is necessary if using imf data instead of lib-mac. Why? */
			/* (the unit cicns do exist when called by draw_unit_image). */
			if (!macuimg->colricon) {
	    			macuimg->colricon = (Handle) mac_create_cicn(uimg);
	    			macuimg->cicn_inited = FALSE;
				mac_init_cicn(uimg);
			}
			
			cicnhandle = (CIconHandle) macuimg->colricon;
			/* Get pixmap, bitmap & maskmap from cicn and set srcrect */
			bm = (*(cicnhandle))->iconBMap;
			mm = (*(cicnhandle))->iconMask;
			SetRect(&srcrect, 0, 0, bm.rowBytes * 8, bm.rowBytes * 8);
			/* Set destination and colors */
			GetDItem(win, diSideColorIcon1 + i, NULL, NULL, &itemrect);
			RGBForeColor(&tmpMain);
			RGBBackColor(&tmpMask);

			/* First plot the MaskMap srcBic using the icon mask color */
			CopyBits(&mm, &win->portBits, &srcrect, &itemrect, srcBic, NULL);
			/* Then plot the BitMap using the main icon color */ 
			CopyBits(&bm, &win->portBits, &srcrect, &itemrect, srcOr, NULL);
			/* Plot right half in half icon color, but only if the latter is defined */
			if (tmpUse[1] == 3 || tmpUse[2] == 3 || tmpUse[3] == 3) {
				RGBForeColor(&tmpHalf);
				srcrect.left = srcrect.right / 2;
				itemrect.left += (itemrect.right - itemrect.left) / 2;
				CopyBits(&bm, &win->portBits, &srcrect, &itemrect, srcOr, NULL);
			}
			/* Restore colors */
			ForeColor(blackColor);
			RGBBackColor(&tmpBack);
		}

		/* Paint temp colors into the color panes */
		PenSize(2, 2);

		GetDItem(win, diSideColorPane1, NULL, NULL, &itemrect);
		if (strcmp(tmpName1, "undefined") == 0) {
			FillRect(&itemrect, QDPat(ltGray));
		} else {
			RGBForeColor(&tmpColor[1]);
			FillRect(&itemrect, QDPat(black));
			ForeColor(blackColor);
		}
		FrameRect(&itemrect);

		GetDItem(win, diSideColorPane2, NULL, NULL, &itemrect);
		if (strcmp(tmpName2, "undefined") == 0) {
			FillRect(&itemrect, QDPat(ltGray));
		} else {
			RGBForeColor(&tmpColor[2]);
			FillRect(&itemrect, QDPat(black));
			ForeColor(blackColor);
		}
		FrameRect(&itemrect);

		GetDItem(win, diSideColorPane3, NULL, NULL, &itemrect);
		if (strcmp(tmpName3, "undefined") == 0) {
			FillRect(&itemrect, QDPat(ltGray));
		} else {
			RGBForeColor(&tmpColor[3]);
			FillRect(&itemrect, QDPat(black));
			ForeColor(blackColor);
		}
		FrameRect(&itemrect);

		PenNormal();

		/* Handle clicks on buttons, popup menus, color panes, check boxes & edit fields */
		ModalDialog(NULL, &ditem);
		switch (ditem) {

			/* Get name from popup menu, load the color and copy name into text field  */
		case 	diSideColorPopup1:
			GetDItem(win, ditem, NULL, &itemhandle, NULL);
			mitem = GetCtlValue((ControlHandle) itemhandle);
			GetItem(popMenu, mitem, pname);
			p2c(pname, tmpName1);
			tmpColor[1] = get_color(tmpName1);	/* May change tmpName1 to undefined! */
			c2p(tmpName1, pname);
			GetDItem(win, diSideColorName1, NULL, &itemhandle, NULL);
			SetIText(itemhandle, pname);
	    	break;
		case 	diSideColorPopup2:
			GetDItem(win, ditem, NULL, &itemhandle, NULL);
			mitem = GetCtlValue((ControlHandle) itemhandle);
			GetItem(popMenu, mitem, pname);
			p2c(pname, tmpName2);
			tmpColor[2] = get_color(tmpName2);	/* May change tmpName2 to undefined! */
			c2p(tmpName2, pname);
			GetDItem(win, diSideColorName2, NULL, &itemhandle, NULL);
			SetIText(itemhandle, pname);
	    	break;
		case 	diSideColorPopup3:
			GetDItem(win, ditem, NULL, &itemhandle, NULL);
			mitem = GetCtlValue((ControlHandle) itemhandle);
			GetItem(popMenu, mitem, pname);
			p2c(pname, tmpName3);
			tmpColor[3] = get_color(tmpName3);	/* May change tmpName3 to undefined! */
			c2p(tmpName3, pname);
			GetDItem(win, diSideColorName3, NULL, &itemhandle, NULL);
			SetIText(itemhandle, pname);
	    	break;

			/* Get color use from popup menus and copy into tmpUse[i] */
		case 	diSideColorUse1:
			GetDItem(win, ditem, NULL, &itemhandle, NULL);
			tmpUse[1] = GetCtlValue((ControlHandle) itemhandle);
			if (strcmp(tmpName1, "") == 0) tmpUse[1] = miNotInUse;
			if (tmpUse[2] == tmpUse[1]) tmpUse[2] = miNotInUse;
			if (tmpUse[3] == tmpUse[1]) tmpUse[3] = miNotInUse;
	    	break;
		case 	diSideColorUse2:
			GetDItem(win, ditem, NULL, &itemhandle, NULL);
			tmpUse[2] = GetCtlValue((ControlHandle) itemhandle);
			if (strcmp(tmpName2, "") == 0) tmpUse[2] = miNotInUse;
			if (tmpUse[1] == tmpUse[2]) tmpUse[1] = miNotInUse;
			if (tmpUse[3] == tmpUse[2]) tmpUse[3] = miNotInUse;
	    	break;
		case 	diSideColorUse3:
			GetDItem(win, ditem, NULL, &itemhandle, NULL);
			tmpUse[3] = GetCtlValue((ControlHandle) itemhandle);
			if (strcmp(tmpName3, "") == 0) tmpUse[3] = miNotInUse;
			if (tmpUse[1] == tmpUse[3]) tmpUse[1] = miNotInUse;
			if (tmpUse[2] == tmpUse[3]) tmpUse[2] = miNotInUse;
	    	break;

			/* Pick new color by clicking in a color pane */
		case 	diSideColorPane1:
			tmpColor[1] = pick_new_color(tmpColor[1], tmpName1);
			break;
		case 	diSideColorPane2:
			tmpColor[2] = pick_new_color(tmpColor[2], tmpName2);
			break;
		case 	diSideColorPane3:
			tmpColor[3] = pick_new_color(tmpColor[3], tmpName3);
			break;

			/* Toggle split icons checkbox */
		case	diSideColorSplit:
			GetDItem(win, diSideColorSplit, NULL, &itemhandle, NULL);
			tmpSplit = !GetCtlValue((ControlHandle) itemhandle);
			SetCtlValue((ControlHandle) itemhandle, tmpSplit);
			break;

			/* Edit the text fields */
		case	diSideColorName1:
		case	diSideColorName2:
		case	diSideColorName3:
			editflag = TRUE;		/* Set flag to save text instead of exit next time Return is hit */
			continue;	 		/* Do NOT break if text is being edited! Continue instead */

		case 	diSideColorOkButton:
			if (editflag) {		 	/* Save text fields instead of exit when flag is set */ 
				editflag = FALSE;		/* Clear flag to permit exit next time Return is hit */

				/* Check text fields for validity and then update temp colors */
				GetDItem(win, diSideColorName1, NULL, &itemhandle, NULL);
		    	GetIText(itemhandle, pname);
				p2c(pname, cname);
				if (valid_imf_name(cname)) {
					tmpColor[1] = get_color(cname);		/* May change cname to undefined! */
					strcpy(tmpName1, cname);
				} else {	
					ParamText("\pSorry, Ò", pname, "\pÓ is not a valid color name. ", 
						 	 "\pUse hyphens: Òdark-redÓ is OK but Òdark redÓ is not.");
					button = Alert(aOneButtonAlert, NULL);
				}
				c2p(tmpName1, pname);
				SetIText(itemhandle, pname);		/* Update or restore the text field */

				GetDItem(win, diSideColorName2, NULL, &itemhandle, NULL);
		    	GetIText(itemhandle, pname);
				p2c(pname, cname);
				if (valid_imf_name(cname)) {
					tmpColor[2] = get_color(cname);		/* May change cname to undefined! */
					strcpy(tmpName2, cname);
				} else {
					ParamText("\pSorry, Ò", pname, "\pÓ is not a valid color name. ", 
						 	 "\pUse hyphens: Òdark-redÓ is OK but Òdark redÓ is not.");
					button = Alert(aOneButtonAlert, NULL);
				}
				c2p(tmpName2, pname);
				SetIText(itemhandle, pname);		/* Update or restore the text field */

				GetDItem(win, diSideColorName3, NULL, &itemhandle, NULL);
		    	GetIText(itemhandle, pname);
				p2c(pname, cname);
				if (valid_imf_name(cname)) {
					tmpColor[3] = get_color(cname);		/* May change cname to undefined! */
					strcpy(tmpName3, cname);
				} else {	
					ParamText("\pSorry, Ò", pname, "\pÓ is not a valid color name. ", 
						 	 "\pUse hyphens: Òdark-redÓ is OK but Òdark redÓ is not.");
					button = Alert(aOneButtonAlert, NULL);
				}
				c2p(tmpName3, pname);
				SetIText(itemhandle, pname);		/* Update or restore the text field */

				break;

			} else {	/* Update everything and exit the dialog */

				/* Update side colors */
				set_sideColor(e, 1, tmpColor[1]);
				set_sideColor(e, 2, tmpColor[2]);
				set_sideColor(e, 3, tmpColor[3]);

				/* Update side color names */
				set_sideColorName(e, 1, copy_string(tmpName1));
				set_sideColorName(e, 2, copy_string(tmpName2));
				set_sideColorName(e, 3, copy_string(tmpName3));

				/* Change "undefined" to empty string before proceeding */
				/* This is done to conform with the color scheme format */
				if (strcmp(tmpName1, "undefined") == 0)
				  strcpy(tmpName1, "");
				if (strcmp(tmpName2, "undefined") == 0)
				  strcpy(tmpName2, "");
				if (strcmp(tmpName3, "undefined") == 0)
				  strcpy(tmpName3, "");

				/* Build a new colorscheme */
				strcpy(tmpScheme,tmpName1);
				strcat(tmpScheme, ",");
				strcat(tmpScheme, tmpName2);
				strcat(tmpScheme, ",");
				strcat(tmpScheme, tmpName3);
				side_n(e)->colorscheme = copy_string(tmpScheme);

				/* Update color use parameters */
				main_icon_color[e] = 0;
				half_icon_color[e] = 0;
				icon_mask_color[e] = 0;
				for (i = 1; i <=3; i++) {
					if (tmpUse[i] == miMainIconColor)
					  main_icon_color[e] = i;
					if (tmpUse[i] == miHalfIconColor)
					  half_icon_color[e] = i;
					if (tmpUse[i] == miIconMaskColor)
					  icon_mask_color[e] = i;
				}

				/* Set use of split icons */
				split_icon[e] = tmpSplit;

				done = TRUE;
				break;
			}

		case 	diSideColorCancelButton:
			done = TRUE;
			break;
		
		default:   /* Important to break here in order to reenter the while loop! */
			break;

 		}
	}
	SetPort(oldport);
	DisposeDialog(win);
	update_all_map_windows();
}

/* Set the colors of special features */

void
set_feature_color(int e)
{
	short editflag, ditem, mitem, button, found, done, i, n;  
	char cname[32], tmpName[32];
	Handle itemhandle, ppathandle;  
	RGBColor tmpColor;
	MenuHandle popMenu;
	Rect itemrect;
	GrafPtr oldport;
	Str255 pname;
	DialogPtr win;

	/* Then check for color support */
	if (!hasColorQD) {
		ParamText("\pSorry, your mac does not support colors.", "\p", "\p", "\p");
		button = Alert(aOneButtonAlert, NULL);
		return;
	} 

	/* Get dialog window and popup menu */
	win = GetNewDialog(dFeatureColor, NULL, (DialogPtr) -1);
	popMenu = GetMenu(mSideColorPopup);

	/* Load current color & name into temps */
	strcpy(tmpName, featColorName[e]);
	tmpColor = featColor[e];

	/* Load temp name into the text field */
	GetDItem(win, diFeatureColorName, NULL, &itemhandle, NULL);
	c2p(tmpName, pname);
	SetIText(itemhandle, pname);

	/* Build the popup menu for new colors. */
	build_colors_popup_menu(popMenu);
	
	/* Change port and start the main loop */
	GetPort(&oldport);
	SetPort(win);
	done = FALSE;
	editflag = FALSE;
	while (!done) {

		/* Check length of popMenu */
		n = CountMItems(popMenu);

		/* Set popup to tmpName if found in menu */
		GetDItem(win, diFeatureColorPopup, NULL, &itemhandle, NULL);
		SetCtlMax((ControlHandle) itemhandle, n);			/* Important! */
		found = FALSE;
		for (i = 1; i <= n; i++) {
			GetItem(popMenu, i, pname);
			p2c(pname, cname);
			if (strcmp(tmpName, cname) != 0)
			  continue;
			SetCtlValue((ControlHandle) itemhandle, i);
			found = TRUE;
			  break;
		}
		if (!found) {				/* Add tmpName to menu if necessary */
			c2p(tmpName, pname);
			AppendMenu(popMenu, pname);
			SetCtlMax((ControlHandle) itemhandle, n + 1);	/* Important! */
			SetCtlValue((ControlHandle) itemhandle, n + 1);
		}

		/* Open the window now (as late as possible) */
		ShowWindow(win);
		SetCursor(&QD(arrow));
		draw_default_button(win, diFeatureColorOkButton);
	
		/* Paint temp color into the color pane */
		PenSize(2, 2);
		GetDItem(win, diFeatureColorPane, NULL, NULL, &itemrect);
		RGBForeColor(&tmpColor);
		FillRect(&itemrect, QDPat(black));
		ForeColor(blackColor);
		FrameRect(&itemrect);
		PenNormal();

		/* Handle clicks on buttons, popup menus, and color panes */
		ModalDialog(NULL, &ditem);
		switch (ditem) {

			/* Get name from popup menu, copy into text field, and load the color */
		case 	diFeatureColorPopup:
			GetDItem(win, ditem, NULL, &itemhandle, NULL);
			mitem = GetCtlValue((ControlHandle) itemhandle);
			GetItem(popMenu, mitem, pname);
			GetDItem(win, diFeatureColorName, NULL, &itemhandle, NULL);
			SetIText(itemhandle, pname);
			p2c(pname, tmpName);
			tmpColor = get_color(tmpName);
	    		break;

			/* Pick new color by clicking in a color pane */
		case 	diFeatureColorPane:
			tmpColor = pick_new_color(tmpColor, tmpName);
			break;

			/* The text field is being edited */
		case	diFeatureColorName:
			editflag = TRUE;		/* Set flag to save text instead of exit next time OK is hit */
			continue;	 		/* Do NOT break if text is being edited! Continue instead */

		case 	diFeatureColorOkButton:
			if (editflag) {		 	/* Save text fields instead of exit when flag is set */ 
				editflag = FALSE;		/* Clear flag to permit exit next time OK is hit */

				/* Check text field for validity and then update temp color */
				GetDItem(win, diFeatureColorName, NULL, &itemhandle, NULL);
		    		GetIText(itemhandle, pname);
				p2c(pname, cname);
				if (valid_imf_name(cname)) {
					strcpy(tmpName, cname);
					tmpColor = get_color(tmpName);
				} else {
					ParamText("\pSorry, Ò", pname, "\pÓ is not a valid color name. ", 
						 	 "\pUse hyphens: Òdark-redÓ is OK, Òdark redÓ is not.");
					button = Alert(aOneButtonAlert, NULL);
					c2p(tmpName, pname);
					SetIText(itemhandle, pname);		/* Restore old text */
				} 
				break;

			} else {	/* Update everything and exit the dialog */

				featColor[e] = tmpColor;
				featColorName[e] = copy_string(tmpName);

				/* This is now checked only once, instead of every time a map is redrawn. */
				if (strcmp(gridcolor_name, unseencolor_name) == 0
				    || g_terrain_seen() || (dside)->see_all) {
		 	 		 grid_matches_unseen = TRUE;
				} else grid_matches_unseen = FALSE;

				ui_update_state();
				done = TRUE;
				break;
			}

		case 	diFeatureColorCancelButton:
			done = TRUE;
			break;
		
		default:   /* Important to break here in order to reenter the while loop! */
			break;

 		}
	}
	SetPort(oldport);
	DisposeDialog(win);
	update_all_map_windows();
}

/* Set color (or pattern) used to display the terrain */

void
set_terrain_color( Str255 tname)
{
	short editflag, ditem, mitem, button, found, done, i, n, e = -1;  
	char cname[32], tmpName[32];
	Handle itemhandle, ppathandle;  
	RGBColor tmpColor;
	MenuHandle popMenu;
	MacImage *macimg;
	Rect itemrect;
	GrafPtr oldport;
	Str255 pname;
	ImageFamily *imf;
	Image *img;
	DialogPtr win;

	/* Then check for color support */
	if (!hasColorQD) {
		ParamText("\pSorry, your mac does not support colors.", "\p", "\p", "\p");
		button = Alert(aOneButtonAlert, NULL);
		return;
	} 

	/* Get dialog window and popup menu */
	win = GetNewDialog(dFeatureColor, NULL, (DialogPtr) -1);
	popMenu = GetMenu(mSideColorPopup);

	/* Load tname into the text field and get the corresponding color */
	GetDItem(win, diFeatureColorName, NULL, &itemhandle, NULL);
	SetIText(itemhandle, tname);
	p2c(tname, tmpName);
	tmpColor = get_color(tmpName);

	/* Get the current terrain number from tmpName */
	for_all_terrain_types(i) {
		/* Use image names if they exist */
		if (!empty_string(t_image_name(i))) {
			sanitize_for_menu(t_image_name(i), pname);
			/* Else use terrain names (may differ from image names) */
		} else
		  sanitize_for_menu(t_type_name(i), pname);
		p2c(pname, cname);
		if (strcmp(cname, tmpName) != 0)
		  continue;
		e = i; 
		break;
	}

	/* Build the popup menu for new colors. */
	build_colors_popup_menu(popMenu);
	
	/* Change port and start the main loop */
	GetPort(&oldport);
	SetPort(win);
	done = FALSE;
	editflag = FALSE;
	while (!done) {

		/* Check length of popMenu and load the image family */
		n = CountMItems(popMenu);
		imf = get_imf(tmpName);
		mac_load_imf(imf);

		/* Set popup to tmpName if found in menu */
		GetDItem(win, diFeatureColorPopup, NULL, &itemhandle, NULL);
		SetCtlMax((ControlHandle) itemhandle, n);			/* Important! */
		found = FALSE;
		for (i = 1; i <= n; i++) {
			GetItem(popMenu, i, pname);
			p2c(pname, cname);
			if (strcmp(tmpName, cname) != 0)
			  continue;
			SetCtlValue((ControlHandle) itemhandle, i);
			found = TRUE; break;
		}
		if (!found) {				/* Add tmpName to menu if necessary */
			c2p(tmpName, pname);
			AppendMenu(popMenu, pname);
			SetCtlMax((ControlHandle) itemhandle, n + 1);	/* Important! */
			SetCtlValue((ControlHandle) itemhandle, n + 1);
		}

		/* Open the window now (as late as possible) */
		ShowWindow(win);
		SetCursor(&QD(arrow));
		draw_default_button(win, diFeatureColorOkButton);
	
		/* Paint terrain pattern into the color pane */
		GetDItem(win, diFeatureColorPane, NULL, NULL, &itemrect);
		img = best_image(imf, hws[5], hcs[5]);
		macimg = (MacImage *) img->hook;
		if (macimg->colrpat != NULL) {
			FillCRect(&itemrect, macimg->colrpat);
		} else if (macimg->colordefined) {
			RGBForeColor(&macimg->color);
			PaintRect(&itemrect);
			ForeColor(blackColor);
		}

		/* Draw the frame */
		PenSize(2, 2);
		FrameRect(&itemrect);
		PenNormal();

		/* Handle clicks on buttons, popup menus, and color panes */
		ModalDialog(NULL, &ditem);
		switch (ditem) {

			/* Get name from popup menu, copy into text field, and load the color */
		case 	diFeatureColorPopup:
			GetDItem(win, ditem, NULL, &itemhandle, NULL);
			mitem = GetCtlValue((ControlHandle) itemhandle);
			GetItem(popMenu, mitem, pname);
			GetDItem(win, diFeatureColorName, NULL, &itemhandle, NULL);
			SetIText(itemhandle, pname);
			p2c(pname, tmpName);
			tmpColor = get_color(tmpName);
	    	break;

			/* The text field is being edited */
		case	diFeatureColorName:
			editflag = TRUE;		/* Set flag to save text instead of exit next time OK is hit */
			continue;	 		/* Do NOT break if text is being edited! Continue instead */

		case 	diFeatureColorOkButton:
			if (editflag) {		 	/* Save text fields instead of exit when flag is set */ 
				editflag = FALSE;		/* Clear flag to permit exit next time OK is hit */

				/* Check text field for validity and then update temp color */
				GetDItem(win, diFeatureColorName, NULL, &itemhandle, NULL);
		    	GetIText(itemhandle, pname);
				p2c(pname, cname);
				if (valid_imf_name(cname)) {
					strcpy(tmpName, cname);
					tmpColor = get_color(tmpName);
				} else {	/* Restore previous text */
					ParamText("\pSorry, Ò", pname, "\pÓ is not a valid color name. ", 
						 	 "\pUse hyphens: Òdark-redÓ is OK but Òdark redÓ is not.");
					button = Alert(aOneButtonAlert, NULL);
					c2p(tmpName, pname);
					SetIText(itemhandle, pname);
				} 
				break;

			} else {	/* Update everything and exit the dialog */

				/* Replace terrain images used for drawing */
				for (i = 0; i < NUMPOWERS; ++i) {
					img = best_image(imf, hws[i], hcs[i]);
					if (img && e != -1) {
						best_terrain_images[i * numttypes + e] = img;
					}
				}
				/* Replace terrain colors used for solid color drawing */
				img = get_img(imf, 1, 1, 0);
				if (img->hook && e != -1) {
					macimg = (MacImage *) img->hook;
					tcolors[e] = macimg;
				}
				done = TRUE;
				break;
			}

		case 	diFeatureColorCancelButton:
			done = TRUE;
			break;
		
		default:   /* Important to break here in order to reenter the while loop! */
			break;

 		}
	}
	SetPort(oldport);
	DisposeDialog(win);
	update_all_map_windows();
}

/* --- FUNCTIONS USED TO BUILD AND MAINTAIN MENUS -----------------------------------*/

/* Insert side and feature names into the colors menu */

void
build_colors_menu(void)
{
	MenuHandle menu;
	Str255 pname;
	int i, t;

	menu = GetMenu(mColors);
	/* First load side names at the top of the menu */
	/* Side 0 (Independents) is already in the menu */
	for (i = 1; i <= numsides; i++) {
		sanitize_for_menu(shortest_side_title(side_n(i), tmpbuf), pname);
		InsMenuItem(menu, pname, i);
	}
	/* Then load feature names below first separator */
	for (i = 0; i <= FEATURES; i++) {
		sanitize_for_menu(featColorItemName[i], pname);
		InsMenuItem(menu, pname, numsides + i + 2);
	}
	/* Then load terrain types below second separator */
	for_all_terrain_types(t) {
		sanitize_for_menu(t_type_name(t), pname);
		InsMenuItem(menu, pname, numsides + FEATURES + t + 4);
	}
}

void
build_sides_menu(void)
{
	MenuHandle menu;
	Str255 pname;
	int i;

	menu = GetMenu(mSidesPopup);
	/* First load real side names for sides in play */
	/* Side 0 (Independents) is already in the menu */
	for (i = 1; i <= numsides; i++) {
		sanitize_for_menu(shortest_side_title(side_n(i), tmpbuf), pname);
		AppendMenu(menu, pname);
	}
	/* Then load side numbers for remaining sides */
	for (i = numsides + 1; i <= MAXSIDES; i++) {
		sprintf(tmpbuf, "Side %d", i);
		sanitize_for_menu(tmpbuf, pname);
		AppendMenu(menu, pname);
	}
}
void
build_features_menu(void)
{
	MenuHandle menu;
	Str255 pname;
	int i;

	menu = GetMenu(mFeatPopup);
	/* Load available feature names */
	for (i = 0; i <= FEATURES; i++) {
		sanitize_for_menu(featColorItemName[i], pname);
		AppendMenu(menu, pname);
	}
}

void
build_colors_popup_menu(MenuHandle popMenu)
{
	Handle	ppathandle;  
	char 		cname[32];
	Str255	pname;
	int 		i, n;

	/* Use lib-mac Images file if available. */
	n = GetResFileAttrs(images_refnum);
	if (!ResError()) {
		/* Load all available ppat colors into the popup menu. */
		n = CountResources('ppat');
		for (i = 1; i <= n; ++i ) {
			ppathandle = GetIndResource('ppat', i);
			GetResInfo(ppathandle, NULL, NULL, pname);
			/* Only use ppats that live in the Images file. */
			if (HomeResFile(ppathandle) != images_refnum)
				continue;
			p2c(pname, cname);
			/* Skip invalid names. */
			if (!valid_imf_name(cname))
				continue;
			AppendMenu(popMenu, pname);
		}

	/* Else use colors from the colors.imf and terrain.imf files. */
	} else {
		/* First load all real colors. */
	    	make_pathname(xconq_libs->path, "colors.imf", "", spbuf);
		load_imf_file(spbuf, append_color_callback);

		/* Then add an item separator. */
		AppendMenu(popMenu, "\p(-");

		/* Then load the terrain colors. */
	    	make_pathname(xconq_libs->path, "terrain.imf", "", spbuf);
		load_imf_file(spbuf, append_color_callback);
	}
}

void 
append_color_callback(ImageFamily *imf, int loadnow)
{
	Str255 		lastname, pname;
	char 			cname[32];
	MenuHandle	popMenu;	

	if (!valid_imf_name(imf->name))
		return;
	popMenu = GetMenu(mSideColorPopup);
	GetItem(popMenu, CountMItems(popMenu), lastname);
	p2c(lastname, cname);
	/* Skip if item has the same name as previous item. */
	if (strcmp(imf->name, cname) != 0) {
		c2p(imf->name, pname);
		AppendMenu(popMenu, pname);
	}
}
