// Global path for MSA
string MSA112_MSApath() return "_temDM-Scripts:MSA"

/******************************************************************
Interfaces
******************************************************************/	
interface InterfaceFramesMSA
{
string GetPackageName(object self);			//needed for loading/storing parameters
number MSA112_AboutToCloseUIFrame(object self, number verify);
//void MSA112_CloseUIFrame(object self);
void MSA112_SafeCloseUIFrame(object self);			
void MSA112_CloseWindowUser(object self);	//may be defined by user
void MSA112_CloseFrame(object self);		//may be defined by user

number  GetInfoMode(object mother);		//need for Info icons
number  GetInfoReset(object mother);
void  SetInfoReset(object mother,number reset);
					
void EnablingButtons(object self,number state);//for info captions
number EnablingAll(object self);
number FrameWidth(object self);	
}
	

/******************************************************************
Functions: load /store parameters
******************************************************************/	
string MSA112_getPackageName(object frm)
	{
	if(frm.ScriptObjectIsValid()) 
		{
		string package
		try
			{package = frm.GetPackageName();}
		catch
			{throw("Object must be of type MSA112_");}
			
		if(package=="") throw("MSA112_ object name was not initiated")
	
		return package
		}
	}

/*** Parameter ****************/	
number MSA112_LoadParameter(object frm,number default,string ParameterName)
	{
	string package = frm.MSA112_getPackageName()
	number Parameter
	if(!getPersistentNumberNote(Package+":"+ParameterName,Parameter)) Parameter=Default;

	return Parameter
	}

void MSA112_StoreParameter(object frm,number Parameter,string ParameterName)
	{
	string package = frm.MSA112_getPackageName()
	setPersistentNumberNote(Package+":"+ParameterName,Parameter)
	}

number MSA112_LoadStoreParameter(object frm,number default,string ParameterName)
	{
	number Parameter = MSA112_LoadParameter(frm,default,ParameterName)
	MSA112_StoreParameter(frm,Parameter,ParameterName)

	return Parameter
	}

/*** ID number (0-4294967295) ****************/	
number MSA112_LoadID(object frm,string ObjectName)
	{
	string package = frm.MSA112_getPackageName()
	TagGroup pers = GetPersistentTagGroup()
	
	number ID
	TagGroupGetTagAsUInt32(pers,Package+":"+ObjectName,ID)
	
	return ID
	}

void MSA112_StoreID(object frm,number ID, string ObjectName)
	{
	string package = frm.MSA112_getPackageName()
	TagGroup pers = GetPersistentTagGroup()

	TagGroupSetTagAsUInt32(pers,Package+":"+ObjectName,ID)
	}

number MSA112_LoadStoreID(object frm,string ObjectName)
	{
	number ID = MSA112_LoadID(frm,ObjectName)
	MSA112_StoreID(frm,ID,ObjectName)
	
	return ID
	}

/*** Point ****************/				
void MSA112_LoadPoint(object frm,number &X,number &Y,number defaultX,number defaultY,string ParameterName)
	{
	string package = frm.MSA112_getPackageName()
	if(!getPersistentPointNote(Package+":"+ParameterName, X,Y)) 
		{
		X = defaultX
		Y = defaultY
		}
	}

void MSA112_StorePoint(object frm,number X,number Y,string ParameterName)
	{
	string package = frm.MSA112_getPackageName()
	setPersistentPointNote(Package+":"+ParameterName, X,Y) 
	}

void MSA112_LoadStorePoint(object frm,number &X,number &Y,number defaultX,number defaultY,string ParameterName)
	{
	MSA112_LoadPoint(frm,X,Y,defaultX,defaultY,ParameterName)

	MSA112_StorePoint(frm,X,Y,ParameterName)
	}
	

/*** Rect ****************/				
void MSA112_LoadRect(object frm,number &X1,number &Y1,number &X2,number &Y2,number defaultX1,number defaultY1,number defaultX2,number defaultY2,string ParameterName)
	{
	string package = frm.MSA112_getPackageName()
	if(!getPersistentRectNote(Package+":"+ParameterName, X1,Y1,X2,Y2)) 
		{
		X1 = defaultX1
		Y1 = defaultY1
		X2 = defaultX2
		Y2 = defaultY2
		}
	}

void MSA112_StoreRect(object frm,number X1,number Y1,number X2,number Y2,string ParameterName)
	{
	string package = frm.MSA112_getPackageName()
	setPersistentRectNote(Package+":"+ParameterName, X1,Y1,X2,Y2) 
	}

void MSA112_LoadStoreRect(object frm,number &X1,number &Y1,number &X2,number &Y2,number defaultX1,number defaultY1,number defaultX2,number defaultY2,string ParameterName)
	{
	MSA112_LoadStoreRect(frm,X1,Y1,X2,Y2,defaultX1,defaultY1,defaultX2,defaultY2,ParameterName)
	
	MSA112_StoreRect(frm,X1,Y1,X2,Y2,ParameterName)
	}

/*** String ****************/				
string MSA112_LoadString(object frm,string default,string ParameterName)
	{
	string package = frm.MSA112_getPackageName()
	string Name
	if(!getPersistentStringNote(Package+":"+ParameterName,Name)) Name=Default;
	return Name
	}

void MSA112_StoreString(object frm,string Name,string ParameterName)
	{
	string package = frm.MSA112_getPackageName()
	setPersistentStringNote(Package+":"+ParameterName,Name)
	}

string MSA112_LoadStoreString(object frm,string default,string ParameterName)
	{
	string Name = MSA112_LoadString(frm,default,ParameterName)

	MSA112_StoreString(frm,Name,ParameterName)
	
	return Name
	}

