/* Menus and commands for the Mac interface to Xconq.
   Copyright (C) 1992-1998 Stanley T. Shebs.

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"
extern int num_sides_allowed PARAMS ((int u));
#include "print.h"
#include "kpublic.h"
#include "macconq.h"
extern int do_down_command(void);
extern int do_up_command(void);

/* Advance and advanced unit support. */
extern void global_advance_dialog(Side *side, Unit *unit, int advance);
extern void city_dialog(Map *map, Unit *unit);
static void do_city_dialog_mi(void);

Side *tmpcmdside;

int tmp_plan_type;

void
query_position_modally(int mode)

{
	if (map_modal == NO_MODAL) {
		map_modal = mode;
	} else {
		beep();
	}
}

void
set_position_modally()
{
	modal_map = map_from_window(FrontWindow());
	GetMouse(&modal_point);
	position_set_modally = TRUE;
}

extern int do_one_give(Unit *unit);
extern int do_one_take(Unit *unit);
extern int do_one_detonate(Unit *unit);
extern int do_one_give_unit(Unit *unit);

extern int do_one_dir_move(Unit *unit);
extern int do_one_dir_multiple_move(Unit *unit);
extern int do_one_set_name(Unit *unit);

static int do_one_plan_type(Unit *unit);

static void resign_the_game(int forced);

static void te_cut(TEHandle hdl);
static void te_copy(TEHandle hdl);
static void te_paste(TEHandle hdl);

static void do_page_setup_mi(void);
static void do_print_mi(void);
static void do_select_all_mi(void);
static void do_find_previous_mi(void);
static void do_find_next_mi(void);
static void do_find_location_mi(void);
static void do_find_unit_by_name_mi(void);
static void do_find_selected_mi(void);
static void do_closeup_mi(void);
static void do_done_moving_mi(void);
static void do_overrun_mi(void);
static void do_take_mi(void);
static void do_detonate_mi(void);
static void do_give_unit_mi(int mi);
static void do_disband_mi(void);
static void do_plan_type_mi(void);
static void moveonclick_mi(void);
static void autoselect_mi(void);

static void adjust_menu_item(MenuHandle menu, int item, int value);
extern void enable_commands_for_unit(MenuHandle menu, MenuHandle menu2, Unit *unit);

int forcedtoresign;

int modal_construction = FALSE;

WindowPtr window_behind_construction;

#ifdef THINK_C
#include <profile.h>
#endif

int Profile = FALSE;

#ifdef DESIGNERS
#define side_may_select(unit) (in_play(unit) && ((unit)->side == dside || dside->designer))

#define valid_selection(unit) (in_play(unit) && ((unit)->side == dside || dside->designer))

#define menus_tweakable() ((!beforestart && !endofgame) || (gameinited && dside->designer))
#else /* n DESIGNERS */
#define side_may_select(unit) (in_play(unit) && ((unit)->side == dside))

#define valid_selection(unit) (in_play(unit) && ((unit)->side == dside))

#define menus_tweakable() ((!beforestart && !endofgame) || (gameinited))
#endif /* DESIGNERS */

#define MAXWINDOWS 100

char *cursavename = NULL;

MenuHandle mapviewmenu = nil;
MenuHandle listviewmenu = nil;
MenuHandle closeupviewmenu = nil;
MenuHandle colorsmenu = nil;
MenuHandle utypemenu = nil;
MenuHandle ttypemenu = nil;
MenuHandle mtypemenu = nil;
MenuHandle sidemenu = nil;
MenuHandle aitypemenu = nil;

MenuHandle featuremenu = nil;
MenuHandle optterrmenu = nil;

/* This is the array of windows that the Windows menu references. */

WindowPtr *winmenuwins;

int numwindows = 0;

Map *worldmap = NULL;

WindowPtr worldmapwin = nil;

short *feature_menu_fids;

int feature_menu_size;

/* Set up all the menus, at least in their basic form. */

void
init_menus()
{
	int i;
	Handle menubar;
	MenuHandle menu;

	menubar = GetNewMBar(mbMain);
	SetMenuBar(menubar);
	/* Add the DAs etc as usual. */
	menu = GetMHandle(mApple);
	if (menu != nil)
	  AddResMenu(menu, 'DRVR');
	/* Get the different versions of the view menu. */
	mapviewmenu = GetMenu(mViewMap);
	listviewmenu = GetMenu(mViewList);
	closeupviewmenu = GetMenu(mViewCloseup);
	/* Init submenus and popups. */
	colorsmenu = GetMenu(mColors);
	if (colorsmenu != nil)
	  InsertMenu(colorsmenu, -1);
	menu = GetMenu(mMagnifications);
	if (menu != nil)
	  InsertMenu(menu, -1);
	menu = GetMenu(mViewWeather);
	if (menu != nil)
	  InsertMenu(menu, -1);
	menu = GetMenu(mViewAngles);
	if (menu != nil)
	  InsertMenu(menu, -1);
	menu = GetMenu(mPlanTypes);
	if (menu != nil)
	  InsertMenu(menu, -1);
	menu = GetMenu(mViewText);
	if (menu != nil)
	  InsertMenu(menu, -1);

	menu = GetMenu(mViewGrids);
	if (menu != nil)
	  InsertMenu(menu, -1);

	menu = GetMenu(mViewColors);
	if (menu != nil)
	  InsertMenu(menu, -1);

	menu = GetMenu(mViewBorders);
	if (menu != nil)
	  InsertMenu(menu, -1);

	sidemenu = GetMenu(mSides);
	if (sidemenu != nil)
	  InsertMenu(sidemenu, -1);
	utypemenu = GetMenu(mUnitTypes);
	if (utypemenu != nil)
	  InsertMenu(utypemenu, -1);
	mtypemenu = GetMenu(mMaterialTypes);
	if (mtypemenu != nil)
	  InsertMenu(mtypemenu, -1);
	ttypemenu = GetMenu(mTerrainTypes);
	if (ttypemenu != nil)
	  InsertMenu(ttypemenu, -1);
	aitypemenu = GetMenu(mAITypes);
	if (aitypemenu != nil)
	  InsertMenu(aitypemenu, -1);
	featuremenu = GetMenu(mFeatures);
	if (featuremenu != nil)
	  InsertMenu(featuremenu, -1);
	optterrmenu = GetMenu(mOptTerrainTypes);
	if (optterrmenu != nil)
	  InsertMenu(optterrmenu, -1);
	/* Init the support for the Windows menu. */
	winmenuwins = (WindowPtr *) xmalloc(MAXWINDOWS * sizeof(WindowPtr));
	for (i = 0; i < MAXWINDOWS; ++i)
	  winmenuwins[i] = nil;
	numwindows = 0;
	/* Done fiddling with menus, draw them. */
	DrawMenuBar();
}

/* Add a menu item that can be used to go to the given window.  Set the window title
   here too, ensures that the two match. */

void
add_window_menu_item(char *name, WindowPtr win)
{
	MenuHandle menu;
	Str255 tmpstr;

	if (numwindows < MAXWINDOWS) {
		c2p(name, tmpstr);
		SetWTitle(win, tmpstr);
		/* Don't add the World Map - it's already in the menu. */
		if (win != worldmapwin) {
			winmenuwins[numwindows++] = win;
			menu = GetMHandle(mWindows);
			if (menu != nil)
		  	    AppendMenu(menu, tmpstr);
		}
	}
}

/* Remove the menu item that can be used to select a given window. */

void
remove_window_menu_item(WindowPtr win)
{
	int i, found = FALSE, next = 0;
	Str255 tmpstr;
	MenuHandle menu;

	/* Search for the window and remove it from the array of windows
	   that have menu items. */
	for (i = 0; i < numwindows; ++i) {
		if (!found && winmenuwins[i] == win) {
			found = TRUE;
		}
		if (found && i < numwindows - 1) {
			/* Shift the other windows down. */
			winmenuwins[i] = winmenuwins[i + 1];
		}
	}
	/* This routine gets called for all windows, so get out of here
	   if this window is not one of those in the menu. */
	if (!found)
	  return;
	--numwindows;
	/* Trash the existing window menu. */
	menu = GetMHandle(mWindows);
	if (menu != nil) {
		DeleteMenu(mWindows);
		ReleaseResource((Handle) menu);
	}
	/* Build a new version starting with the resource. */
	menu = GetMenu(mWindows);
	if (menu != nil) {
		for (i = 0; i < numwindows; ++i) {
			GetWTitle(winmenuwins[i], tmpstr);
			AppendMenu(menu, tmpstr);
		}
		/* Glue a view menu on after the windows menu. */
		if (GetMHandle(mViewMap) != nil)
		  next = mViewMap;
		if (GetMHandle(mViewList) != nil)
		  next = mViewList;
		InsertMenu(menu, next);
	}
	DrawMenuBar();
}

/* Fill up the side menu. */

void
build_side_menu()
{
	char *title;
	Side *side2;
	Str255 tmpstr;

	if (sidemenu != nil && CountMItems(sidemenu) < 1) {
		for_all_sides(side2) {
			title = shortest_side_title(side2, spbuf);
			sanitize_for_menu(title, tmpstr);
			AppendMenu(sidemenu, tmpstr);
			EnableItem(sidemenu, side_number(side2));
		}
		if (1 /* independent units possible in this game */) {
			AppendMenu(sidemenu, "\pindependent");
		}
	}
}

