implementation module ProjectWindowDialog;

import StdClass,StdString, StdInt,StdArray,StdBool,StdChar;
import deltaIOSystem, deltaDialog, deltaControls, deltaPicture, deltaFont, deltaIOState;

import	EdProgramState, EdConstants, EdFileMenu, EdProject, EdDialogs, EdWindowsMenu, EdPath,
		EdDrawWindow, EdTextWindow, EdLists, EdMyIO, ProjectWindowAux;

	DProjectWdID	:== 15;
	DModInfoID		:== 16;

	PSPTitleID		:== 1;
	PSPMainID		:== 2;
	PDPMainID		:== 3;
	PSPCurID		:== 4;
	PDPCurID		:== 5;
	PPModsID		:== 6;
	POpenDefID		:== 7;
	POpenImpID		:== 8;
	PSetMainID		:== 9;
	PInfoID			:== 10;
	PDateID			:== 11;
	PCloseID		:== 12;
	
	ExampleChar		:== 'W';
	CharWidth		:== 8;
	ListBoxMargin	:== 10.0;
	NrItems			:== 7;
	
	ISPTitleID		:== 12;
	IRModsID		:== 13;
		RIDclID		:== 131;
		RIIclID		:== 132;
		RIAbcID		:== 133;
		RIObjID		:== 134;
	ISPImportsID	:== 14;
	IPImportsID		:== 15;
	IRTypeID		:== 16;
		RIOptID		:== 161;
		RIFileID	:== 162;
		RISysID		:== 163;
	IDTextsID		:== 17;
//	IDTextsBTID		:== 18;
	ICCloseID		:== 19;
	
	TextLength		:== 13;
	TextWid			:== 390;
	
	ButHgt			:== 20;
	
	DynButStrs		:== "Change..." :! "More..." :! "Info" :! Nil;
						
::	Strings	=	{	legend	:: !String,
					value	:: !String };

