E for Experts

Multi Window Interfaces using EasyGUI.

EasyGUI is the gadget-layout engine written by Wouter to help E developers to create font sensitive, self arranging interfaces. This great module consists of a few commands which can help anyone to achieve his goal.

Ok, EasyGUI is not as powerful as other engines, such as MUI or BGUI, but it is small, fast and friendly.

One of the major feature is that you can use it at different "levels": the easy one and the complex one. Here we will describe one complex method to create multi window interfaces using low-level EasyGUI functions.

The following code opens one single interface with two buttons. The first opens another interface, and the second writes a message on the Shell. The second interface, is a single button interface, which writes another message on the Shell.

Please, note that this code is meant for explanation only.


A LITTLE BACKGROUND

Amiga is a multitasking machine. Due to this fact, you can have a lot of windows working together on the same screen and everyone sending messages to its own application. One single application can have more than one window sending messages at the same time. From one point of view, this is a problem, because the programmer has to handle all different events correctly, but on the other side, it is one great feature. The programmer can split program functions into different windows and the user can find easily what he/she needs.

Exec, Amiga heart of multitasking, offers different ways to wait for a window event (also to other kind of events, but here we will talk only about window events). The way we use is to wait for a signal using the Wait() function. See autodocs on Exec/Wait() command.


THE PROGRAM

Here will follow the code. To have it completely in lha format, click here.

/***************** AMIGA E PROGRAM STARTS HERE ****************************/
MODULE 'tools/EasyGUI', 'tools/exceptions'

/*
First of all,  we have to define our  GUI handles (for this example, they are
global... hmmm it is not always a good idea to have global vars.)
*/

DEF firstgui:PTR TO guihandle -> The GUI handle of the main gui
DEF secndgui:PTR TO guihandle -> The GUI handle of the second gui we will open

/*
** This is the main proc. All it does is to init the first interface and  
** then to begin to handle events.                                        
** Please note the HANDLE keyword: we use exceptions handling!
*/
PROC main() HANDLE
  firstgui := egui('Main Window',
    [BEVELR,
      [EQROWS,
        [SBUTTON, {second}, 'Second GUI'],
        [SBUTTON, {msg1}, 'Message']
      ]
    ]
  )

  handleevents()      -> Here we handle events

EXCEPT DO
  closeall()          -> Here we close all interfaces
  report_exception()  -> In case an exception arrives, we show it!
  CleanUp(0)          -> Just to keep things clean
ENDPROC

/* This is my 'custom' version of guiinit. 
** It just try to open the interface and, with the exceptions handler
** we trace possible errors.
*/
PROC egui(wtitle, gui) HANDLE
  DEF gh:PTR TO guihandle  

  gh := guiinit(wtitle, gui)    -> Here we init the gui

  RETURN gh       -> If everything went fine, we just return the guihandler pointer

EXCEPT            -> If it does not work properely...
  cleangui(gh)    -> We clean the gui
  ReThrow()       -> And ReThrow() the exceptions.
ENDPROC

/*
** Here there is the most important routine.
** We will try to explain it line-by-line
*/

PROC handleevents() HANDLE
  DEF res=-1      -> Here we will store messages from the guimessage() function
  DEF signal      -> Here we store all the ORed sigbits
  DEF sig

  WHILE (res<0)
    IF (secndgui) -> If the user has opened the second gui
      -> We create the signal with both first and secnd gui
      signal := firstgui.sig OR secndgui.sig
    ELSE
      -> Else, only first gui is present.
      signal := firstgui.sig
    ENDIF

    sig := Wait(signal)  -> Here we wait for

    /* Here is the handling heart. We check for sig with both guis.
    ** The process is this. Sig will contain a sigbit of the 
    ** window which has produced the event.
    ** All we have to do is to check it with an AND operation
    */
    IF sig AND firstgui.sig   -> Here we check for the first window
      res := guimessage(firstgui) -> And we handle first window event 
      
    ELSEIF sig AND secndgui.sig -> Here we check for the second window
      res := guimessage(secndgui) -> And we handle second window event
      IF res>0    -> If res>0, the user has closed the window, but we do
                  -> NOT WANT to end the program.
        res := -1 -> So we set res to -1 (so WHILE...ENDWHILE will continue)
        cleangui(secndgui) -> We close second window gui
        secndgui := NIL    -> And set secndgui handle to NIL
      ENDIF
    ENDIF
  ENDWHILE

EXCEPT 
  closeall()
  ReThrow()
ENDPROC

/* This proc closes all guis */
PROC closeall()
  IF secndgui 
    cleangui(secndgui)
    secndgui := NIL
  ENDIF

  IF firstgui 
    cleangui(firstgui)
    firstgui := NIL
  ENDIF
ENDPROC

/* This proc opens the second GUI
** Note the HANDLE command.
*/
PROC second(i) HANDLE
  IF secndgui THEN RETURN

  secndgui := egui('Second Window',
    [BEVELR,
      [SBUTTON, {msg2}, 'Second Message']
    ]
  )

EXCEPT
  ReThrow()
ENDPROC

PROC msg1(i) 
  WriteF('This message comes from window 1!!!\n')
ENDPROC

PROC msg2(i)
  WriteF('This message comes from window 2!!!\n')
ENDPROC

/******************** AMIGA E PROGRAMS ENDS HERE **************************/