void
update_side_menu(Side *side2)
{
	char *title;
	Str255 tmpstr;

	title = shortest_side_title(side2, spbuf);
	sanitize_for_menu(title, tmpstr);
	SetMenuItemText(sidemenu, side_number(side2), tmpstr);
}

void
build_unit_type_menu()
{
	int u;
	Str255 tmpstr;

	if (utypemenu != nil && CountMItems(utypemenu) < 1) {
		for_all_unit_types(u) {
			sanitize_for_menu(u_type_name(u), tmpstr);
			AppendMenu(utypemenu, tmpstr);
			EnableItem(utypemenu, u + 1);
		}
	}
}

void
build_material_type_menu()
{
	int m;
	Str255 tmpstr;

	if (mtypemenu != nil && CountMItems(mtypemenu) < 1 && nummtypes > 0) {
		for_all_material_types(m) {
			sanitize_for_menu(m_type_name(m), tmpstr);
			AppendMenu(mtypemenu, tmpstr);
			EnableItem(mtypemenu, m + 1);
		}
	}
}

void
build_terrain_type_menu()
{
	int t;
	Str255 tmpstr;

	if (ttypemenu != nil && CountMItems(ttypemenu) < 1) {
		for_all_terrain_types(t) {
			sanitize_for_menu(t_type_name(t), tmpstr);
			AppendMenu(ttypemenu, tmpstr);
			EnableItem(ttypemenu, t);
		}
	}
}

void
build_ai_type_menu()
{
	if (aitypemenu != nil && CountMItems(aitypemenu) < 1) {
		AppendMenu(aitypemenu, "\pNone");
		EnableItem(aitypemenu, 1);
		AppendMenu(aitypemenu, "\pMplayer");
		EnableItem(aitypemenu, 2);
	}
}

void
build_feature_menu()
{
	int i, newsize;
	char *name;
	Str255 tmpstr;
	Feature *feature;
	MenuHandle oldmenu, newmenu = nil;

	if (featuremenu != nil) {
		if (CountMItems(featuremenu) >= 1) {
			/* Trash the existing feature menu. */
			oldmenu = GetMHandle(mFeatures);
			if (oldmenu != nil) {
				DeleteMenu(mFeatures);
				ReleaseResource((Handle) oldmenu);
				/* Build a new version starting with the resource. */
				if ((newmenu = GetMenu(mFeatures)) != nil) {
					featuremenu = newmenu;
				}
			}
		}
		/* Allocate the lookup array that maps menu items to actual feature ids. */
		newsize = 1;
		for_all_features(feature) {
			++newsize;
		}
		if (newsize != feature_menu_size) {
			if (feature_menu_size > 0)
			  free(feature_menu_fids);
			feature_menu_size = newsize;
			feature_menu_fids =
			  (short *) xmalloc(feature_menu_size * sizeof(short));
		}
		i = 0;
		/* The first item is used to clear features. */
		AppendMenu(featuremenu, "\pNo Feature");
		EnableItem(featuremenu, i + 1);
		feature_menu_fids[i++] = 0;
		for_all_features(feature) {
			name = feature_desc(feature, spbuf);
			sanitize_for_menu(name, tmpstr);
			AppendMenu(featuremenu, tmpstr);
			EnableItem(featuremenu, i + 1);
			feature_menu_fids[i++] = feature->id;
		}
		if (newmenu != nil) {
			InsertMenu(featuremenu, -1);
		}
	}
}

void
build_optional_terrain_type_menu()
{
	int t;
	Str255 tmpstr;

	if (optterrmenu != nil && CountMItems(optterrmenu) < 1) {
		for_all_terrain_types(t) {
			if (!t_is_cell(t)) {
				sanitize_for_menu(t_type_name(t), tmpstr);
				AppendMenu(optterrmenu, tmpstr);
				EnableItem(optterrmenu, t);
			}
		}
		if (CountMItems(optterrmenu) < 1)
		  optterrmenu = nil;
	}
}

/* This removes chars that are specially recognized by the Menu Manager.
   Has to be done so that strange game-defined names don't scramble the
   menus; innocuous because this affects only the appearance in the menu. */

extern void
sanitize_for_menu(char *str, Str255 outstr)
{
	int i = 0;

	/* Replace special chars with blanks. */
	for (i = 0; str[i] != '\0' && i < 255; ++i) {
		switch (str[i]) {
			case ';':
			case '!':
			case '<':
			case '/':
			case '(':
			/* I don't think closing parens are special, but since the
			   (presumed) matching open paren is gone, might as well get
			   rid of the close also. */
			case ')':
				outstr[i + 1] = ' ';
				break;
			default:
				outstr[i + 1] = str[i];
				break;
		}
	}
	outstr[i + 1] = '\0';
	/* Replace a leading hyphen with an underscore. */
	if (outstr[1] == '-')
	  outstr[1] = '_';
	outstr[0] = i;
}

/* Decipher and do a menu command. */