OpenProjectWindowDialog :: !ProgState !IO -> ProgIO;
OpenProjectWindowDialog prog=:{editor={editwindows,project}} io
	= OpenModalDialog dialog prog io;
	where {
	dialog= CommandDialog DProjectWdID title [] PCloseID
				[st0,st1,dt1,sl1,st2,dt2,bt1,bt2,bt3,bt4,bt5,bt6];
	st0	= StaticText	PSPTitleID	Center							title;
	st1	= StaticText	PSPMainID	Center							"Main Module: ";
	dt1	= DynamicText	PDPMainID	(RightTo PSPMainID) (MM 40.0)	root;
	sl1 = ScrollingList PPModsID 	Left ListBoxW able NrItems root modlist`		SetSelectedModule;
	st2	= StaticText	PSPCurID	(Below PPModsID)				"Selected Module: ";
	dt2	= DynamicText	PDPCurID	(RightTo PSPCurID) (MM 40.0)	root;
	bt1	= DialogButton	POpenDefID	(RightTo PPModsID) 		"Open .dcl"		able	(OpenMod DclMod);
	bt2	= DialogButton	POpenImpID	(Below POpenDefID) 		"Open .icl"		able	(OpenMod IclMod);
	bt3	= DialogButton	PSetMainID	Left					"Select Main"	able	(SetMod root modlist`);
	bt4	= DialogButton	PInfoID		(RightTo PSetMainID)	"Info..."		able	ShowModInfo;
	bt5	= DialogButton	PDateID		(RightTo PInfoID)		"Check Up To Date" able	ExecUpToDate;
	bt6	= DialogButton	PCloseID	(RightTo PDateID)		"OK"			Able	ClosePrjDialog;
	projectwd			= GetWindow ProjectWdID editwindows;
	root				= PR_GetRootModuleName project;
	modlist`			= MakeLazySortedList modlist;
	modlist				= PR_GetModulenames False IclMod project;
	title				= "Project: " +++ RemovePath (projectwd.wstate.pathname);
	able				= BoolToSelect (PR_ProjectSet project);
	};

SetSelectedModule :: !DialogInfo !(DialogState ProgState IO) -> DialogState ProgState IO;
SetSelectedModule dinfo dstate
	= ChangeDynamicText PDPCurID (GetScrollingListItem PPModsID dinfo) dstate;
	
OpenMod :: !Bool !DialogInfo !ProgState !IO -> ProgIO;
OpenMod def dinfo prog io
	= OpenModule modname EmptyTSel prog io`;
	where {
	modname	| def	= MakeDefPathname mod;
					= MakeImpPathname mod;
	mod				= GetScrollingListItem PPModsID dinfo;
	io`				= CloseActiveDialog io;
	};
	
SetMod :: !String ![String] !DialogInfo !ProgState !IO -> ProgIO;
SetMod mod mods dinfo prog io
	= (prog, io`)
	where {
	io`		= ChangeDialog DProjectWdID
				[	ChangeDynamicText PDPCurID mod,
					ChangeScrollingList PPModsID mod mods ] io;
	};
	
ClosePrjDialog :: !DialogInfo !ProgState !IO -> ProgIO;
ClosePrjDialog dinfo prog=:{editor={editwindows}} io
	| one_window	= (prog`,io`);
					= NextWindow prog` io`;
	where {
	one_window		= nextwdid == ProjectWdID;
	(nextwdid,_)	= GetNextWindow editwindows;
	(prog`,io`)		= Cancel dinfo prog io;
	};
	
ShowModInfo :: !DialogInfo !ProgState !IO -> ProgIO;
ShowModInfo dinfo prog=:{editor=ed=:{project,editwindows}} io
	= OpenModalDialog dialog prog` io`;
	where {
	dialog= CommandDialog DModInfoID mod [] ICCloseID
				[st0,rb1,dts /* ,db1 */,rb2,st1,sl1,bt1];
	st0	= StaticText	ISPTitleID	Center ("Info about '" +++ mod +++ "'");
	rb1	= RadioButtons IRModsID Left (Columns 1) RIDclID [
			RadioItem RIDclID	(mod +++ ".dcl")		Able		(ShowSelectedModule peo info),
			RadioItem RIIclID	(mod +++ ".icl")		Able		(ShowSelectedModule peo info),
			RadioItem RIAbcID	(mod +++ ".abc")		Able		(ShowSelectedModule peo info),
			RadioItem RIObjID	(mod +++ ".obj")		Able		(ShowSelectedModule peo info) ];
	dts	= MakeDynamicStrings IDTextsID (RightTo IRModsID) peo text;
//	db1	= MakeDynamicButton IDTextsBTID (Below IRModsID) "Change..." DynButStrs (Compiler_and_EditOptions` DclMod info);
	rb2	= RadioButtons IRTypeID Center (Rows 1) RIOptID [
			RadioItem RIOptID	"Compiler & Edit Options"	Able	(ShowSelectedModule peo info),
			RadioItem RIFileID	"File Info"					Able	(ShowSelectedModule peo info),
			RadioItem RISysID	"ABC Sys. Info"				Unable	(ShowSelectedModule peo info) ];
	st1	= StaticText ISPImportsID Left "Imports:";
	sl1 = ScrollingList IPImportsID (XOffset ISPImportsID (MM 1.0)) ListBoxW Able NrItems "" imports DFIdle;
	bt1	= DialogButton	ICCloseID	Right "OK"	Able	Cancel;
	mod				= GetScrollingListItem PPModsID dinfo;
	projectwd		= GetWindow ProjectWdID editwindows;
	((prog`,info), io`)	= accFiles (ReadInfo True mod project prog) io;
	text			= ModInfoToText RIOptID RIDclID info;
	imports			= [];
	peo				= EW_GetEditOptions projectwd;
	};
	