/*** Position ****************/
//this is loading the special point - position of Frame
void MSA112_LoadFramePositions(object frm,number &top,number &left, string Name)
	{
	//check the overall available area for frames
	number topD,leftD,bottomD,rightD
	DLGBuildPositionFromApplication().taggroupGetTagAsShortRect("Reference",topD,leftD,bottomD,rightD)
//result("\navailable "+topD+","+leftD+"->"+bottomD+","+rightD)
	//load the stored (UI)Frame112 position and check it

	frm.MSA112_LoadPoint(top,left,topD,leftD,Name+" TL")

	if((top==topD)&&(left==leftD)) result("\nNo stored Frame position")
	
	//top-left position above available area make Frame invisible
	if(top>bottomD){top=topD;result("\nstored top position is too large");}
	if(left>rightD){left=leftD;result("\nstored top position is too large");}
	}
	

/******************************************************************
	uploading downloading strings
******************************************************************/

void MSA112_UP(string Name)
{
setPersistentStringNote(MSA112_MSApath()+":upload",Name)
}

string MSA112_DOWN()
{
return getPersistentStringNote(MSA112_MSApath()+":upload")
}

void MSA112_reset()
{
setPersistentStringNote(MSA112_MSApath()+":upload","upload")
}

	

/******************************************************************
Waiting icon 
******************************************************************/
	
class MSA112_Wait:UIFrame
{
number takt
number stop

image im1,im2,im3,im4

Image WaitIcon(object self,number sign,number rot,number size,number background)
	{
	number central = size/20
	number rad = size/2
	number kant = size/25
	
	image im:= integerimage("",1,0,size,size)
	im = background
	im = tert(((icol-size/2)*(irow-size/2)*sign)>central,0,im)
	if(rot) 
		{
		image rotated = im.rotate(3.14159/4)
		number offset = round(size*(sqrt(2)-1)/2)
		im = rotated[offset,offset,size+offset,size+offset]
		}
		
	im = tert(iradius>(rad-kant),0,im)
	im = tert(iradius>rad,background,im)
	
	return im
	}

image GetIcon(object self,number index)
	{
	if(index==1) return im1
	if(index==2) return im2
	if(index==3) return im3
	if(index==4) return im4
	}
		
TagGroup CreateDLG(object self,number size)
	{
	TagGroup Wait = DLGCreateDialog("")
	Wait.DLGAddElement(DLGAddBitmap(DLGCreateGraphic(size,size),im1).DLGIdentifier("Wicon"))
	Wait.DLGAddElement(DLGCreateLabel("wait ..."))
	
	return Wait
	}
	
void Waiting(object self)	
	{
	number index
	while(!stop)
		{
		index++
		sleep(takt)
		try{
		self.LookUpElement("Wicon").DLGGetElement(0).DLGBitmapData(self.GetIcon(index))	
			}
		catch{stop=1;break;}
	
		if(index==4) index = 0
		}
	}
		
void init(object self)	
	{
	takt = 0.1
	number size = 40
	number background = 210
	
	im1 = self.WaitIcon(1,0,size,background)
	im2 = self.WaitIcon(-1,1,size,background)
	im3 = self.WaitIcon(-1,0,size,background)
	im4 = self.WaitIcon(1,1,size,background)
	
	self.init(self.CreateDLG(size))
	display(self,"");
	
	number top,left,bottom,right
	TagGroup AppPositions = DLGBuildPositionFromApplication()
	AppPositions.TagGroupGetTagAsShortRect("Reference",top,left,bottom,right)
	self.GetFrameWindow().WindowSetFramePosition((left+right)/2,(top+bottom)/2)
	
	self.StartThread("Waiting")
	}
	
~MSA112_Wait(object self)	
	{
	result("\nwaiting object "+self.ScriptObjectGetID()+ " destroyed")
	}
}



/******************************************************************
Info icon 
******************************************************************/

class MSA112_infoIcon :UIFrame
{
TagGroup CreateDLG(object self,string Caption)
	{
	TagGroup Dialog = DLGCreateDialog("")
	Dialog.DLGAddElement(DLGCreateLabel(Caption).DLGIdentifier("PressButton"))

taggroup layoutt = newTagGroup()	
DLGlayout(Dialog,layoutt)	//just add tag called "Layout"
	
	return Dialog
	}
void init(object self,string button,string Caption,number left,number top)
	{
	self.init(self.CreateDLG(Caption))
	display(self,button+":")
	
	self.GetFrameWindow().WindowSetFramePosition(left,top)
	}	

}


void MSA112_Info(object mother,string button,number shiftX,number ShiftY, string caption)
	{
	number left,top
	mother.GetFrameWindow().WindowGetFramePosition(left,top)
	
	number Xoffset = -130
	
	number InfoMode = mother.GetInfoMode()
	if(InfoMode) Caption +="\n--------------------\nto exit info-mode\npress \"I\" again"//\n(circle around \"I\" appears)"
		
	if(infoMode||OptionDown()) {alloc(MSA112_infoIcon).init(button,caption,left+Xoffset+ShiftX,top+ShiftY);exit(0);}

	}


void MSA112_InfoBox(object mother,tagGroup tg,string boxName,number shiftX,number ShiftY, string caption)
	{
	number InfoMode = mother.GetInfoMode()
	number reset = mother.GetInfoReset()

	if(infoMode||OptionDown()) 
		{
		if(!reset)	//only if reset==0
			{			
			number par = DLGgetValue(tg)	//induces second run with reset 1
			par = !par		
			DLGvalue(tg,par)
			}
			
		if(!reset)	//only if reset==0
				{		
				number left,top
				mother.GetFrameWindow().WindowGetFramePosition(left,top)
				
				if(infoMode)
					{
					Caption +="\n--------------------\nto exit info-mode\npress \"I\" again"//\n(circle around \"I\" appears)"
					}		
					
				{alloc(MSA112_infoIcon).init(BoxName,caption,left-mother.FrameWidth()+ShiftX,top+ShiftY);}	//no exit(0)			
				}				

		//toggle reset
		if(!reset)
			{
			//make reset==1, then the second run is dummy			
			mother.SetInfoReset(1)		
			}
		else	
			{
			//make reset== at the end of the second run			
			mother.SetInfoReset(0)		
			}			
		}
	}

	
	
	
	