void
do_menu_command(long which)
{
	short menuid, menuitem, daRefNum;
	Str255 daname;
	WindowPtr win;
	Map *map;

	menuid = HiWord(which);
	menuitem = LoWord(which);
	DGprintf("menu %d, item %d\n", menuid, menuitem);
	map = map_from_window(FrontWindow());	
	switch (menuid) {
		case mApple:
			switch (menuitem) {
				case miAppleAbout:
					do_about_box();
					break;
				case miAppleHelp:
					help_dialog(NULL);
					break;
				case miAppleInstructions:
					instructions_dialog();
					break;
				default:
					GetItem(GetMHandle(mApple), menuitem, daname);
					daRefNum = OpenDeskAcc(daname);
			}
			break;
		case mFile:
			switch (menuitem) {
				case miFileNew:
					/* (should reset state of everything first) */
					new_game_dialog();
					break;
				case miFileOpen:
					/* (should reset state of everything first) */
					open_game_dialog();
					break;
				case miFileConnect:
					connect_game_dialog();
					break;
				case miFileClose:
					close_window(FrontWindow());
					break;
				case miFileSave:
					save_the_game(FALSE, FALSE);
					break;
				case miFileSaveAs:	
					save_the_game(TRUE, FALSE);
					break;
				case miFilePreferences:
					set_preferences();
					break;
				case miFilePageSetup:
					do_page_setup_mi();
					break;
				case miFilePrintWindow:
					do_print_mi();
					break;
				case miFileResign:
					do_resign(dside);
					break;
				case miFileQuit:
					quit_the_game();
					break;
			}
			break;
		case mEdit:
			if (SystemEdit(menuitem - 1))
			  break;
			switch (menuitem)  {
				case miEditCut:
					if (FrontWindow() == commandwin) {
						te_cut(command_text);
					} else if(FrontWindow() == constructionwin) {
						te_cut(run_length_text);
					}
					break;
				case miEditCopy:
					if (FrontWindow() == commandwin) {
						te_copy(command_text);
					} else if(FrontWindow() == constructionwin) {
						te_copy(run_length_text);
					}
					break;
				case miEditPaste:
					if (FrontWindow() == commandwin) {
						te_paste(command_text);
					} else if (FrontWindow() == constructionwin) {
						te_paste(run_length_text);
					}
					break;
				case miEditClear:
					if (FrontWindow() == commandwin) {
						TEDelete(command_text);						
					} else if (FrontWindow() == constructionwin) {
						TEDelete(run_length_text);						
					}
					break;
				case miEditSelectAll:
					do_select_all_mi();
					break;
#ifdef DESIGNERS
				case miEditDesign:
					do_design(dside);
					break;
#endif
			}
			break;
		case mFind:
			switch (menuitem) {
				case miFindPrevious:
					do_find_previous_mi();
					break;
				case miFindNext:
					do_find_next_mi();
					break;
				case miFindNextOccupant:
					do_occupant(dside);
					break;
				case miFindLocation:
					do_find_location_mi();
					break;
				case miFindUnitByName:
					do_find_unit_by_name_mi();
					break;
				case miFindDistance:
					do_distance(dside);
					break;
				case miFindSelected:
					do_find_selected_mi();
					break;
			}
			break;
		case mPlay:
			switch (menuitem) {
				case miPlayCloseup:
					do_closeup_mi();
					break;
				case miPlayCityDialog:
					do_city_dialog_mi();
					break;
				case miPlayMove:
					query_position_modally(MOVE_TO_MODAL);
					break;
				case miPlaySetFormation:
					query_position_modally(SET_FORMATION_MODAL);
					break;
				case miPlayReturn:
					do_return(dside);
					break;
				case miPlayWake:
					do_wake(dside);
					break;
				case miPlaySleep:
					do_sleep(dside);
					break;
				case miPlayReserve:
					do_reserve(dside);
					break;
				case miPlayBuild:
					do_build(dside);
					break;
				case miPlayRepair:
					do_repair(dside);
					break;
				case miPlayAttack:
					query_position_modally(ATTACK_MODAL);
					break;
				case miPlayOverrun:
					do_overrun_mi();
					break;
				case miPlayFire:
					query_position_modally(FIRE_MODAL);
					break;
				case miPlayFireInto:
					query_position_modally(FIRE_INTO_MODAL);
					break;
				case miPlayDetonate:
					do_detonate_mi();
					break;
			}
			break;
		case mMore:
			switch (menuitem) {
				case miMoreTake:
					do_take_mi();
					break;
				case miMoreGive:
					beep();
					break;
				case miMoreEmbark:
					do_embark(dside);
					break;
				case miMoreDisembark:
					do_disembark(dside);
					break;
				case miMoreDrop:
					beep();
					break;
				case miMoreGiveUnit:
					/* has submenu mSides */
					break;
				case miMoreDetach:
					do_detach(dside);
					break;
				case miMoreDisband:
					do_disband(dside);
					break;
				case miMoreAddTerrain:
					query_position_modally(ADD_TERRAIN_MODAL);
					break;
				case miMoreRemoveTerrain:
					query_position_modally(REMOVE_TERRAIN_MODAL);
					break;
				case miMoreRename:
					do_name(dside);
					break;
				case miMoreAIControl:
					do_auto(dside);
					break;
			}
			break;
		case mSides:
			do_give_unit_mi(menuitem);
			break;
		case mSide:
			switch (menuitem) {
				case miSideCloseup:
					break;
				case miSideFinishedTurn:
					net_finish_turn(dside);
					break;
				case miSideMoveOnClick:
					moveonclick_mi();
					break;
				case miSideAutoSelect:
					autoselect_mi();
					break;
				case miSideAutoFinish:
					/* Toggle auto-finish for turns. */
					net_set_autofinish(dside, !dside->autofinish);
					break;
				case miSideSound:
					playsounds = !playsounds;
					ui_update_state();
					save_preferences();
					break;
				case miSideSendMessage:
					do_message(dside);
					break;
				case miSideGlobalAdvance:
					global_advance_dialog(dside, NULL, -1);
					break;
				case miSideRename:
					side_rename_dialog(dside);
					break;
			}
			break;
		case 	mColors:
			if (menuitem <= numsides + 1) {
				set_side_colors(menuitem - 1);
			/* - 2 because of Independents and separator line */
			} else if (menuitem <= numsides + FEATURES + 2) {
				 set_feature_color(menuitem - numsides - 3);
			} else {
			/* Pass terrain by sanitized name instead of number */
				GetItem(GetMenu(mColors), menuitem, daname);
				set_terrain_color(daname);
			}			
			force_overall_update();
			break;
		case mWindows:
			switch (menuitem) {
				case miWindowsGame:
					if (gamewin == nil) {
						create_game_window();
					}
					ShowWindow(gamewin);
					SelectWindow(gamewin);
					break;
				case miWindowsNotices:
					if (noticewin == nil) {
						create_notice_window();
					}
					ShowWindow(noticewin);
					SelectWindow(noticewin);
					break;
				case miWindowsHistory:
					if (historywin == nil) {
						create_history_window();
					}
					ShowWindow(historywin);
					SelectWindow(historywin);
					break;
				case miWindowsConstruction:					
					enable_construction();
					break;
				case miWindowsCommand:
					enable_command();
					break;
				/* should have agreements list etc handling here also */
				case miWindowsScores:
					scores_dialog();
					break;
				case miWindowsNewList:
					create_list();
					break;
				case miWindowsNewMap:
					create_map(default_power, mapnum++);
					break;
				case miWindowsWorldMap:
					/* Create a new World Map if necessary. */
					if (!worldmap) {
						/* winwid should equal the default size of new windows */
						int p, power = 0, winwid, mainwidth;
						get_main_screen_size(&mainwidth, 0);
						winwid = mainwidth  - gamewinw - 10;
						for (p = NUMPOWERS - 1; p >= 0; p--) {
							if (area.width * hws[p] <= winwid) { 
								power = p;
								break;
							}
						}
						create_map(power, 0);
						/* Break to avoid a crash if create_map failed! */
						if (worldmap == NULL)
						     break;
					}
					ShowWindow(worldmapwin);
					SelectWindow(worldmapwin);
					update_window(worldmapwin);
					break;

				default:
					win = winmenuwins[menuitem - miWindowsFirst];
					if (win != nil) {
						SelectWindow(win);
						update_window(win);
					}
					break;
			}
			break;
		case mViewMap:
			if (map == NULL) break;
			switch (menuitem)  {
				case miViewCloser:
					magnify_map(map, 1);
					break;
				case miViewFarther:
					magnify_map(map, -1);
					break;
				case miViewPeople:
					toggle_map_people(map);
					break;
				case miViewControl:
					toggle_map_control(map);
					break;
				case miViewElevations:
					toggle_map_elevations(map);
					break;
				case miViewDaylight:
					toggle_map_lighting(map);
					break;
				case miViewCoverage:
					toggle_map_coverage(map);
					break;
				case miViewOffscreen:
					set_offscreen_buffers(map);
					break;
				case miViewMeridians:
					set_meridians(map);
					break;
			}
			break;


		case mViewWeather:
			if (map == NULL) break;
			switch (menuitem)  {
				case miWeatherTemperature:
					toggle_map_temperature(map);
					break;
				case miWeatherWinds:
					toggle_map_winds(map);
					break;
				case miWeatherClouds:
					toggle_map_clouds(map);
					break;
			}
			break;
		case mViewAngles:
			if (map == NULL) break;
			switch (menuitem)  {
				case miAngle15:
					set_map_angle(map, 15);
					break;
				case miAngle30:
					set_map_angle(map, 30);
					break;
				case miAngle90:
					set_map_angle(map, 90);
					break;
			}
			break;
		case mViewText:
			if (map == NULL) break;
			switch (menuitem)  {
				case miTextUnitNames:
					toggle_map_names(map);
					break;
				case miTextFeatureNames:
					toggle_featurenames(map);
					break;
				case miTextOptimizeFonts:
					toggle_optimize_fonts(map);
					break;
				case miTextEraseNames:
					toggle_erase_names(map);
					break;

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

				case miTextDrawEmblems:
					toggle_map_draw_emblems(map);
					break;

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

			}
			break;

		case mViewGrids:
			if (map == NULL) break;
			switch (menuitem)  {
				case miViewGrid:
					toggle_map_grid(map);
					break;
				case miViewTopline:
					toggle_map_topline(map);
					break;
				case miViewTopunit:
					toggle_map_topunit(map);
					break;
				case miViewOtherMaps:
					toggle_map_other_maps(map);
					break;
			}
			break;

		case mViewColors:
			if (map == NULL) break;
			switch (menuitem)  {
				case miSideColors:
					toggle_map_sidecolors(map);
					break;
				case miIconMasks:
					toggle_iconmasks(map);
					break;
				case miBoxMasks:
					toggle_boxmasks(map);
					break;
				case miTextMasks:
					toggle_textmasks(map);
					break;
				case miSolidColorTerrain:
					toggle_solid_color_terrain(map);
					break;
			}
			break;

		case mViewBorders:
			if (map == NULL) break;
			switch (menuitem)  {
				case miFeatureBorders:
					toggle_featureborders(map);
					break;
				case miShoreLines:
					toggle_shorelines(map);
					break;
				case miSimpleBorders:
					toggle_simple_borders(map);
					break;
			}
			break;
		case mViewList:
			switch (menuitem)  {
				case miViewByType:
					set_list_sorting(list_from_window(FrontWindow()), bytype, menuitem);
					break;
				case miViewByName:
					set_list_sorting(list_from_window(FrontWindow()), byname, menuitem);
					break;
				case miViewBySide:
					set_list_sorting(list_from_window(FrontWindow()), byside, menuitem);
					break;
				case miViewByActOrder:
					set_list_sorting(list_from_window(FrontWindow()), byactorder, menuitem);
					break;
				case miViewByLocation:
					set_list_sorting(list_from_window(FrontWindow()), bylocation, menuitem);
					break;
				case miViewCompleted:
					toggle_list_completed(list_from_window(FrontWindow()));
					break;
				case miViewIncomplete:
					toggle_list_incomplete(list_from_window(FrontWindow()));
					break;
				case miViewIconSize:
					toggle_list_large_icons(list_from_window(FrontWindow()));
					break;
				case miListSideColors:
					toggle_list_sidecolors(list_from_window(FrontWindow()));
					break;

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

				case miListDrawEmblems:
					toggle_list_draw_emblems(list_from_window(FrontWindow()));
					break;

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

			}
			break;
		case mAITypes:
			switch (menuitem) {
				case 1:
					if (side_has_ai(dside)) {
						net_set_side_ai(dside, NULL);
					}
					break;
				case 2:
					if (!side_has_ai(dside)) {
						net_set_side_ai(dside, "mplayer");
					}
					break;
			}
			break;
		case mMagnifications:
			if (map == NULL) break;
			set_map_mag(map, menuitem - 1);
			break;
		case mMaterialTypes:
			if (map == NULL) break;
			toggle_map_materials(map, menuitem - 1);
			break;
		case mOptTerrainTypes:
			if (map == NULL) break;
			toggle_map_aux_terrain(map, map->vp->aux_terrain_types[menuitem]);
			break;
		case mPlanTypes:
			tmp_plan_type = PLAN_NONE;
			switch (menuitem)  {
				case miPlanTypeNone:
					tmp_plan_type = PLAN_NONE;
					break;
				case miPlanTypePassive:
					tmp_plan_type = PLAN_PASSIVE;
					break;
				case miPlanTypeDefensive:
					tmp_plan_type = PLAN_DEFENSIVE;
					break;
				case miPlanTypeExploratory:
					tmp_plan_type = PLAN_EXPLORATORY;
					break;
				case miPlanTypeOffensive:
					tmp_plan_type = PLAN_OFFENSIVE;
					break;
				case miPlanTypeRandom:
					tmp_plan_type = PLAN_RANDOM;
					break;
			}
			do_plan_type_mi();
			break;
	}
	HiliteMenu(0);
}