ShowSelectedModule :: !EditOptions !Info !DialogInfo !(DialogState ProgState IO) -> DialogState ProgState IO;
ShowSelectedModule	po info=:{path,modinfo={deps}}
					dinfo dstate
	= ChangeDynamicStrings IDTextsID po text dstate`;
	where {
	dstate`	| showabc			= ChangeScrollingList IPImportsID "" (MakeLazySortedList deps) dstate3;
								= ChangeScrollingList IPImportsID "" [] dstate3;
	dstate3						= /* button */ dstate2;
	dstate2						= EnableDialogItems enable` (DisableDialogItems disable` dstate1);
	dstate1						= SelectDialogRadioItem select dstate;
	text						= ModInfoToText select mod info;
	enable`	| showabc			= [RISysID];
			| showsrc			= [RIOptID];
								= [];
	disable`| showabc			= [RIOptID];
			| showobj			= [RIOptID,RISysID];
			| showsrc			= [RISysID];
								= [];
//	button dstate
//		| (showabc && not showsys) || (showicl && (showfile || showsys))
//								= ChangeDynamicButton IDTextsBTID "More..." DynButStrs (ShowOutOfDate True po info) dstate;
//		| showopt && showsrc	= ChangeDynamicButton IDTextsBTID "Change..." DynButStrs (Compiler_and_EditOptions` showdcl info) dstate;
//								= ChangeDynamicButton IDTextsBTID "" DynButStrs ButIdle dstate;
	select	| showabc && showopt= RIFileID;
			| showobj			= RIFileID;
			| showsrc && showsys= RIFileID;
								= type;
	showdcl						= mod == RIDclID;
	showicl						= mod == RIIclID;
	showabc						= mod == RIAbcID;
	showobj						= mod == RIObjID;
	showsrc						= showdcl || showicl;
	showsys						= type == RISysID;
	showopt						= type == RIOptID;
	showfile					= type == RIFileID;
	mod							= GetSelectedRadioItemId IRModsID dinfo;
	type						= GetSelectedRadioItemId IRTypeID dinfo;
	};
		
ModInfoToText :: !Int !Int !Info -> List Strings;
ModInfoToText infotype filetype info
	| infotype	== RIOptID	= OptionsToText filetype info;
	| infotype	== RIFileID	= FileInfoToText filetype info;
	| infotype	== RISysID	= AbcInfoToText info;
	
OptionsToText :: !Int !Info -> List Strings;
OptionsToText filetype info=:{modinfo={dir,compilerOptions={neverMemoryProfile,neverTimeProfile,sa,listTypes,gw,bv,gc},defeo,impeo,defopen,impopen}}
	= 	{legend="Window Open"	, value=BooleanToString winopen} :!
		{legend="Font Name"		, value=fontname} :!
		{legend="Font Size"		, value=toString fontsize +++ " points"} :!
		{legend="Auto Indent"	, value=BooleanToString autoi} :!
		{legend="Tab Width"		, value=toString tabs} :!
		compiler;
	where {
	winopen	| def	= defopen;
					= impopen;
	fontname | def	= defeo.eo.EditOptions.fontname;
					= impeo.eo.EditOptions.fontname;
	fontsize | def	= defeo.eo.EditOptions.fontsize;
					= impeo.eo.EditOptions.fontsize;
	autoi| def		= defeo.eo.EditOptions.autoi;
					= impeo.eo.EditOptions.autoi;
	tabs | def		= defeo.eo.EditOptions.tabs;
					= impeo.eo.EditOptions.tabs;
	compiler | def	=	Nil;
					=	{legend=""						, value=""} :!
						{legend="Never Time Profile"			, value=BooleanToString neverTimeProfile} :!
						{legend="Never Memory Profile"		, value=BooleanToString neverMemoryProfile} :!
						{legend="Strictness Analyzer"	, value=BooleanToString sa} :!
						{legend="Types"					, value=TypesToString listTypes} :!
						{legend="Give Warnings"			, value=BooleanToString gw} :!
						{legend="Be Verbose"			, value=BooleanToString bv} :!
						{legend="Generate Comments"		, value=BooleanToString gc} :!
						Nil;
	def				= filetype == RIDclID;
	};
	