/******************************************************************
Extended UIFrame

WITHOUT kept classes, redrawer, child
******************************************************************/
class MSA112_UIFrame: UIFrame
{
				string Package
				string Name

				void SetFrameName(object self,string NameP) Name = NameP
				void SetPackageName(object self,string PackageP) Package = PackageP
				string GetFrameName(object self) return Name
				string GetPackageName(object self) return Package

	
number MSA112_initUIFrame(object self,TagGroup FrameTag,string PackageP,string NameP)
	{
	//set standard names			
	self.SetPackageName(PackageP)
	self.SetFrameName(NameP)
	
	//ultimate opening the frame
	if(ShiftDown())
		{
		self.init(FrameTag)
		display(self,Name);	
					
		//store frame ID in Tags
		self.MSA112_StoreID(self.ScriptObjectGetID(),Name+" ID")
result("\n"+Name+" "+ self.ScriptObjectGetID() + " initialized")
			
		return 1
		}
		
	//check if already opened
	number FrameID = self.MSA112_LoadID(Name+" ID")	
	//object temp = FrameID.GetScriptObjectFromID()
		
	if((FrameID !=0)&&(FrameID.GetScriptObjectFromID().ScriptObjectIsValid())) 
		{
		object previous =FrameID.GetScriptObjectFromID()
		documentwindow win 
		try{
			win =previous.GetFrameWindow()
			win.WindowShow()
result("\ntool shown "+win.WindowIsShown())		//in GMS3 NOT shown	
			win.WindowSelect();			
			}	
		catch{break;}
		
		return 0			
		} 
	else
		{
		self.init(FrameTag)
		display(self,Name);	
					
		//store frame ID in Tags
		self.MSA112_StoreID(self.ScriptObjectGetID(),Name+" ID")
	
		//load and set position of the UIFrame112					
		number top,left
		self.MSA112_LoadFramePositions(top,left,Name)

//result("\ntop "+top+ " left "+left)
		self.GetFrameWindow().WindowSetFramePosition(left,top) //Note that point defined as left,top in this command		
	
result("\n"+Name+" "+ self.ScriptObjectGetID() + " initialized")
				
		return 1
		}
	}


void MSA112_SafeCloseUIFrame(object self) //universal for DM1.x and DM2.x
				{
				try{self.close();} catch{self.GetFrameWindow().WindowClose(0);break;}
				}	



//just before closing UIFrame	
//DO NOT OVERWRITE IT in the derived claases, use "MSA112_AboutToCloseUIFrame" instead !!!		
number AboutToCloseDocument(object self, number verify )
	{
	//store window position in Tags
	number top,left
	Self.GetFrameWindow().WindowGetFramePosition(left,top) //Note that point defined as left,top in this command
//result("\ntop "+top+" left "+left)

	self.MSA112_StorePoint(top,left,Name+" TL")
				
	//fire higher level method if defined
	number verify
	try{self.MSA112_AboutToCloseUIFrame(verify);} catch{break;} 
	//AboutToCloseUIFrame112 maybe defined  if neccesary in classes derived from UIFrame112 
				
	//set frame ID in Tags to 0
	self.MSA112_StoreID(0,Name+" ID")
	
	return 1
	}
	
	
~MSA112_UIFrame(object self) 
	{
	//fire higher level method if defined
	//try{self.MSA112_CloseUIFrame();} catch{break;}

	//TagGroup Ptg = GetPersistentTagGroup()
	//if(TagGroupDoesTagExist(Ptg,Package+":Kept Class")) TagGroupDeleteTagWithLabel(Ptg,Package+":Kept Class")
					
result("\n"+Name+" "+self.ScriptObjectGetID()+" destroyed") 
	}


/******************** starting thread with waiting icon *******************/
//fire a thread from DLG with using "Start" 
//identifier of "Start" buttons is required	
//The waiting icon appears indicating the runnning process 
//Waiting ID is returned, this must be used ate the end of thread to close the waiting icon			
number StartThreadFromDLG(object self,string ThreadName,string StartButton)
	{
	self.SetElementIsEnabled(StartButton,0)
	object WaitingIcon = alloc(MSA112_Wait)
	WaitingIcon.init()
	self.StartThread(ThreadName)	

	return WaitingIcon.ScriptObjectgetID()			
	}
	
//this closes the waiting icon 
//"Start" control button is enabled 
//identifier of "Start" button is required				
void EndThread(object self,string StartButton,number WaitingID)
	{
	self.SetElementIsEnabled(StartButton,1)
	object WaitingIcon = WaitingID.GetScriptObjectFromID()	
	
	try{WaitingIcon.close();} catch{WaitingIcon.GetFrameWindow().WindowClose(0);break;}		
	}


/******************** starting a thread with posibility to stop it from DLG *******************/

void GenerateException(object self)
	{
	throw("")
	//image err
	//Err.setPixel(2,0,0)	//intentionally generate exception
	}
	
//fire a thread from DLG with using "Start" 
//thread may be stopped with "Stop" control button 
//identifiers of both buttons are required
void RunThreadFromDLG(object self,string ThreadName,number &run,string StartButton,string StopButton)
	{
	run = 1
	self.SetElementIsEnabled(StartButton,0)
	self.SetElementIsEnabled(StopButton,1)
	self.StartThread(ThreadName)				
	}

//stop a thread from DLG with using "Stop" control button
//"Start" button is not yet enabled because it might be too early to allow the new start of thread
// identifiers of "Stop" button is required		
void StopThreadFromDLG(object self,number &run,string StopButton)
	{
	run = 0
	self.SetElementIsEnabled(StopButton,0)
	}

//Start Button is enabled			
void RestoreStartButton(object self,number run,string StartButton)
	{
	if(run==0) 
		{
		self.SetElementIsEnabled(StartButton,1)
		}	
	}

//if "Stop" button is already pressed but thread is still busy with long calculations
//insert it within Try{}catch{} in the long calculation chain
//exception is generated and "Start" Button is enabled 
void CheckStopFlag(object self,number run,string StartButton)
	{
	if(run==0) 
		{
		self.RestoreStartButton(run,StartButton)
		self.GenerateException()
		}	
	}
	
//Full termination of thread
//"Stop" and "Start" buttons are immediately set in the right state 
void TerminateThreadFromDLG(object self,number &run,string StartButton,string StopButton)
	{
	run = 0
	self.SetElementIsEnabled(StopButton,0)
	self.RestoreStartButton(run,StartButton)
	}
	

/******************Graphics**********************/	
				
//This convert the input string into the graphical image with controlled font size and style				
image GraphicFromString(object self,string input,number size,string font,number Face,number Bcgrd)
	{
	//Face 	0-standard
	//		1-bold
	//		2-kursive
	//		3-boldkursiv,
	//		4-underlined,
	//		5-boldunderlined
	//		6-kursiveunderlined
	//		7-boldkursivunderlined
	
	//create image surely larger than the annotation size
	if(size<=1) size=1
	number w0 = 2*len(input)*size+20
	number h0 = 2*size+20
	image base:= integerimage("base",1,0,w0,h0)
	base = Bcgrd 
///result("\n"+w0+"x"+h0)

	//create annotation
	number textID = CreateTextAnnotation(base,0,0,input)
	setAnnotationSize(base,textID,size)
	setAnnotationFont(base,textID,font)
	setAnnotationFace(base,textID,Face)
	setAnnotationBackground(base,textID,2)

	//burn annotation and cut the caption area from it
	number top,left,bottom,right
	GetAnnotationRect(base,textID,top,left,bottom,right)
	bottom = trunc(bottom)+1
	right = trunc(right)+1
	
	//NOTE THAT THERE IS A MINIMAL CAPTION SIZE POSSIBLE
//result("\n"+right+"-"+bottom)

	image Merged = blue(CreateImageFromDisplay(base))[top,left,bottom,right]
				
	return Merged
	}

image IRahm(object self,image in,number kantX,number kantY,number Bcgrd)
	{
	number W,H
	getSize(in,W,H)
	
	image Outlined:=integerImage("",1,0,W+2*kantX,H+2*kantY)
	Outlined = Bcgrd
	Outlined[kantY,kantX,kantY+H,kantX+W]=in
	
	return Outlined
	}

image Ibcgrd(object self,number size,number Bcgrd)
	{
	image im:=integerIMage("",1,0,size,size)	
	im=Bcgrd
	
	return im
	}
	
image Iplay(object self,number size,number Bcgrd,number Rahm)
	{		
	image im = self.Ibcgrd(size,0)
	
	im = tert((icol+irow)>1.25*size,Bcgrd,im)
	im = tert((icol-irow)>0.25*size,Bcgrd,im)
	im[0,0,size,0.35*size]=Bcgrd
		
	return self.IRahm(im,Rahm,Rahm,Bcgrd)
	}

image IFastPlay(object self,number size,number Bcgrd,number Rahm)
	{
	image im = self.Ibcgrd(size,0)
	
	im = tert((icol+irow)>1.15*size,Bcgrd,im)
	im = tert((icol-irow)>0.15*size,Bcgrd,im)
	im[0,0,size,0.25*size]=Bcgrd
	
	im[0.2*size,0.7*size,0.9*size,0.9*size]=0
	
	return self.IRahm(im,Rahm,Rahm,Bcgrd)	
	}

image IBackplay(object self,number size,number Bcgrd,number Rahm)
	{		
	image im = self.Iplay(size,Bcgrd,Rahm).rotate(3.14159)
		
	return im
	}

image IFastBackplay(object self,number size,number Bcgrd,number Rahm)
	{		
	image im = self.IFastplay(size,Bcgrd,Rahm).rotate(3.14159)
		
	return im
	}

image Isort(object self,number size,number Bcgrd,number Rahm)
	{
	image im:=integerIMage("",1,0,size,size)	
	im= Bcgrd
	
	number subS=size/9
	
	//horizontal
	im[2*subS,0,3*subS,4*subS]=0
	im[4*subS,3*subS,5*subS,6*subS]=0
	im[6*subS,6*subS,7*subS,9*subS]=0

	//vertical
	im[0,0,2*subS,subS]=0
	im[0,3*subS,4*subS,4*subS]=0
	im[0,6*subS,6*subS,7*subS]=0
	
	return self.IRahm(im,Rahm,Rahm,Bcgrd)
	}
	
TagGroup Button112(object self,image Icon,string Method)	
	{
	return DLGCreateBevelButton(Icon.DLGMakeLowered(),Icon.DLGMakeRaised(),Method)
	}

image IInfo(object self,number size,number Bcgrd,number Forground)
	{
	image Icon:=integerImage("",1,0,size,size)
	Icon=Bcgrd

	Icon =tert((iradius>(size*0.4))&&(iradius<(size*0.5)),Forground,Icon)
	
	Icon[0.2*size,0.4*size,0.8*size,0.6*size] =Forground
	Icon[0.2*size,0.3*size,0.3*size,0.7*size] =Forground
	Icon[0.7*size,0.3*size,0.8*size,0.7*size] =Forground
		
	return Icon
	}
	
image ISettings(object self,number size,number Bcgrd)
	{
	image Settings:=integerIMage("",1,0,size,size)
	Settings=Bcgrd
	Settings[0.1*size,0.1*size,0.6*size,0.6*size] = 0
	number L=0.07*size,h=0.52*size
	Settings[L,L,h,h] = tert(iradius<0.1*size,Bcgrd,Settings[L,L,h,h])
	Settings = tert(((icol-irow)<0.15*size)&&((icol-irow)>-0.15*size)&&((icol+irow)<0.6*size),Bcgrd,Settings)
	Settings = tert(((icol-irow)<0.15*size)&&((icol-irow)>-0.15*size)&&((icol+irow)>0.66*size)&&((icol+irow)<1.6*size),0,Settings)
	Settings = tert(((icol-irow)>-0.38*size)&&((icol-irow)<0.38*size),Settings,Bcgrd)

	return Settings
	}

/**********************************************
		Settings
**********************************************/	

//create Setting button Tags in dialogs
TagGroup SettingsButton(object self,number Size,number Bcgrd,string SettingsMethod) 
	{
	return DLGCreateBevelButton(self.ISettings(Size,Bcgrd).DLGMakeLowered(),self.ISettings(Size,Bcgrd).DLGMakeRaised(),SettingsMethod)
	}


/*****************  create settings line *****************/

TagGroup SettingsLine(object self,string Name,TagGroup Param)
	{
	//name (MSA path) is used to label DLG input
	TagGroup Items
	TagGroup Line =DLGCreateDialog("dummy",Items)
	Line.DLGTableLayout(2,1,0)
	Items.DLGaddElement(DLGCreateLabel(Name))
	Items.DLGaddElement(Param.DLGIdentifier(Name))
				
	return Line
	}


TagGroup AddSettingsLine(object self,taggroup &SettingList,TagGroup &TgPar)
	{
	//the name of parameter must be uploaded just before !!
	string Name = MSA112_DOWN()
	//strore parameter name in identificator
	TgPar.DLGIdentifier(Name).DLGAnchor("East")

	SettingList.DLGaddElement(self.SettingsLine(Name,TgPar))
	
	return TgPar
	}

TagGroup AddSettingsLine_Int(object self,taggroup &SettingList,number par,number digits)
	{
	TagGroup TgPar = DLGCreateIntegerField(Par,digits)
	
	self.AddSettingsLine(SettingList,TgPar)
	
	return TgPar
	}

TagGroup AddSettingsLine_Real(object self,taggroup &SettingList,number par,number digits,number afterComma)
	{
	TagGroup TgPar = DLGCreateRealField(Par,digits,afterComma)
	
	self.AddSettingsLine(SettingList,TgPar)
	
	return TgPar
	}

TagGroup AddSettingsLine_Check(object self,taggroup &SettingList,number par)
	{
	TagGroup TgPar = DLGCreateCheckBox("",Par)
	
	self.AddSettingsLine(SettingList,TgPar)
	
	return TgPar
	}

TagGroup AddSettingsLine_Menu(object self,taggroup &SettingList,number par,string It1,string It2)
	{									//here can be +1
			TagGroup Items 
	TagGroup TgPar = DLGCreatePopup(Items,par)
		TgPar.DLGAddPopupItemEntry(It1)
		TgPar.DLGAddPopupItemEntry(It2)
	
	self.AddSettingsLine(SettingList,TgPar)
	
	return TgPar
	}

TagGroup AddSettingsLine_Menu(object self,taggroup &SettingList,number par,string It1,string It2,string It3)
	{									//here can be +1
			TagGroup Items 
	TagGroup TgPar = DLGCreatePopup(Items,par)
		TgPar.DLGAddPopupItemEntry(It1)
		TgPar.DLGAddPopupItemEntry(It2)
		TgPar.DLGAddPopupItemEntry(It3)
	
	self.AddSettingsLine(SettingList,TgPar)
	
	return TgPar
	}

TagGroup AddAddSettingsLine_Str(object self,taggroup &SettingList,string par, number digits)
	{
	TagGroup TgPar = DLGCreateStringField(Par,digits)
	
	self.AddSettingsLine(SettingList,TgPar)
	
	return TgPar
	}


/*****************  read changed parameter *****************/
	
number SettingNumberParameter(object self,taggroup ParTg)
	{
	//get parameter name from tag identificator
	string parName 
	DLGGetIdentifier(ParTg, parName)

	//get/store parameter
	number Par = DLGGetValue(ParTg) 
	self.MSA112_StoreParameter(Par,ParName)
	
	return Par
	}

string SettingStringParameter(object self,taggroup ParTg)
	{
	//get parameter name from tag identificator
	string parName 
	DLGGetIdentifier(ParTg, parName)
	
	string Par = DLGGetStringValue(ParTg)
	self.MSA112_StoreString(Par,ParName)
	
	return Par
	}		


/**********************************************
		Info part
**********************************************/	
number InfoMode
number reset
number enablingState

number GetInfoMode(object self) return InfoMode	
  void SetInfoMode(object self,number mode) InfoMode = mode

number GetInfoReset(object self) return reset
  void SetInfoReset(object self,number resetP) reset = resetP

number GetEnablingState(object self) return reset
  void SetEnablingState(object self,number resetP) reset = resetP
  
number FrameWidth(object self) return 130


TagGroup InfoButton(object self,number Size,number Bcgrd) 
	{
	string SettingsMethod = "ToggleInfo"
	return DLGCreateDualStateBevelButton("InfoButton",self.IInfo(Size,Bcgrd,Bcgrd/1.4),self.IInfo(Size,Bcgrd,0),SettingsMethod)
	}

void ToggleInfo(object self)
	{
	if(InfoMode)
		{
		//returns to the previous state of disabled buttons (if exist)
		try{EnablingButtons(self,enablingState);} catch{break;} 
		InfoMode =0
		}
	else	
		{		 
		//this enable disabled buttons ("enabling all" exist in only few tools) 
		try{enablingState =EnablingAll(self);} catch{break;} 
		InfoMode =1
		}
//result("\ninfoMode "+InfoMode)
	}
	
}


	
	
	
/******************************************************************
Extended Frames functions 
******************************************************************/