/* Display the "About..." box. */

void
do_about_box()
{
	short ditem;
	Str255 tmpstr;
	WindowPtr win;
	PicHandle pic;
	short itemtype;  Handle itemhandle;  Rect itemrect;

	win = GetNewDialog(dAbout, NULL, (DialogPtr) -1L);
	/* Fill in the kernel's version and copyright. */
	GetDItem(win, diAboutVersion, &itemtype, &itemhandle, &itemrect);
	c2p(version_string(), tmpstr);
	SetIText(itemhandle, tmpstr);
	GetDItem(win, diAboutCopyright, &itemtype, &itemhandle, &itemrect);
	c2p(copyright_string(), tmpstr);
	SetIText(itemhandle, tmpstr);
	/* Substitute a color picture if we've got a color/gray screen. */
	if (hasColorQD) {
		GetDItem(win, diAboutPicture, &itemtype, &itemhandle, &itemrect);
		if ((pic = (PicHandle) GetResource('PICT', pSplashColor)) != nil) {
			SetDItem(win, diAboutPicture, itemtype, (Handle) pic, &itemrect);
		}
	}
	ShowWindow(win);
	SelectWindow(win);
	draw_default_button(win, diAboutOK);
	SetCursor(&QD(arrow));
	ModalDialog(NULL, &ditem);
	/* Just return, no matter what input. */
	HideWindow(win);
	DisposeDialog(win);
	update_all_map_windows();
}

/* This routine does both "save" and "save as". */

void
save_the_game(int askname, int quitting)
{
	Point pnt;
	char namebuf[256];
	Str255 tmpstr;
    SFReply reply;

#ifdef DESIGNERS
	/* Do the selective save only if we're not shutting down Xconq. */
	if (is_designer(dside) && !quitting) {
		designer_save_dialog();
		return;
	}
#endif
	if (askname || cursavename == NULL) {
		if (cursavename == NULL)
		  cursavename = saved_game_filename();
		/* Collect the file and path to save to. */
		SetPt(&pnt, 100, 100);
		c2p(cursavename, tmpstr);
		SFPutFile(pnt, "\pSave game as:", tmpstr, /*(DlgHookProcPtr)*/ nil, &reply);
		if (!reply.good)
		  return;
		/* Make the location of the file be the current volume. */
		SetVol(reply.fName, reply.vRefNum);
		p2c(((char *) reply.fName), namebuf);
		cursavename = copy_string(namebuf);
	}
	SetCursor(*watchcursor);
	write_entire_game_state(cursavename);
	set_game_file_type(cursavename);
	SetCursor(&QD(arrow));
}

/*THPrint printrecordhandle = nil;*/

void
maybe_init_print()
{
/*	if (printrecordhandle == nil) {
		printrecordhandle = (THPrint) NewHandle(sizeof(TPrint));
		PrOpen();
		PrintDefault(printrecordhandle);
	} */
}

void
do_page_setup_mi()
{
	maybe_init_print();
/*	PrStlDialog(printrecordhandle); */
}

/* Handle printing.  What gets printed depends on which window is in front. */

static void
do_print_mi()
{
	Map *map;
	List *list;

	maybe_init_print();
/*	if (!PrJobDialog(printrecordhandle)) return; */
	if ((map = map_from_window(FrontWindow())) != NULL) {
		print_map(map);
	} else if ((list = list_from_window(FrontWindow())) != NULL) {
		print_list(list);
	} else {
		/* (should at least be able to print help) */
	}
}

static void
resign_the_game(int forced)
{
	Str255 tmpstr;

	sprintf(tmpbuf, "Other players");
	c2p(tmpbuf, tmpstr);
	ParamText(tmpstr, "\p", "\p", "\p");
	switch (CautionAlert(aResignGame, nil)) {
		case aiResignGameOK:
			forcedtoresign = forced;
			net_resign_game(dside, NULL);
			break;
		case aiResignGameWillingToDraw:
			net_set_willing_to_draw(dside, TRUE);
			break;
		case aiResignGameCancel:
			break;
	}
}

/* Attempt to quit. */

void
quit_the_game()
{
	int confirmresign = FALSE;

#ifdef DESIGNERS
	/* If we're designing, need only confirm the save before quitting;
	   no resignation requirement. */
	if (is_designer(dside)) {
		switch (CautionAlert(aDesignerQuitGame, nil)) {
			case aiDesignerQuitGameOK:
				SetCursor(*watchcursor);
				save_the_game(FALSE, TRUE);
				SetCursor(&QD(arrow));
				/* Fall through to exit. */
			case aiDesignerQuitGameDontSave:
				exit_macconq();
				break;
			case aiDesignerQuitGameCancel:
				break;
		}
		return;
	}
#endif /* DESIGNERS */
	if (endofgame) {
		/* Game is already over, nothing to save, just leave. */
		exit_macconq();
	} else if (!gamestatesafe || !interfacestatesafe) {
		switch (CautionAlert(aQuitGame, nil)) {
			case aiQuitGameOK:
				if (all_others_willing_to_save(dside)) {
					SetCursor(*watchcursor);
					save_the_game(FALSE, TRUE);
					SetCursor(&QD(arrow));
					exit_macconq();
				} else {
					net_set_willing_to_save(dside, TRUE);
					/* (should warn that not all were willing to save) */
				}
				break;
			case aiQuitGameDontSave:
				if (all_others_willing_to_quit(dside)) {
					net_set_willing_to_draw(dside, TRUE);
				} else {
					/* Can only get out by resigning. */
					confirmresign = TRUE;
				}
				break;
			case aiQuitGameCancel:
				break;
		}
	} else {
		/* (should still confirm that we're not avoiding our fate?) */
		exit_macconq();
	}
	if (confirmresign) {
		resign_the_game(TRUE);
	}
}

static void
te_cut(TEHandle hdl)
{
	if (ZeroScrap() == noErr) {
		TECut(hdl);
		if (TEToScrap() != noErr)
		  ZeroScrap();
	}
}

static void
te_copy(TEHandle hdl)
{
	if (ZeroScrap() == noErr) {
		TECopy(hdl);
		if (TEToScrap() != noErr)
		  ZeroScrap();
	}
}

static void
te_paste(TEHandle hdl)
{
	if (TEFromScrap() == noErr) {
		TEPaste(hdl);
	}
}

static void
do_select_all_mi()
{
	Map *map;
	Unit *unit;

	if (FrontWindow() == commandwin) {
		/* (should add this) */
	} else if (FrontWindow() == constructionwin) {
		/* (should add this) */
	} else if ((map = map_from_window(FrontWindow())) != NULL) {
		for_all_units(unit) {
			if (side_may_select(unit)) {
				select_unit_on_map(map, unit);
			}
		}
		/* Do all the drawing at once. */
		draw_selections(map);
	} else if (0 /* is list */) {
	}
}

static void
do_find_previous_mi()
{
	Map *map;
	
	if ((map = map_from_window(FrontWindow())) != NULL) {
		select_previous_unit(map);
	}
}

static void
do_find_next_mi()
{
	Map *map;
	
	if ((map = map_from_window(FrontWindow())) != NULL) {
		select_next_mover(map);
	}
}

static int find_location_dialog(int *xp, int *yp);
static int find_unit_dialog(Unit **unitp);
static int find_something(Side *side, char *str, int findunit, int *xp, int *yp, Unit **unitp);

static void
do_find_location_mi()
{
	int x, y, oldsx, oldsy;
	Map *map;

	if (find_location_dialog(&x, &y)) {
		if (in_area(x, y)) {
			if ((map = map_from_window(FrontWindow())) != NULL) {
				set_view_focus(map->vp, x, y);
				/* (should make a common routine for this?) */
				if (!in_middle(map, x, y)) {
					oldsx = map->vp->sx;  oldsy = map->vp->sy;

					set_view_focus(map->vp, x, y);
					m_center_on_focus(map);

					/* Scroll offscreen instead of forcing update */
					scroll_map_window(map, map->vp->sx - oldsx, map->vp->sy - oldsy);
				}
			}
		} else {
			beep();
		}
	}
}

static void
do_find_unit_by_name_mi()
{
	int x, y;
	Unit *unit;
	
	if (find_unit_dialog(&unit)) {
		if (unit != NULL) {
			scroll_best_map_to_unit(unit, TRUE);
		} else {
			beep();
		}
	}
}

