
                          M U L T I G U I

 Introduction
--------------

  multiGUI is an extension for easyGUI (written by Wouter van Oortmerssen).
easyGUI is an powerful and very small GUI-creating-system. The only thing I
missed was simultaneous handling of multiple windows. Originally I need this
feature for my 3d-plotter and so I wrote this piece of code.
Features:
  - Handle as many GUIs as you want
  - easy to use
  - possibility to define termination-functions for each GUI
  - object-oriented


 Description
-------------

(Definition(s):
   mg:PTR TO multiGUI
   gl                 -> pointer to a guientry (blackbox-structure)
   gh:PTR TO guihandle
)

multiGUI export only one OBJECT:

(----) OBJECT multiGUI
         multiGUI()
         addGUI(a,b,c,d,e,f)
         nextGUI(a)
         findGUIFromHandle(a)
         getGUIHandle(a)
         getSendingGUI()
         removeGUI(a,b)
         wait()
         getCounter()
         setStdScreen(a)
         setStdTextAttr(a)
         getStdScreen()
         getStdTextAttr()
         setGUIProcs(a,b,c)
         setGUIUserData(a,b)
         getGUIInfo(a)
         getGUIDescription(a)
         getGUIUserData(a)
         removeAll(a)
         end()
         waitSignal(a)
         processMessage(a,b)
         processFailure(a,b)
         unknownSignal(a)