//check if image window is still valid	
number MSA112_CheckImageWindow(imageDocument imdoc)
	{
	if(!imdoc.ImageDocumentIsValid()) return 0 	//if imdoc not initialised yet
	
	try {
		imdoc.ImageDocumentGetWindow().WindowIsOpen();
		} 
	catch return 0 	//if window was closed 	

	return 1
	}


number MSA112_defaultLinePlotLength() return 670

number MSA112_SetDesiredZoom(imageDocument imdoc, number desiredZoom)
	{
	image im := imdoc.ImageDocumentGetImage(0)
	DocumentWindow Win = imDoc.ImageDocumentShow()
		
	number width,height
	getsize(im,width,height)

	number LinePlotDisp
	try{
	im.SetZoom(desiredZoom);
	width  *= desiredZoom
	height *= desiredZoom
	} 
	catch{
	//This means that image is 1D and displayed as line plot
	LinePlotDisp = 1
	width = MSA112_defaultLinePlotLength()
	width *= desiredZoom
	height = width/2		//default setting : hight is twice less width
	break;
	}
	
	WindowSetContentSize(win,width,height);		

	//check if the actual zoom coinsides with the desired
	number ActualZoom
	number Integral = ImageDocumentGetDoIntegralZoom(imdoc)
	//Integral=1 stepped resize, 0 continuous resize
	if(Integral&&!LinePlotDisp)
		{	
//result("\nintegral")
		ActualZoom = im.getZoom()
		//the actual zoom might be lower than the desired	
		number zoomedWidth = trunc(width*ActualZoom)
		number zoomedHeight = trunc(height*ActualZoom)
		
		if(zoomedWidth<width) zoomedWidth = zoomedWidth+1
		else zoomedWidth = Width
		if(zoomedHeight<height*ActualZoom) zoomedHeight = zoomedHeight+1
		else zoomedHeight = Height
//result(" w "+w+" h "+h+" ww "+ww+" wh "+wh)

	win.WindowSetContentSize(zoomedWidth,zoomedHeight)	
		}
	else
		{
		ActualZoom = desiredZoom
		}
		
	return ActualZoom
	}