static int
find_location_dialog(int *xp, int *yp)
{
	short done = FALSE, ditem, rslt;
	DialogPtr win;
	short itemtype;  Handle itemhandle;  Rect itemrect;

	rslt = FALSE;
	*xp = *yp = -1;
	win = GetNewDialog(dFindLocation, NULL, (DialogPtr) -1L);
	ShowWindow(win);
	while (!done) {
		draw_default_button(win, diFindLocationOK);
		SetCursor(&QD(arrow));
		ModalDialog(NULL, &ditem);
		switch (ditem) {
			case diFindLocationOK:
				GetDItem(win, diFindLocationText, &itemtype, &itemhandle, &itemrect);
				rslt = find_something(dside, get_string_from_item(itemhandle), 0, xp, yp, NULL);
				if (rslt)
				  done = TRUE;
				else
				  beep();
				break;
			case diFindLocationCancel:
				done = TRUE;
				break;
		}
	}
	DisposeDialog(win);
	update_all_map_windows();
	return rslt;
}

static int
find_unit_dialog(Unit **unitp)
{
	short done = FALSE, ditem, rslt;
	DialogPtr win;
	short itemtype;  Handle itemhandle;  Rect itemrect;

	rslt = FALSE;
	*unitp = NULL;
	win = GetNewDialog(dFindUnit, NULL, (DialogPtr) -1L);
	ShowWindow(win);
	while (!done) {
		draw_default_button(win, diFindUnitOK);
		SetCursor(&QD(arrow));
		ModalDialog(NULL, &ditem);
		switch (ditem) {
			case diFindUnitOK:
				GetDItem(win, diFindUnitText, &itemtype, &itemhandle, &itemrect);
				rslt = find_something(dside, get_string_from_item(itemhandle), 1, NULL, NULL, unitp);
				if (rslt)
				  done = TRUE;
				else
				  beep();
				break;
			case diFindUnitCancel:
				done = TRUE;
				break;
		}
	}
	DisposeDialog(win);
	update_all_map_windows();
	return rslt;
}

/* (should make generic) */
static int
find_something(Side *side, char *str, int findunit, int *xp, int *yp, Unit **unitp)
{
	Unit *unit;
	Feature *feature;

	if (empty_string(str))
	  return FALSE;
	if (findunit) {
		/* Thumb through the side's own units first. */
		for_all_side_units(side, unit) {
			if (in_play(unit)
				&& !empty_string(unit->name)
				&& strcmp(str, unit->name) == 0) {
				*unitp = unit;
				return TRUE;
			}
		}
		/* Look for other units that this side might know about. */
		for_all_units(unit) {
			if (in_play(unit)
				&& !empty_string(unit->name)
				&& strcmp(str, unit->name) == 0
				&& side_sees_image(side, unit)) {
				*unitp = unit;
				return TRUE;
			}
		}
	} else {
		if (isdigit(*str)) {
			if (sscanf(str, "%d,%d", xp, yp) == 2
				&& in_area(*xp, *yp))
			  return TRUE;
		} else {
			/* Look for a geographical feature. */
			/* Exact matches first, then approximate. */
    		for_all_features(feature) {
				if (feature->name && strcmp(feature->name, str) == 0) {
					*xp = feature->x;  *yp = feature->y;
					return TRUE;
				}
    		}
    		for_all_features(feature) {
				if (feature->name && strstr(feature->name, str) == 0) {
					*xp = feature->x;  *yp = feature->y;
					return TRUE;
				}
    		}
		}
	}
	return FALSE;
}

static void
do_find_selected_mi()
{
	Map *map;
	List *list;
	UnitCloseup *closeup;
	
	if ((map = map_from_window(FrontWindow())) != NULL) {
		int i;
		Unit *unit;

		/* Scroll to the first valid selected unit we find. */
		for (i = 0; i < map->numselections; ++i) {
			unit = map->selections[i];
			if (in_play(unit)) {
				scroll_to_unit(map, unit);
				return;
			}
		}
		beep();
	} else if ((list = list_from_window(FrontWindow())) != NULL) {
		scroll_to_selected_unit_in_list(list);
	} else if ((closeup = unit_closeup_from_window(FrontWindow())) != NULL) {
		if (closeup->unit != NULL)
		  scroll_best_map_to_unit(closeup->unit, TRUE);
	} else if (constructionwin == FrontWindow()) {
		scroll_to_selected_construction_unit();
	} else {
		/* nothing to do */
	}
}

/* Menu items/commands for unit play action. */

void
apply_to_all_selected(int (*fn)(Unit *unit), int beepfailure)
{
	int i, rslt, numcould = 0, numnot = 0;
	Map *map;  List *list;  UnitCloseup *closeup;
	Unit *unit;

	if (fn == NULL)
	  return;
	if ((map = map_from_window(FrontWindow())) != NULL) {
		for (i = 0; i < map->numselections; ++i) {
			unit = map->selections[i];
			if (in_play(unit)) {
				rslt = (*fn)(unit);
				if (rslt)
				  ++numcould;
				else
				  ++numnot;
			}
		}
	} else if ((list = list_from_window(FrontWindow())) != NULL) {
		if ((unit = (Unit *) selected_unit_in_list(list)) != NULL) {
			rslt = (*fn)(unit);
			if (rslt)
			  ++numcould;
			else
			  ++numnot;
		}
	} else if ((closeup = unit_closeup_from_window(FrontWindow())) != NULL) {
		if ((unit = closeup->unit) != NULL) {
			rslt = (*fn)(unit);
			if (rslt)
			  ++numcould;
			else
			  ++numnot;
		}
	} else if (maplist != NULL) {
		map = maplist;
		for (i = 0; i < map->numselections; ++i) {
			unit = map->selections[i];
			if (in_play(unit)) {
				rslt = (*fn)(unit);
				if (rslt)
				  ++numcould;
				else
				  ++numnot;
			}
		}
	}
	/* If everybody that was asked to do this couldn't, beep once. */
	if (beepfailure && numcould == 0 && numnot > 0)
	  beep();
}

static void
do_city_dialog_mi()
{
	int i;
	Map *map;
	Unit *unit;
	
	if ((map = map_from_window(FrontWindow())) != NULL) {
		for (i = 0; i < map->numselections; ++i) {
			if ((unit = map->selections[i]) != NULL/* && u_advanced(unit->type)*/) {
				city_dialog(map, unit);				
			}
		}
	}
}

static void
do_closeup_mi()
{
	int i;
	Map *map;  List *list;  UnitCloseup *unitcloseup;
	Unit *unit;
	
	if ((map = map_from_window(FrontWindow())) != NULL) {
		for (i = 0; i < map->numselections; ++i) {
			if ((unit = map->selections[i]) != NULL) {
				if ((unitcloseup = find_unit_closeup(unit)) != NULL) {
					ShowWindow(unitcloseup->window);
					SelectWindow(unitcloseup->window);
				} else {
					create_unit_closeup(unit);
				}
			}
		}
	} else if ((list = list_from_window(FrontWindow())) != NULL) {
		if ((unit = (Unit *) selected_unit_in_list(list)) != NULL) {
			if ((unitcloseup = find_unit_closeup(unit)) != NULL) {
				ShowWindow(unitcloseup->window);
				SelectWindow(unitcloseup->window);
			} else {
				create_unit_closeup(unit);
			}
		}
	} else if ((unitcloseup = unit_closeup_from_window(FrontWindow())) != NULL) {
		if ((unit = unitcloseup->unit) != NULL) {
			force_update(unitcloseup->window);
		}
	}
}

int
do_down_command()
{
	int i, numcould = 0, numnot = 0;
	int rawamt, amt, newalt;
	Point target;
	Map *map;
	Unit *unit;

	rawamt = 0;	
	if ((map = map_from_window(FrontWindow())) != NULL) {
		for (i = 0; i < map->numselections; ++i) {
			if ((unit = map->selections[i]) != NULL && valid_selection(unit)) {
				amt = rawamt;
				if (amt == 0 && unit_alt(unit) > 0)
				  amt = unit_alt(unit) / 2;
				newalt = (unit_alt(unit) - amt) << 1;
				if (valid(check_move_action(unit, unit, unit->x, unit->y, newalt))) {
					net_prep_move_action(unit, unit, unit->x, unit->y, newalt);
					++numcould;
				} else {
					++numnot;
				}
			}
		}
	}
	/* If nobody could do the action, beep once. */
	if (numcould == 0 && numnot > 0) {
		beep();
		return FALSE;
	} else {
		return TRUE;
	}
}

static void
do_overrun_mi()
{
	/* (should loop until mouse clicked in map) */
	beep();
}

static void
do_detonate_mi()
{
	apply_to_all_selected(do_one_detonate, TRUE);
}

static void
do_give_unit_mi(int mi)
{
	Side *side = side_n(mi);
	/* note that side_n returns NULL for mi == numsides */

    tmpcmdside = side;	
	apply_to_all_selected(do_one_give_unit, TRUE);
}

static void
moveonclick_mi()
{
	Map *frontmap = map_from_window(FrontWindow());

	if (frontmap) {

// --- NEW BUG FIX --------------------------------

//		toggle_survey(frontmap);
	
		frontmap->moveonclick = !frontmap->moveonclick;

		/* (should force updates of map windows to reflect?) */

// --- BUG FIX ------------------------------------

		/* Necessary or the control panel will get out of sync! */
		draw_control_panel(frontmap);

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

	} else {
		defaultmoveonclick = !defaultmoveonclick;
	}
}

void
do_plan_type_mi()
{
	apply_to_all_selected(do_one_plan_type, TRUE);	
}

static int
do_one_plan_type(Unit *unit)
{
    int newval;

	if (unit->plan) {
		newval = tmp_plan_type;
		net_set_unit_plan_type(dside, unit, newval);
	}
	return TRUE;
}