(----) ENDOBJECT     /* SIZEOF=24 */
  
  multiGUI()  -- Constructor
	initialize datastructures for the multiGUI-object.
	Example:
		NEW mg.multiGUI()
		->... some piece of code
		END mg     -> remove all GUIs and multiGUI-datas

  addGUI(windowtitle,gui,info=0,screen=0,textattr=0,newmenus=0)
	link an gui to the multiGUI-list and create the window. The arguments
	are the same like for guiinit() or easygui().
    
	After calling this function the gui-window is ready for use. addGUI()
	use function guiinit() from easyGUI and returns a guientry.

	Notes:
		- If you set 'screen' to NIL the standard screen is used.
		  (Can be set via setStdScreen()). Same for 'textattr'.

  nextGUI(gl=NIL)
	With this method you can scan through the gui-list. Pass NIL to get
	the first gui or a valid guientry to get the next entry.
	Example:
		gl:=NIL
		WHILE gl:=mg.nextGUI(gl)
		  ...do your stuff here
		ENDWHILE

  findGUIFromHandle(gh:PTR TO guihandle)
	Searches in the guilist for an entry with the guihandle 'gh'.
	Returns the guientry or NIL.

  getGUIHandle(gl)
	Returns the guihandle of the guientry 'gl'.

  getSendingGUI()
	Returns a pointer the guientry that has handled the last message.

	EasyGUI is well designed for a single gui. But there is no way to
	get the guihandle in a action-function (you can't pass it as the
	info-value because you don't know it during creating). For single
	guis you could store it as an global variable. For multiple guis
	this is nearly impossible.
	With multiGUI there is a work-around:
		- store the multiGUI-object as global variable (or as the
		  info-value)
		- now call getSendingGUI() as *first* thing in your
		  action-function and you get the pointer to your guientry

  removeGUI(gl,res=-1)
	Search the guientry 'gl' in the multiGUI-list and remove this
	GUI from list and from memory. Defined action functions are called.

  wait()
	Handle messages for all gui's. wait() does the same like
	easygui/easygui() but for multiple gui's. That means if
	easygui/guimessage() returns an action-value or an exception occur
	during guimessage() (caused by an action-function) then this gui
	is removed. wait() returns the result from guimessage() and the
	info-data of this gui (the one you give as argument to addgui()).
	The 'stdrast'-variable is set to the window rastport of this gui.
	Note:
		- wait() returns immediately. So if you have to call this
		  function again until all gui's are closed or until you have
		  removed all gui's using removeGUI() or removeAll().
		  Example:
			...
			WHILE mg.getCounter>0 DO mg.wait()
			...

		- wait() uses the 4 methods waitSignal(), processMessage(),
		  unknownSignal() and processFailure(). You can change these
		  methods if you wanna do some special things here. See below
		  for more details.
		  waitSignal() is called whenever wait() think its time to
		  wait for incomming signals. After waitSignal() has returned
		  a value and wait() found the corresponding gui
		  processMessage() is called. If no gui is found wait() calls
		  unknownSignal(). On Failure (exception or positive result
		  from processMessage()/unknownSignal()) wait() calls
		  processFailure().

  getCounter()
	Returns the number of gui's linked to the gui-list.

  setStdScreen(screen)
	Sets the standard screen to 'screen'. See addGUI() for details.

  setStdTextAttr(textattr)
	Sets the standard textattributes to 'textattr'. See addGUI().

  getStdScreen()
	Returns the standard screen.

  getStdTextAttr()
	Returns the standard textattributes.

  setGUIProcs(gl,rf_before,rf_after)
	Whenever a gui is removed this 2 action-functions are called.
	'rf_before' is called before the easygui/cleangui()-call and
	'rf_after' this.
	These functions get 3 arguments:
		- a pointer to the multiGUI-object
		- pointer to the guientry
		- a result-value (normally this from easygui/guimessage())
	The 'rf_before'-PROC normally do some output/notify and 'rf_after'
	free allocated memory.
	Example:
		...
		mg.setGUIProcs(gl,{my_output},NIL)
		...
		PROC my_output(mg:PTR TO multiGUI,gl,res) IS
		  PrintF('Info: \d; Result: \d\n',mg.getGUIInfo(gl),res)

  setGUIUserData(gl,userdata)
	Sets the userdata-value to 'userdata'. This attribute is freely
	usable.

  getGUIInfo(gl)
	Returns the info-value of the guientry 'gl' (see addGUI()).

  getGUIDescription(gl)
	Returns the list you have passed as 'gui' to addGUI(). Useful
	if you create your lists dynamical and want to delete them.
	See multiGUI_Demo2 for this.

  getGUIUserData(gl)
	Returns the userdata-value of this gui.

  removeAll(res=-1)
	Removes all gui's from the list. 'res' is passed as third argument
	to the action-functions (see setGUIProcs()).

  guianz()
	returns the number of GUIs still open

  end()
	Destructor.
	Removes all gui's and frees memory used for the multiGUI-list.

  The following methods are used by wait(). You can overwrite them if
  necessary.

  waitSignal(sigs)
	When wait() wants to wait for a new signal it call this method.
	'sigs' is the bitmask of all signals. Normally you do a Wait() call
	here and return the result.
	The default implementation is:

		PROC waitSignal(sigs) OF multiGUI IS Wait(sigs)

  processMessage(gl,gh)
	When wait() has got a result from waitSignal() and could identify
	the gui this method is called.
	'gl' is a pointer to the guientry of this gui and 'gh' the guihandle.
	You should call easygui/guimessage() and return the result.
	The default implementation is:

		PROC processMessage(gl,gh:PTR TO guihandle) OF multiGUI
		  SetStdRast(gh.wnd.rport)
		ENDPROC guimessage(gh)

  unknownSignal(sig)
	Wait() has got a result from waitSignal() but could not identify
	the gui that caused it. So it calls this method with the received
	signal 'sig'. This enables you to wait for custom signals in
	waitSignals().
	The default implementation is:

		PROC unknownSignal(sig) OF multiGUI IS -1

  processFailure(gl,res)
	If easygui/guimessage() returns a positive number or calls an
	action-function which throw an exception, wait() calls this method.
	'gl' is pointer to the guientry, 'res' is the result value from
	processMessage() (only valid if >0 otherwise an exception occurs).
	The default implemenation is:

		PROC processFailure(gl,res) OF multiGUI IS
		  self.removeGUI(gl,res)


----------
Feel free to send me any comments, suggestions or ideas.

Sven Steiniger
Email: ss37@irz.inf.tu-dresden.de