FileInfoToText :: !Int !Info -> List Strings;
FileInfoToText filetype
		info=:{	path,abcpath,objpath,dcldate,icldate,objdate,abcdate,tp }
	| exists	=	{legend="Location"			, value=RemoveFilename path`} :!
					{legend="Last Modification"	, value=DateToString date`} :!
					uptodate;
				=	{legend="Nonexistent",value=""} :!
					Nil;
	where {
	uptodate| showdcl	= status :! Nil;
			| showicl	= status :! Nil;
			| showabc	= deps :! status :! Nil;
						= processor :! Nil;
	date`	| showdcl	= dcldate;
			| showicl	= icldate;
			| showabc	= abcdate;
			| showobj	= objdate;
	path`	| showdcl	= path;
			| showicl	= path;
			| showabc	= abcpath;
			| showobj	= objpath;
	exists	| showdcl	= dcldate.exists;
			| showicl	= icldate.exists;
			| showabc	= abcdate.exists;
			| showobj	= objdate.exists;
	status	| outofdate	= {legend="Status", value="Out Of Date..."};
						= {legend="Status", value="Up To Date"};
	deps	| rescan	= {legend="Dependency Analysis"	, value="Reanalyze"};
						= {legend="Dependency Analysis"	, value="Up To Date"};
	processor			= {legend="Processor"			, value=ProcessorToString tp};
	outofdate			= OutOfDate showicl info;
	showdcl				= filetype == RIDclID;
	showicl				= filetype == RIIclID;
	showabc				= filetype == RIAbcID;
	showobj				= filetype == RIObjID;
	rescan				= ReScan info;
	};
						
AbcInfoToText :: !Info -> List Strings;
AbcInfoToText {path,abcdate,version,sys,stack,abcOptions}
	|	not abcdate.exists
		=	{legend="Nonexistent"			, value=""} :!
			Nil;
		=	{legend="Compiler version"		, value=VersionToString version} :!
			{legend="System File"			, value=BooleanToString sys} :!
			{legend="Seq. Stack Info"		, value=BooleanToString stack} :!
			{legend="Strictness Analyzer"	, value=BooleanToString abcOptions.abcStrictnessAnalysis} :!
			{legend="Give Warnings"			, value=BooleanToString abcOptions.abcGiveWarnings} :!
			{legend="Be Verbose"			, value=BooleanToString abcOptions.abcBeVerbose} :!
			{legend="Generate Comments"		, value=BooleanToString abcOptions.abcGenerateComments} :!
			{legend="Time Profile"			,	value=BooleanToString abcOptions.abcTimeProfile} :!
			{legend="Reuse Unique Nodes"	,	value=BooleanToString abcOptions.abcReuseUniqueNodes} :!
			{legend="Memory Profile"		,	value=BooleanToString abcOptions.abcMemoryProfile} :!
			Nil;
									
FileUpToDate :: !Int !Info -> List Strings;
FileUpToDate	filetype
		{	path,imports,dcldate,icldate,abcdate,objdate,version,sys,stack,abcOptions,abc,src,
			modinfo={ModInfo | compilerOptions} }
	| filetype == RIIclID	&&	src_outofdate	= linesa;
	| filetype == RIIclID						= {legend="Up To Date",value=""} :! Nil;
	| filetype == RIAbcID	&&	abc_outofdate	= linesb;
	| filetype == RIAbcID						= {legend="Up To Date",value=""} :! Nil;
												= {legend="",value=""} :! Nil;
	where {
	linesa	| imports		= 	{legend="Some imported .dcl files younger than .abc file",value=""} :!
								lines5;
							= 	lines5;
	lines5	| src			=	{legend="Paths modified",value=""} :! lines4;
							=	lines4;
	lines4	| not_exists	= 	{legend=".abc and .obj files nonexistent",value=""} :! lines3; 
			| src_younger	= 	{legend=abc_obj_suffix +++ " file older than " +++ src_file,value=""} :!
								lines3;
							=	lines3;
	lines3	| old_version	=	{legend=".abc file generated with different compiler version",value=""} :!
								lines2;
							=	lines2;
	lines2	| stackinfo		=	{legend=".abc file has no seq. stack info",value=""} :! lines1;
							=	lines1;
	lines1	| options		=	{legend="File generated with different compiler options",value=""} :!
								Nil;
							=	Nil;
	old_version				= (version <> Version) && abcdate.exists;
	src_younger				= dcl || icl;
	dcl						= dcldate.exists && Older_Date abc_obj_date dcldate;
	icl						= icldate.exists && Older_Date abc_obj_date icldate;
	not_exists				= not abcdate.exists && not objdate.exists;
	options					= abcdate.exists && NECompilerOptions abcOptions compilerOptions;
	stackinfo				= abcdate.exists && not stack && not sys;
	abc_obj_date
		| abcdate.exists	= abcdate;
							= objdate;
	abc_obj_suffix
		| abcdate.exists	= ".abc";
		| objdate.exists	= ".obj";
							= ".abc & .obj";
	src_file
		| dcl && icl		= ".dcl & .icl files"; 
		| dcl				= ".dcl file";
							= ".icl file";
	src_outofdate			= old_version || imports || src_younger || src || not_exists || options || stackinfo;
	
	linesb	| abc			= {legend="Code Gen. Options and/or paths modified",value=""} :! lines6;
							= lines6;
	lines6	| not_obj_exists= {legend=".obj file nonexistent",value=""} :! Nil;
			| abc_younger	= {legend=".obj file older than .abc file",value=""} :! Nil;
							= Nil;
	abc_younger				= Older_Date objdate abcdate;
	not_obj_exists			= not objdate.exists;
	abc_outofdate			= abc_younger || not_obj_exists || abc;
	};
		