static void
do_take_mi()
{
	apply_to_all_selected(do_one_take, TRUE);
}

int
do_up_command()
{
	int i, numcould = 0, numnot = 0;
	int rawamt, amt, newalt;
	Point target;
	Map *map;
	Unit *unit;

	rawamt = 1;
	if ((map = map_from_window(FrontWindow())) != NULL) {
		for (i = 0; i < map->numselections; ++i) {
			if ((unit = map->selections[i]) != NULL && valid_selection(unit)) {
				amt = rawamt;
				newalt = (unit_alt(unit) + amt) << 1;
				if (valid(check_move_action(unit, unit, unit->x, unit->y, newalt))) {
					net_prep_move_action(unit, unit, unit->x, unit->y, newalt);
					++numcould;
				} else {
					++numnot;
				}
			}
		}
	}
	/* If nobody could do the action, beep once. */
	if (numcould == 0 && numnot > 0) {
		beep();
		return FALSE;
	} else {
		return TRUE;
	}
}

static void
autoselect_mi()
{
	Map *frontmap = map_from_window(FrontWindow());
	extern Unit *curunit;

	if (frontmap) {
		frontmap->autoselect = !frontmap->autoselect;
		frontmap->curunit = NULL; /* maybe not a good idea? */
		/* (should force updates of map windows to reflect?) */
	} else {
		defaultautoselect = !defaultautoselect;
	}
}

static void
adjust_menu_item(MenuHandle menu, int item, int value)
{
	if (value)
	  EnableItem(menu, item);
	else
	  DisableItem(menu, item);
}

/* The state of menu items changes to reflect selected units, etc. */