number MSA112_GetWindowZoomAndPosition(imageDocument imdoc,number &Y,number &X,number &Zoom)
	{
	if(MSA112_CheckImageWindow(imdoc)!=0)
		{
		image im := imdoc.ImageDocumentGetImage(0)
		documentwindow Win = imdoc.ImageDocumentGetWindow()

		win.WindowGetFramePosition(X,Y)	
		
		try{
		zoom = im.getZoom();
		
		}
		catch{
		number w,h
		win.WindowGetContentSize(w,h)

		zoom = w / MSA112_defaultLinePlotLength()
		break;
		}
		
		return 1
		}
	else return 0
	}	
	
number MSA112_SetWindowZoomAndPosition(imageDocument imdoc,number Y,number X,number Zoom)
	{
	if(MSA112_CheckImageWindow(imdoc)!=0) 
		{

		//check if zoom is reasonable
		if((Zoom<=0)||(zoom>64)) zoom = 1

		MSA112_SetDesiredZoom(imdoc,Zoom)

		documentWindow Win = imdoc.ImageDocumentGetWindow()
		win.WindowSetFramePosition(X,Y)
		
		return 1
		}
	else return 0
	}
	
	
/******************************************************************
extended Frames class
******************************************************************/
class MSA112_Frame:object
{
//This is effectively a wrap around the ImageDocument for images
//This keeps the position and zoom of the periodically created images like LiveView or FFT
//If an image is dependent on the parent image (e g FFT) it is automatically closed when parent is closed