ShowOutOfDate :: !Bool !EditOptions !Info !DialogInfo ProgState !IO -> ProgIO;
ShowOutOfDate outofdate peo info dinfo prog io
	= (prog, io`)
	where {
	io` = ChangeDialog DModInfoID
			[	ChangeDynamicStrings IDTextsID peo txt
				/* ChangeDynamicButton IDTextsBTID bttxt DynButStrs (ShowOutOfDate outofdate` peo info) */ ] io;
	txt	| outofdate		= Concat (FileUpToDate mod info) (FileInfoToText mod info);
						= Concat (FileInfoToText mod info) (FileUpToDate mod info);
	outofdate`			= not outofdate;
	mod					= GetSelectedRadioItemId IRModsID dinfo;
	bttxt | outofdate	= "Info";
						= "More...";
	};
	
BooleanToString :: !Bool -> String;
BooleanToString True	= "Yes";
BooleanToString False	= "No";

TypesToString :: !ListTypes -> String;
TypesToString NoTypes			=  "No Types";
TypesToString InferredTypes		=  "Inferred Types";
TypesToString StrictExportTypes	=  "Strict Export Types";
TypesToString AllTypes			=  "All Types";

DateToString :: !DATE -> String;
DateToString {exists,yy,mm,dd,h,m}
	| exists	=	toString dd +++ "-" +++ toString mm +++ "-" +++ toString yy +++ ", " +++
					ItoS` h +++ ":" +++ ItoS` m;
				=	"N/A";
	where {
	ItoS` x | x<10	= "0" +++ toString x;
					= toString x;
	};

VersionToString :: !Int -> String;
VersionToString version
	= toString (version / 100) +++ "." +++ toString (version rem 100);
	
ProcessorToString :: !Processor -> String;
// RWS ProcessorToString CurrentProcessor	= "68020 + 68881";
ProcessorToString CurrentProcessor	= "Current Processor";

ProcessorToString MC68000			= "68000";
ProcessorToString MC68020			= "68020";
ProcessorToString MC68020_and_68881	= "68020 + 68881";
	
ListBoxW :: Measure;
ListBoxW
	= Pixel ( CharWidth * FontCharWidth ExampleChar font + MMToHorPixels ListBoxMargin );
	where {
	(_,font)	= SelectFont fn [] fs;
	(fn,_,fs)	= DefaultFont;
	};
	
MakeLazySortedList :: !(List String) -> [String];
MakeLazySortedList (hd:!tl)	= InsertInLazyList hd (MakeLazySortedList tl);
MakeLazySortedList Nil		= [];

InsertInLazyList :: !String ![String] -> [String];
InsertInLazyList new []							= [new];
InsertInLazyList new l=:[hd : tl]	| new <$ hd	= [new, hd : tl];
									| hd <$ new	= [hd : InsertInLazyList new tl];
												= l;
												