void
adjust_menus()
{
	int i, m, t, numwins, menus_useful, numitems, text_win, has_text, offset;
	MenuHandle menu, menu2;
	Map *frontmap;
	List *frontlist;
	UnitCloseup *frontcloseup;
	Unit *unit;
	WindowPtr frontwin;

	frontwin = FrontWindow();
	frontmap = map_from_window(frontwin);
	frontlist = list_from_window(frontwin);
	frontcloseup = unit_closeup_from_window(frontwin);
	menus_useful =
		(gamedefined
		 && ((!beforestart && !endofgame)
		 	 || (gameinited && is_designer(dside))));
	/* Certain menus need to be built after the game is running. */
	if (menus_useful) {
		build_material_type_menu();
		build_side_menu();
		build_ai_type_menu();
	}
#if 0
	if (is_da_window(FrontWindow())) {
		if ((menu = GetMHandle(mEdit)) != nil) {
		}
		return;
	}
#endif
	menu = GetMHandle(mApple);
	if (menu != nil) {
		adjust_menu_item(menu, miAppleInstructions, gamedefined);
	}
	menu = GetMHandle(mFile);
	if (menu != nil) {
		/* Availability of file menu items depends on whether we're in a game. */
		adjust_menu_item(menu, miFileNew, !gamedefined);
		adjust_menu_item(menu, miFileOpen, !gamedefined);
		adjust_menu_item(menu, miFileConnect, !gamedefined);
		adjust_menu_item(menu, miFileClose, (frontwin != NULL));
		adjust_menu_item(menu, miFileSave, menus_useful);
		adjust_menu_item(menu, miFileSaveAs, menus_useful);
		adjust_menu_item(menu, miFilePrintWindow, (frontmap != NULL || frontlist != NULL));
		adjust_menu_item(menu, miFileResign, menus_useful && dside->ingame);
	}
	menu = GetMHandle(mEdit);
	if (menu != nil) {
		/* Edit menu is always available, but individual items may be disabled. */
		adjust_menu_item(menu, miEditUndo, FALSE);
		text_win = has_text = FALSE;
		if (frontwin && frontwin == commandwin) {
			text_win = TRUE;
			has_text = ((*command_text)->selStart < (*command_text)->selEnd);
		} else if (frontwin && frontwin == constructionwin) {
			text_win = TRUE;
			has_text = ((*run_length_text)->selStart < (*run_length_text)->selEnd);
		}
		adjust_menu_item(menu, miEditCut, has_text);
		adjust_menu_item(menu, miEditCopy, has_text);
		adjust_menu_item(menu, miEditPaste, (text_win && (GetScrap(nil, 'TEXT', (long *) &offset) > 0)));
		adjust_menu_item(menu, miEditClear, has_text);
		adjust_menu_item(menu, miEditSelectAll, (frontmap != NULL || frontlist != NULL || has_text));
		if (menus_useful) {
#ifdef DESIGNERS
			CheckItem(menu, miEditDesign, is_designer(dside));
#else
			DisableItem(menu, miEditDesign);
#endif /* DESIGNERS */
		}
	}
	menu = GetMHandle(mFind);
	if (menu != nil) {
		if (gameinited) {
			EnableItem(menu, 0);
			adjust_menu_item(menu, miFindPrevious, menus_useful);
			adjust_menu_item(menu, miFindNext, menus_useful);
			DisableItem(menu, miFindNextOccupant);
			adjust_menu_item(menu, miFindLocation, menus_useful);
			adjust_menu_item(menu, miFindUnitByName, menus_useful);
			adjust_menu_item(menu, miFindDistance, menus_useful);
			adjust_menu_item(menu, miFindSelected, (frontmap != NULL || frontlist != NULL || frontcloseup != NULL || constructionwin == frontwin));
		} else {
			/* We're not even in a game yet, turn entire menu off. */
			DisableItem(menu, 0);
		}
	}
	menu = GetMHandle(mPlay);
	menu2 = GetMHandle(mMore);
	if (menu != nil && menu2 != nil) {
		if (gameinited) {
			EnableItem(menu, 0);
			/* Disable everything first, then selectively re-enable. */
			DisableItem(menu, miPlayCloseup);
			DisableItem(menu, miPlayCityDialog);
			DisableItem(menu, miPlayMove);
			DisableItem(menu, miPlaySetFormation);
			DisableItem(menu, miPlayReturn);
			DisableItem(menu, miPlayWake);
			DisableItem(menu, miPlaySleep);
			DisableItem(menu, miPlayReserve);
			DisableItem(menu, miPlayDelay);
			DisableItem(menu, miPlayBuild);
			DisableItem(menu, miPlayRepair);
			DisableItem(menu, miPlayAttack);
			DisableItem(menu, miPlayOverrun);
			DisableItem(menu, miPlayFire);
			DisableItem(menu, miPlayFireInto);
			DisableItem(menu, miPlayDetonate);
			EnableItem(menu2, 0);
			DisableItem(menu2, miMoreGive);
			DisableItem(menu2, miMoreTake);
			DisableItem(menu2, miMoreEmbark);
			DisableItem(menu2, miMoreDisembark);
			DisableItem(menu2, miMoreDrop);
			DisableItem(menu2, miMoreGiveUnit);
			DisableItem(menu2, miMoreDetach);
			DisableItem(menu2, miMoreDisband);
			DisableItem(menu2, miMoreAddTerrain);
			DisableItem(menu2, miMoreRemoveTerrain);
			DisableItem(menu2, miMorePlanTypes);
			DisableItem(menu2, miMoreAIControl);
			DisableItem(menu2, miMoreRename);
			/* Note that command enabling is accumulative for all units; if at least
			   one of the selected units can do something, the menu item turns on. */
			if (frontmap != NULL) {
				for (i = 0; i < frontmap->numselections; ++i) {
					if ((unit = frontmap->selections[i]) != NULL) {
						enable_commands_for_unit(menu, menu2, unit);
					}
				}
			} else if (frontlist != NULL) {
				if ((unit = (Unit *) selected_unit_in_list(frontlist)) != NULL) {
					enable_commands_for_unit(menu, menu2, unit);
				}
			} else if (frontcloseup != NULL) {
				if ((unit = frontcloseup->unit) != NULL) {
					enable_commands_for_unit(menu, menu2, unit);
				}
			}
		} else {
			/* We're not even in a valid game state yet, turn entire menus off. */
			DisableItem(menu, 0);
			DisableItem(menu2, 0);
		}
	}
	menu = GetMHandle(mSide);
	if (menu != nil) {
		if (menus_useful) {
			EnableItem(menu, 0);
			CheckItem(menu, miSideMoveOnClick,
					  (frontmap ? frontmap->moveonclick : defaultmoveonclick));
			CheckItem(menu, miSideAutoSelect,
					  (frontmap ? frontmap->autoselect : defaultautoselect));
			CheckItem(menu, miSideAutoFinish, dside->autofinish);
			CheckItem(menu, miSideSound, playsounds);
			DisableItem(menu, miSideGlobalAdvance);
			for_all_side_units(dside, unit) {
				if (u_advanced(unit->type)) {
					EnableItem(menu, miSideGlobalAdvance);
					break;
				}
			}
			if (dside->nameslocked) {
				DisableItem(menu, miSideRename);
			} else {
				EnableItem(menu, miSideRename);
			}
		} else {
			/* We're not even in a game yet, turn entire menu off. */
			DisableItem(menu, 0);
		}
	}
	menu = GetMHandle(mWindows);
	if (menu != nil) {
		if (gameinited) {
			EnableItem(menu, 0);
			/* Most window types are always enabled. */
			CheckItem(menu, miWindowsGame,
				(gamewin && ((WindowPeek) gamewin)->visible));
			CheckItem(menu, miWindowsNotices,
				(noticewin && ((WindowPeek) noticewin)->visible));
			CheckItem(menu, miWindowsHistory,
				(historywin && ((WindowPeek) historywin)->visible));
			CheckItem(menu, miWindowsCommand,
				(commandwin && ((WindowPeek) commandwin)->visible));
			if (any_construction_possible()) {
				EnableItem(menu, miWindowsConstruction);
				CheckItem(menu, miWindowsConstruction,
					(constructionwin && ((WindowPeek) constructionwin)->visible));
			} else {
				DisableItem(menu, miWindowsConstruction);
			}
			CheckItem(menu, miWindowsScores,
				(scoreswin && ((WindowPeek) scoreswin)->visible));
			CheckItem(menu, miWindowsWorldMap, worldmapwin && worldmapwin == frontwin);

			/* Go through all the user-added windows. */
			numwins = CountMItems(menu) - miWindowsFirst + 1;		
			/* (miWindowsFirst equals the number of windows + 1) */
			for (i = 0; i < numwins; ++i) {
				CheckItem(menu, i + miWindowsFirst, (winmenuwins[i] == frontwin));
			}
		} else {
			/* We're not even in a game yet, turn entire menu off. */
			DisableItem(menu, 0);
		}
	}
	menu = GetMHandle(mColors);
	if (menu != nil) {
		EnableItem(menu, 0);

	}
	/* If a map window is frontmost, install and adjust the map view menu. */
	if (frontmap != NULL) {
		/* Delete the list view menu if that's what's installed currently. */
		menu = GetMHandle(mViewList);
		if (menu != nil)
		  DeleteMenu(mViewList);
		/* Make sure the map view menu is installed (is always at the end). */
		InsertMenu(mapviewmenu, 0);
		menu = GetMHandle(mViewMap);
		if (menu != nil) {
			EnableItem(menu, 0);
			if (frontmap->vp->power == 0) {
				DisableItem(menu, miViewFarther);
			} else {
				EnableItem(menu, miViewFarther);
			}
			if (frontmap->vp->power == NUMPOWERS-1) {
				DisableItem(menu, miViewCloser);
			} else {
				EnableItem(menu, miViewCloser);
			}
			EnableItem(menu, miViewOffscreen);
			if (people_sides_defined()) {
				EnableItem(menu, miViewPeople);
				CheckItem(menu, miViewPeople, frontmap->vp->draw_people);
			} else {
				DisableItem(menu, miViewPeople);
			}
			if (control_sides_defined()) {
				EnableItem(menu, miViewControl);
				CheckItem(menu, miViewControl, frontmap->vp->draw_control);
			} else {
				DisableItem(menu, miViewControl);
			}
			if (elevations_defined()) {
				EnableItem(menu, miViewElevations);
				CheckItem(menu, miViewElevations, frontmap->vp->draw_elevations);
			} else {
				DisableItem(menu, miViewElevations);
			}
			if (temperatures_defined() || winds_defined() || clouds_defined()) {
				EnableItem(menu, miViewWeather);
			} else {
				DisableItem(menu, miViewWeather);
			}
			if (nummtypes > 0) {
				EnableItem(menu, miViewMaterials);
				/* (should do checkmark if anything in submenu is on) */
			} else {
				DisableItem(menu, miViewMaterials);
			}
			if (numbordtypes + numconntypes + numcoattypes > 0) {
				EnableItem(menu, miViewTerrain);
			} else {
				DisableItem(menu, miViewTerrain);
			}
			if (world.daylength != 1) {
				EnableItem(menu, miViewDaylight);
				CheckItem(menu, miViewDaylight, frontmap->vp->draw_lighting);
			} else {
				DisableItem(menu, miViewDaylight);
			}
			if (dside->coverage) {
				EnableItem(menu, miViewCoverage);
				CheckItem(menu, miViewCoverage, frontmap->vp->draw_cover);
			} else {
				DisableItem(menu, miViewCoverage);
			}
			menu = GetMHandle(mViewWeather);
			if (menu != nil) {
				EnableItem(menu, 0);
				if (temperatures_defined()) {
					EnableItem(menu, miWeatherTemperature);
					CheckItem(menu, miWeatherTemperature, frontmap->vp->draw_temperature);
				} else {
					DisableItem(menu, miWeatherTemperature);
				}
				if (winds_defined()) {
					EnableItem(menu, miWeatherWinds);
					CheckItem(menu, miWeatherWinds, frontmap->vp->draw_winds);
				} else {
					DisableItem(menu, miWeatherWinds);
				}
				if (clouds_defined()) {
					EnableItem(menu, miWeatherClouds);
					CheckItem(menu, miWeatherClouds, frontmap->vp->draw_clouds);
				} else {
					DisableItem(menu, miWeatherClouds);
				}
			}
		}
	} else if (frontlist != NULL) {
		/* Do the list view menu similarly. */
		menu = GetMHandle(mViewMap);
		if (menu != nil)
		  DeleteMenu(mViewMap);
		/* Make sure the menu is actually installed (is always at the end). */
		InsertMenu(listviewmenu, 0);
		menu = GetMHandle(mViewList);
		if (menu != nil) {
			EnableItem(menu, 0);
			if (1 /* at least one unit in list */) {
				EnableItem(menu, miViewByType);
				CheckItem(menu, miViewByType, (frontlist->mainsortmi == miViewByType));
				EnableItem(menu, miViewByName);
				CheckItem(menu, miViewByName, (frontlist->mainsortmi == miViewByName));
				EnableItem(menu, miViewBySide);
				CheckItem(menu, miViewBySide, (frontlist->mainsortmi == miViewBySide));
				EnableItem(menu, miViewByActOrder);
				CheckItem(menu, miViewByActOrder, (frontlist->mainsortmi == miViewByActOrder));
				EnableItem(menu, miViewByLocation);
				CheckItem(menu, miViewByLocation, (frontlist->mainsortmi == miViewByLocation));
				/* should mark the secondary sort? */
				EnableItem(menu, miViewCompleted);
				CheckItem(menu, miViewCompleted, frontlist->completed_units);
				EnableItem(menu, miViewIncomplete);
				CheckItem(menu, miViewIncomplete, frontlist->incomplete_units);
				EnableItem(menu, miViewWithTransport);
				DisableItem(menu, miViewWithCommander);
				EnableItem(menu, miViewIconSize);
				CheckItem(menu, miViewIconSize, frontlist->largeicons);
				EnableItem(menu, miListSideColors);
				CheckItem(menu, miListSideColors, frontlist->sidecolors);

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

				EnableItem(menu, miListDrawEmblems);
				CheckItem(menu, miListDrawEmblems, frontlist->draw_emblems);

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

			} else {
				DisableItem(menu, miViewByType);
				DisableItem(menu, miViewByName);
				DisableItem(menu, miViewBySide);
				DisableItem(menu, miViewByActOrder);
				DisableItem(menu, miViewByLocation);
				DisableItem(menu, miViewWithTransport);
				DisableItem(menu, miViewWithCommander);
				DisableItem(menu, miViewIconSize);

// --- USER CONTROL OF EMBLEMS & SIDE COLOR BUG FIX --------------------------

				DisableItem(menu, miListSideColors);
				DisableItem(menu, miListDrawEmblems);

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

			}
		}
	} else {
		/* For any other window, disable any or all of the view menus, as needed. */
		menu = GetMHandle(mViewList);
		if (menu != nil)
		  DisableItem(menu, 0);
		menu = GetMHandle(mViewMap);
		if (menu != nil)
		  DisableItem(menu, 0);
	}
	menu = GetMHandle(mMagnifications);
	if (menu != nil) {
		/* Always on. */
		EnableItem(menu, 0);
		if (frontmap != NULL) {
			for (i = 0; i < NUMPOWERS; ++i) {
				CheckItem(menu, i + 1, (i == frontmap->vp->power));
			}
		}
	}
	menu = GetMHandle(mMaterialTypes);
	if (menu != nil) {
		/* Always on, if any material types defined. */
		if (nummtypes > 0) {
			EnableItem(menu, 0);
			if (frontmap != NULL) {
				for_all_material_types(m) {
					if (any_cell_materials_defined() && cell_material_defined(m)) {
						EnableItem(menu, m + 1);
						CheckItem(menu, m + 1, frontmap->vp->draw_materials[m]);
					} else {
					    CheckItem(menu, i, FALSE);
						DisableItem(menu, m + 1);
					}
				}
			}
		} else {
			DisableItem(menu, 0);
		}
	}
	menu = GetMHandle(mOptTerrainTypes);
	if (menu != nil) {
		if (any_aux_terrain_defined()) {
			EnableItem(menu, 0);
			if (frontmap != NULL) {
				numitems = CountMItems(menu);
				for (i = 1; i <= numitems; ++i) {
					t = frontmap->vp->aux_terrain_types[i];
					if (any_aux_terrain_defined() && aux_terrain_defined(t)) {
						EnableItem(menu, i);
					    CheckItem(menu, i, frontmap->vp->draw_aux_terrain[t]);
					} else {
					    CheckItem(menu, i, FALSE);
						DisableItem(menu, i);
					}
				}
			}
		} else {
			DisableItem(menu, 0);
		}
	}
	menu = GetMHandle(mAITypes);
	if (menu != nil) {
		/* Always on. */
		EnableItem(menu, 0);
		CheckItem(menu, 1, (!side_has_ai(dside)));
		CheckItem(menu, 2, (side_has_ai(dside)));
	}
	menu = GetMHandle(mViewText);
	if (menu != nil && frontmap != NULL) {
		/* Always on. */
		EnableItem(menu, 0);
		EnableItem(menu, miTextUnitNames);
		CheckItem(menu, miTextUnitNames, ( frontmap->vp->draw_names));
		EnableItem(menu, miTextFeatureNames);
		CheckItem(menu, miTextFeatureNames, (frontmap->featurenames));
		EnableItem(menu, miTextOptimizeFonts);
		CheckItem(menu, miTextOptimizeFonts, (frontmap->optimize_fonts));
		EnableItem(menu, miTextEraseNames);
		CheckItem(menu, miTextEraseNames, (frontmap->erase_names));

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

		EnableItem(menu, miTextDrawEmblems);
		CheckItem(menu, miTextDrawEmblems, (frontmap->draw_emblems));

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

	}

	menu = GetMHandle(mViewGrids);
	if (menu != nil && frontmap != NULL) {
		/* Always on. */
		EnableItem(menu, 0);
		EnableItem(menu, miViewGrid);
		CheckItem(menu, miViewGrid, frontmap->vp->draw_grid);
		EnableItem(menu, miViewTopline);
		CheckItem(menu, miViewTopline, (frontmap->toplineh > 0));
		EnableItem(menu, miViewTopunit);
		CheckItem(menu, miViewTopunit, (frontmap->topunith > 0));
		if (nummaps > 1) {
			EnableItem(menu, miViewOtherMaps);
			CheckItem(menu, miViewOtherMaps, frontmap->vp->draw_other_maps);
		} else {
			DisableItem(menu, miViewOtherMaps);
		}

	}

	menu = GetMHandle(mViewColors);
	if (menu != nil && frontmap != NULL) {
		/* Always on. */
		EnableItem(menu, 0);
		EnableItem(menu, miSideColors);
		CheckItem(menu, miSideColors, frontmap->sidecolors);
		EnableItem(menu, miIconMasks);
		CheckItem(menu, miIconMasks, frontmap->iconmasks);
		EnableItem(menu, miBoxMasks);
		CheckItem(menu, miBoxMasks, frontmap->boxmasks);
		EnableItem(menu, miTextMasks);
		CheckItem(menu, miTextMasks, frontmap->textmasks);
		EnableItem(menu, miSolidColorTerrain);
		CheckItem(menu, miSolidColorTerrain, frontmap->solid_color_terrain);
	}

	menu = GetMHandle(mViewBorders);
	if (menu != nil && frontmap != NULL) {
		/* Always on. */
		EnableItem(menu, 0);
		EnableItem(menu, miFeatureBorders);
		CheckItem(menu, miFeatureBorders, frontmap->featureborders);
		EnableItem(menu, miShoreLines);
		CheckItem(menu, miShoreLines, frontmap->shorelines);
		EnableItem(menu, miSimpleBorders);
		CheckItem(menu, miSimpleBorders, frontmap->simple_borders);
	}
	/* Everything has been tweaked, redraw the menu bar. */
	DrawMenuBar();
}