	string Package	//this is name of whole package
	string Name		//this is name of specific image frame 
	
	imagedocument imdoc
	documentwindow win

	number CloseID


imageDocument GetWrappedImageDocument(object self) return imdoc
DocumentWindow 	GetWrappedDocumentWindow(object self) return win

void SetFrameName(object self,string NameP) Name = NameP
void SetPackageName(object self,string PackageP) Package = PackageP
string GetFrameName(object self) return Name
string GetPackageName(object self) return Package


//initialization of wrap around Image Window
//wrapped image must be initialized and shown before initialisation	
number MSA112_initFrame(object self,Imagedocument imdocP,string PackageP,string NameP)
	{
	//set wrapped Imagedocument
	imdoc = imdocP
	
	//set window
	if(!imdoc.MSA112_CheckImageWindow())
		{
		result("Image window is not valid !!")
		return 0
		}
	win = imdoc.ImageDOcumentGetWindow()

	//set names
	self.SetPackageName(PackageP)
	self.SetFrameName(NameP)			

	//load and set stored window position and zoom
	number top,left,zoom
	self.MSA112_LoadFramePositions(top,left,Name)
	zoom = self.MSA112_LoadParameter(1,Name+" Z")
//result("\nloaded TL "+top+" "+left+" Z "+zoom)	
	if(!MSA112_SetWindowZoomAndPosition(imdoc,top,left,zoom)) 
		{
		result("Cannot set image window zoom and position")
		return 0
		}

	//add listener on closing window, otherwise the object run away
	CloseID = win.WindowAddWindowListener(self,"window_closed:MSA112_ClosedWindow")
result("\nFrame112 "+self.ScriptObjectgetID()+" initialized")

	return 1
	}	

void MSA112_ClosedWindow(object self, number e_fl, DocumentWindow ThisWin)
	{	//fired many times after single closing		
	
	//store window position and zoom
	number top,left,zoom
	if(MSA112_GetWindowZoomAndPosition(imdoc,top,left,zoom))
		{	
		self.MSA112_StorePoint(top,left,Name+" TL")
		self.MSA112_StoreParameter(zoom,Name+" Z")
		}
	else throw("Cannot set image Window zoom and position")
		
//result("\nstored TL "+top+" "+left+" Z "+zoom)

	//fire higher level method if defined
	try{self.MSA112_CloseWindowUser();} catch{break;}
	
	//remove closing window listener (otherwise object doesnot run out of scope
	ThisWin.WindowRemoveWindowListener(CloseID)
	}


	
~MSA112_Frame(object self) 
	{		
result("\n"+Name+" "+self.ScriptObjectGetID()+" destroyed") 		
	}

}