(<$) infix 2 :: !String !String -> Bool;
(<$) str1 str2
	= LT 0 minlen lenstr1 str1 lenstr2 str2;
	where {
	lenstr1						= size str1;
	lenstr2						= size str2;
	minlen	| lenstr1 < lenstr2	= lenstr1;
								= lenstr2;
	};

LT	:: !Int !Int !Int !String !Int String -> Bool;
LT pos minlen len1 str1 len2 str2
	| pos >= minlen	= len1 < len2;
	| c1 == c2		= LT (inc pos) minlen len1 str1 len2 str2;
					= c1 < c2;
	where {
	c1	= toLower (str1.[pos]);
	c2	= toLower (str2.[pos]);
	};
												
MakeDynamicButton :: !DialogItemId !ItemPos !String !(List String) !(ButtonFunction ProgState IO) -> DialogItem ProgState IO;
MakeDynamicButton id pos str strs buttonfun
	= DialogIconButton id pos ((0,0),(textwidth,ButHgt)) buttonpic Able buttonfun;
	where {
// RWS Win	(_,rfont)		= SelectFont "MS Sans Serif" [] 8;
	(_,rfont)		= SelectFont "Chicago" [] 12;
	xoffset			= (textwidth - FontStringWidth str rfont) / 2;
	yoffset			= at + ld;
	(at,_,_,ld)	= FontMetrics rfont;
	textwidth		= 20 + MaxInt (MapR fontw strs);
	roundrect pic	= DrawRoundRectangle (((0,0),(textwidth,ButHgt)),16,16) pic;
	string pic		= DrawString str (MovePenTo (xoffset,yoffset) pic); 
	buttonpic state	= [SetFont rfont, SetPenMode CopyMode, roundrect, string];
	fontw str		= FontStringWidth str rfont;
	};
	
ChangeDynamicButton :: !DialogItemId !String !(List String) !(ButtonFunction ProgState IO) !(DialogState ProgState IO) -> DialogState ProgState IO;
ChangeDynamicButton id str strs buttonfun dstate
	= ChangeIconLook id changelook (ChangeButtonFunction id buttonfun dstate`);
	where {
// RWS Win	(_,rfont)			= SelectFont "MS Sans Serif" [] 8;
	(_,rfont)			= SelectFont "Chicago" [] 12;
	xoffset				= (textwidth - FontStringWidth str rfont) / 2;
	yoffset				= at + ld;
	(at,_,_,ld)			= FontMetrics rfont;
	textwidth			= 20 + MaxInt (MapR fontw strs);
	roundrect pic		= DrawRoundRectangle (((0,0),(textwidth,ButHgt)),16,16) pic;
	string pic			= DrawString str (MovePenTo (xoffset,yoffset) pic); 
	erase pic			= EraseRectangle ((0,0),(TextWid,ButHgt)) pic;
	fontw str			= FontStringWidth str rfont;
	changelook state
		| size str==0	= [erase];
						= [erase,SetFont rfont, SetPenMode CopyMode, roundrect, string];
	dstate`
		| size str==0	= DisableDialogItems [id] dstate;
						= EnableDialogItems [id] dstate;
	};
											
MakeDynamicStrings :: !DialogItemId !ItemPos !EditOptions !(List Strings) -> DialogItem ProgState IO;
MakeDynamicStrings  id pos {EditOptions | fontname,fontsize} txt
	= DialogIconButton id pos ((0,0),(TextWid,y)) strings Unable ButIdle;
	where {
	y				= TextLength * height;
	(rfont,st1,st2)	= SelectFonts fontname fontsize;
	offset			= at + ld;
	height			= at + dt + ld;
	(at,dt,_,ld)	= FontMetrics rfont;
	xoffset			= GetXOffset 0 txt rfont;
	strings state	=	[	SetFont rfont,
							SetPenMode CopyMode
						:	DrawDynamicStrings offset height offset xoffset st1 st2 TextLength txt
						];
	};
	