/* Tweak the command menu according to what the unit can do. */
/* (some of these should have the menu text tweaked also, terms weird sometimes) */

int any_transport_here PARAMS ((Side *side, Unit *unit, int x, int y));

int
any_transport_here(side, unit, x, y)
Side *side;
Unit *unit;
int x, y;
{
	Unit *unit2;

	for_all_stack(x, y, unit2) {
		if (unit2 != unit
			&& unit2 != unit->transport
			&& trusted_side(side, unit2->side)
			&& can_occupy(unit, unit2)
			) {
			return TRUE;
		}
	}
	return FALSE;
}

static void
enable_commands_for_unit(MenuHandle menu, MenuHandle menu2, Unit *unit)
{
	int u = unit->type, sn;
	Side *side2;
	MenuHandle menu3;

	/* Might get dead units in here, filter them out. */
	if (!in_play(unit))
	  return;
	/* If we can select the unit at all, we can always get a closeup of it. */
	EnableItem(menu, miPlayCloseup);
	/* (how to do checkmarks if multiple units selected? use '-' as per HIG) */
	CheckItem(menu, miPlayCloseup, (find_unit_closeup(unit) != NULL));
	/* If we don't actually have any control over the unit, or the game is over,
	   nothing more to do. */

	/* Enable city dialog for advanced unit. */
	if (u_advanced(unit->type))
		EnableItem(menu, miPlayCityDialog);

	if (!side_controls_unit(dside, unit) || endofgame)
	  return;
	if (can_move_at_all(unit)) {
		EnableItem(menu, miPlayMove);
		if (nummtypes > 0) {
			/* also check that unit carries any material and for places to return to */
			EnableItem(menu, miPlayReturn);
		}
	}
	if (unit->plan) {
		EnableItem(menu, miPlaySetFormation);
		EnableItem(menu, miPlayWake);
		CheckItem(menu, miPlayWake, !unit->plan->asleep);
		EnableItem(menu, miPlaySleep);
		CheckItem(menu, miPlaySleep, unit->plan->asleep);
		EnableItem(menu, miPlayReserve);
		CheckItem(menu, miPlayReserve, unit->plan->reserve);
		EnableItem(menu, miPlayDelay);
		CheckItem(menu, miPlayDelay, unit->plan->delayed);
		EnableItem(menu2, miMorePlanTypes);
		EnableItem(menu2, miMoreAIControl);
		CheckItem(menu2, miMoreAIControl, unit->plan->aicontrol);
		menu3 = GetMHandle(mPlanTypes);
		if (menu3 != nil) {
			EnableItem(menu3, 0);
			CheckItem(menu2, miPlanTypeNone, (unit->plan->type == PLAN_NONE));
			CheckItem(menu2, miPlanTypePassive, (unit->plan->type == PLAN_PASSIVE));
			CheckItem(menu2, miPlanTypeDefensive, (unit->plan->type == PLAN_DEFENSIVE));
			CheckItem(menu2, miPlanTypeExploratory, (unit->plan->type == PLAN_EXPLORATORY));
			CheckItem(menu2, miPlanTypeOffensive, (unit->plan->type == PLAN_OFFENSIVE));
			CheckItem(menu2, miPlanTypeRandom, (unit->plan->type == PLAN_RANDOM));
		}
	}
	if ((can_create(unit) || can_complete(unit))
		&& (unit->transport == NULL
			|| !completed(unit->transport)
			|| uu_occ_can_build(unit->transport->type, u))
		|| can_research(unit)) {
		EnableItem(menu, miPlayBuild);
	}
	if (can_repair(unit)) {
		EnableItem(menu, miPlayRepair);
	}
	if (can_attack(unit)) {
		EnableItem(menu, miPlayAttack);
		EnableItem(menu, miPlayOverrun);
	}
	if (can_fire(unit)) {
		EnableItem(menu, miPlayFire);
		EnableItem(menu, miPlayFireInto);
	}
	if (can_detonate(unit)) {
		EnableItem(menu, miPlayDetonate);
	}
	if (nummtypes > 0 /* (should also test unit capacity) */) {
		EnableItem(menu2, miMoreGive);
		EnableItem(menu2, miMoreTake);
	}
	if (any_transport_here(dside, unit, unit->x, unit->y)) {
		EnableItem(menu2, miMoreEmbark);
	}
	if (unit->transport != NULL) {
		EnableItem(menu2, miMoreDisembark);
	}
	/* (should decide what to do about Drop) */
	if (num_sides_allowed(u) > 1 || is_designer(dside)) {
		EnableItem(menu2, miMoreGiveUnit);
	}
	if (side_can_disband(dside, unit)) {
		EnableItem(menu2, miMoreDisband);
	}
	if (u_parts(u) > 1 && unit->hp > 1) {
		EnableItem(menu2, miMoreDetach);
	}
	if (can_add_terrain(unit)) {
		EnableItem(menu2, miMoreAddTerrain);
	}
	if (can_remove_terrain(unit)) {
		EnableItem(menu2, miMoreRemoveTerrain);
	}
	if (1 /* !unitnameslocked */) {
		EnableItem(menu2, miMoreRename);
	}
	/* Adjust the Find menu. */
	menu3 = GetMHandle(mFind);
	if (menu3 != nil) {
		if (gameinited) {
			adjust_menu_item(menu3, miFindNextOccupant, (unit->occupant || unit->nexthere || unit->transport));
		}
	}
	/* Adjust the give unit menu. */
	menu3 = GetMHandle(mSides);
	if (menu3 != nil) {
		if (num_sides_allowed(u) > 1 || is_designer(dside)) {
			EnableItem(menu3, 0);
			for_all_sides_plus_indep(side2) {
				sn = (side2 == indepside ? numsides + 1 : side2->id);
				if (unit_allowed_on_side(unit, side2)
					&& !(unit->side == side2 || (unit->side == NULL && side2 == indepside))) {
					EnableItem(menu3, sn);
				} else {
					DisableItem(menu3, sn);
				}
			}
		} else {
			DisableItem(menu3, 0);
		}
	}
}