/******************************************************************
Confirm Dialog
******************************************************************/
interface MSA112_confirm
{
void ConfirmAction1(object self);
void ConfirmAction2(object self);
void OKconfirm(object self);
number getOkay(object self);
}

/* USE WITHIN THREADS ONLY !! */
	
class MSA112_ConfirmFrame :UIFrame
{
object Signal
object mother

number OKay

TagGroup CreateDLG(object self,string Caption)
	{
	TagGroup Dialog = DLGCreateDialog("")
	Dialog.DLGAddElement(DLGCreateLabel(Caption).DLGIdentifier("PressButton"))

taggroup layoutt = newTagGroup()	
DLGlayout(Dialog,layoutt)	//just add tag called "Layout"
	
	return Dialog
	}

TagGroup ConfirmTags(object self,string OKbutton,string CancelButton)
	{
	TagGroup Dialog = DLGCreateDialog("").DLGTableLayout(2,1,0)
	
	Dialog.DLGAddElement(DLGCreatePushButton(OKbutton,"OKconfirm").DLGanchor("West"))
	Dialog.DLGAddElement(DLGCreatePushButton(CancelButton,"Cancelconfirm").DLGanchor("West"))
	
	return Dialog
	}

void OKconfirm(object self)
	{
	Okay =1
	SetSignal(Signal)
	}

void Cancelconfirm(object self)
	{
	Okay =0
	SetSignal(Signal)
	}

number getOkay(object self) return Okay
	
void ConfirmAction1(object self)
	{
	mother.ConfirmAction1()
	}
void ConfirmAction2(object self)
	{
	mother.ConfirmAction2()
	}
	
void init(object self,object motherP,object SignalP,TagGroup Content,string Caption,string OKbutton,string CancelButton,number left,number top)
	{
	Signal =SignalP
	mother =motherP
	
//object mother =getScriptObjectFromID(motherID)
	number left0,top0
	mother.GetFrameWindow().WindowGetFramePosition(left0,top0)
	
	TagGroup Frame =DLGCreateDialog("")
	Frame.DLGAddElement(Content)	
	Frame.DLGAddElement(self.ConfirmTags(OKbutton,CancelButton))
	
	self.init(Frame)
	display(self,Caption)
	beep()
	
	left +=left0
	top +=top0
	
	self.GetFrameWindow().WindowSetFramePosition(left,top)
	}
	
number AboutToCloseDocument(object self, number verify )
	{
//result("\nClosed confirm window ")

	Okay =0

	SetSignal(Signal)			
	}

}


number MSA112_ConfirmWaitPoint(object Signal,object Frame,number Timeout)
{
WaitOnSignal(Signal,Timeout,NULL)

number Okay
if(Frame.ScriptObjectIsValid())
	{
	Okay  =Frame.getOkay()

	try{Frame.close();} //close frame safely both in GMS1 and GMS2
	catch{Frame.GetFrameWindow().WindowClose(0);break;}	
	}
else return 0

return Okay	
}

number MSA112_Confirm(object mother,TagGroup ComponentConfirm,string Caption,string OKbutton,string CancelButton,number left,number top)
	{
	object Signal =NewSignal(0)
	object ConfirmFrame = Alloc(MSA112_ConfirmFrame)
	ConfirmFrame.init(mother,Signal,ComponentConfirm,Caption,OKbutton,CancelButton,left,top)
	
	return MSA112_ConfirmWaitPoint(Signal,ConfirmFrame,infinity())
	}
/* **************TEMPLATE ********************* */
/*
	TagGroup ConfirmTags = DLGCreatedialog("")
	ConfirmTags.DLGAddElement()

if(MSA112_Confirm(self,ConfirmTags,"dialog","OK","Cancel",left,top)) ....
else ....			
*/

			/* *************** This is for actions (2 actions reserved)) done within the mother object *********************/
number MSA112_Confirm(object mother,number &ConfirmFrameID,TagGroup ComponentConfirm,string Caption,string OKbutton,string CancelButton,number left,number top)
	{
	object Signal =NewSignal(0)
	object ConfirmFrame = Alloc(MSA112_ConfirmFrame)
	ConfirmFrame.init(mother,Signal,ComponentConfirm,Caption,OKbutton,CancelButton,left,top)
	
	ConfirmFrameID =ConfirmFrame.ScriptObjectGetID()
	
	return MSA112_ConfirmWaitPoint(Signal,ConfirmFrame,infinity())
	}