ChangeDynamicStrings :: !DialogItemId !EditOptions !(List Strings) !(DialogState ProgState IO) -> DialogState ProgState IO;
ChangeDynamicStrings id {EditOptions | fontname,fontsize} txt dstate
	= ChangeIconLook id changelook dstate;
	where {
	(rfont,st1,st2)		= SelectFonts fontname fontsize;
	offset				= at + ld;
	height				= at + dt + ld;
	(at,dt,_,ld)		= FontMetrics rfont;
	xoffset				= GetXOffset 0 txt rfont;
	changelook state
		=	[	EraseRectangle ((0,0),(TextWid,TextLength * height)),
				SetFont rfont,
				SetPenMode CopyMode
			:	DrawDynamicStrings offset height offset xoffset st1 st2 TextLength txt
			];
	};
	
GetXOffset :: !Int !(List Strings) !Font -> Int;
GetXOffset width Nil rfont = width;
GetXOffset width ({legend}:!rest) rfont
	| width < width`	= GetXOffset width` rest rfont;
						= GetXOffset width rest rfont;
	where {
	width`	= FontStringWidth legend rfont + FontCharWidth ExampleChar rfont;
	};
	
SelectFonts :: !FontName !FontSize -> (!Font, ![FontStyle], ![FontStyle]);
SelectFonts fontname fontsize
	| ok	= (rfont, bold, []);
			= (deffont, [], []);
	where {
	(ok, rfont)		= SelectFont fontname bold fontsize;
	(_, deffont)	= SelectFont fontname defstyle fontsize;
	(_,defstyle,_)	= DefaultFont;
	bold			= ["Bold"];
	};
	
DrawDynamicStrings :: !Int !Int !Int !Int ![FontStyle] ![FontStyle] !Int !(List Strings) -> [Picture -> Picture];
DrawDynamicStrings yoffset height offset xoffset st1 st2 0 txt
	=	[];
DrawDynamicStrings yoffset height offset xoffset st1 st2 cnt Nil
	=	[];
DrawDynamicStrings yoffset height offset xoffset st1 st2 cnt ({legend,value}:!rest)
	=	[	SetFontStyle st1,
			MovePenTo (0,yoffset),
			DrawString legend,
			SetFontStyle st2,
			MovePenTo (xoffset,yoffset),
			DrawString value
		:	DrawDynamicStrings (yoffset+height) height offset xoffset st1 st2 (dec cnt) rest
		];

Compiler_and_EditOptions` :: !Bool !Info !DialogInfo !ProgState !IO -> ProgIO;
Compiler_and_EditOptions` def info=:{path} dinfo prog io
	= changedialog prog` io`;
	where {
//	(prog`,io`)	= Compiler_and_EditOptions def info dinfo prog io;
	(prog`,io`)	= (prog, io);


	changedialog :: !ProgState !IO -> ProgIO;
	changedialog prog=:{editor={project,editwindows}} io
		= (prog,io`);
		where {
		io`	= ChangeDialog DModInfoID
				[	ChangeDialogFunction RIDclID newdfun,
					ChangeDialogFunction RIIclID newdfun,
					ChangeDialogFunction RIAbcID newdfun,
					ChangeDialogFunction RIObjID newdfun,
					ChangeDialogFunction RIOptID newdfun,
					ChangeDialogFunction RIFileID newdfun,
					ChangeDialogFunction RISysID newdfun,
					ChangeButtonFunction IDTextsID newbfun,
					ChangeDynamicStrings IDTextsID peo text
				] io;
		projectwd		= GetWindow ProjectWdID editwindows;
		info`			= {info & modinfo = modinfo};
		(_,modinfo)		= PR_GetModuleInfo (GetModuleName path) project;
		peo				= EW_GetEditOptions projectwd;
		text			= OptionsToText filetype info`;
		filetype | def	= RIDclID;
						= RIIclID;
		newdfun			= ShowSelectedModule peo info`;
		newbfun			= Compiler_and_EditOptions` def info`;
		};
	};

/* Misc. */

MaxInt :: !(List Int) -> Int;
MaxInt Nil		= 0;
MaxInt (h:!t)	| h > max	= h;
							= max;
							where {
							max	= MaxInt t;
							};