/* **************TEMPLATE ********************* */
/*
GLOBAL
number ConfirmFrameID

		TagGroup ConfirmTags = DLGCreatedialog("")
		ConfirmTags.DLGAddElement()
			
			numberfield Tag must be explicitely named, then 
									numb =DLGGetValue(TagName)
			action must have standard names : ConfirmAction1(object self), ConfirmAction2(object self)

if(MSA112_Confirm(self,ConfirmFrameID,ConfirmTags,"dialog","OK","Cancel",left,top)) ....
else ....		
	

THis should be in the mother body if OUT-OFF dialog (by closing listener) confirmation is needed

void ListenerActions(...)			
	{	
	object ConfirmFrame =ConfirmFrameID.GetScriptObjectFromID()
	try{ConfirmFrame.OKconfirm();}
	catch break
	}
*/

number  MSA112_SetFeatureInImage(string message,string buttonName)
	{	//OLD VERSION, CURRENTLY NOT IN USE
	number sem = NewSemaphore()
	ModelessDialog(message,buttonName,sem)
	try GrabSemaphore(sem)
	catch return 0
	return 1
	}



/******************************************************************
dummy object, just to get/set MSA parameters
******************************************************************/
class MSA112_dummy: object
{
string Package

void SetPackageName(object self,string PackageP) Package = PackageP
string GetPackageName(object self) return Package
				
object init(object self,string Package)
	{
	self.SetPackageName(Package)
	
	return self
	}
}




/******************************************************************
Functions: Graphic from string
******************************************************************/	
image MSA112_GraphicFromString(string input,number size,string font,number Face,number Bcgrd)
	{
	//Face 	0-standard
	//		1-bold
	//		2-kursive
	//		3-boldkursiv,
	//		4-underlined,
	//		5-boldunderlined
	//		6-kursiveunderlined
	//		7-boldkursivunderlined
	
	//create image surely larger than the annotation size
	if(size<=1) size=1
	number w0 = 2*len(input)*size+20
	number h0 = 10*size+20
	image base:= integerimage("base",1,0,w0,h0)
	base = Bcgrd 
///result("\n"+w0+"x"+h0)

	//create annotation
	number textID = CreateTextAnnotation(base,0,0,input)
	setAnnotationSize(base,textID,size)
	setAnnotationFont(base,textID,font)
	setAnnotationFace(base,textID,Face)
	setAnnotationBackground(base,textID,2)

	//burn annotation and cut the caption area from it
	number top,left,bottom,right
	GetAnnotationRect(base,textID,top,left,bottom,right)
	bottom = trunc(bottom)+1
	right = trunc(right)+1
	
	//NOTE THAT THERE IS A MINIMAL CAPTION SIZE POSSIBLE
//result("\n"+right+"-"+bottom)

	image Merged = blue(CreateImageFromDisplay(base))[top,left,bottom,right]
				
	return Merged
	}




/******************************************************************
Functions for running commands from ScriptString
******************************************************************/	
void MSA112_WN(number val, number index)
{
TagGroup Pers = GetPersistentTagGroup()

Pers.TagGroupSetTagAsLong("temp:number_"+index,val)
}

number MSA112_RN(number index)
{
TagGroup Pers = GetPersistentTagGroup()

number val
if(!Pers.TagGroupGetTagAsLong("temp:number_"+index,val)) return 0

return val
}

image MSA112_WI(image im, number index)
{
TagGroup Pers = GetPersistentTagGroup()

number ID = im.ImagegetID()
Pers.TagGroupSetTagAsLong("temp:image_"+index,ID)

//When ID stored from a ScriptString, MUST showImage() at the end
//otherewise image goes out of scope

return im
}

image MSA112_RI(number index)
{
TagGroup Pers = GetPersistentTagGroup()

number ID 
if(!Pers.TagGroupGetTagAsLong("temp:image_"+index,ID)) return NULL

return FindImageByID(ID)
}

void MSA112_C()
{
TagGroup Pers = GetPersistentTagGroup()

Pers.TagGroupDeleteTagWithLAbel("temp")
}

/* TEMPLATE

image in := realimage("in",4,100,100)
MSA112_WI(in,1)

number binX = 2
number binY = 3
MSA112_WN(binX,1)
MSA112_WN(binY,2)

result(MSA112_RN(2))

string ToExecute
//ToExecute ="number bY = MSA112_RN(2)"
//ToExecute += "result(MSA112_RN(2))"
ToExecute += "MSA112_RI(1).rebin(MSA112_RN(1),MSA112_RN(2)).MSA112_WI(2).showimage();"
//MSA112_RN(2)
try{executeScriptString(ToExecute);}
catch{result("\nold version");break;}


image out2:= MSA112_RI(2)
out2.setName("Out")

MSA112_C()
*/




	
/******************************************************************
Functions: Time marks
******************************************************************/	

/************* Update progress ***************/
void MSA112_UpdateProgress(object starter,string message,number fract) 
	{
	try{
	starter.LookUpElement("Message").DLGTitle(message)

	starter.DLGSetProgress("P bar",fract)
		}
	catch break	
	}

/************* Start mark ***************/	
void MSA112_ThreadMarkStart(object  starter,number fract,string messageView,string messagePrint,number &t)
{
t = getOStickCount()

MSA112_UpdateProgress(starter,messageView+"...",fract)
	
result(messagePrint)
}

/*************   End mark  ***************/
void MSA112_ThreadMarkEnd(object  starter,number Running, string messagePrint,number &t)
{
result(" "+messagePrint+":"+CalcOSsecondsBetween(t,getOStickCount())+"sec")

if(running == 0) 
	{
	starter.GenerateException()
	}
}
