/*************************************************************************
 *          MICRO PAINT.C
 *
 * Programma di esempio sull'uso di Intuition, a corredo del corso di
 * programmazione in C su Amiga. Nell'articolo 'corso di c, parte 5 e 6
 * e' contenuta una dettagliata discussione di questo programma e delle
 * funzioni utilizzate. Questo programma e' basato sull'esempio 
 * allegato alla 4a puntata del corso di C. Dove i due programmi coincidono
 * i commenti sono stati notevolmente alleggeriti. Le parti nuove sono
 * evidenziate da delle cornici di asterischi a tutta pagina.
 *
 * In questo programma vengono introdotti elementi di gestione degli
 * eventi attraverso i messaggi di Intuition ed un esempio di uso dei
 * menu a discesa, di lettura del mouse e diverse routines grafiche.
 *
 *************************************************************************/

/*
 Definizione di alcune costanti per aumentare la leggibilita'
 Corrispondono ai menu ed alle voci all'interno  dei menu.
 */

/* Indici dei menu e delle voci nei menu */
#define PROGETTO    0

#define NUOVO       0
#define FINE        1


#define DISEGNO     1

#define MANOLIBERA  0
#define LINEA       1
#define RETTANGOLO  2
#define ELLISSE     3


#define COLORI      2

/* Macro che trasforma in positivo il valore passato */
#define ABS(x) ((x)>0 ? (x): -(x))

/* Comandi alle nostre funzioni grafiche */
#define INIZIO      1
#define MUOVI       2
#define TERMINA     3
#define UNDO        255

/* Stato delle funzioni grafiche */
#define IN_CORSO    1
#define FINITO      255


/* Inclusione dei files di supporto. */
#include <intuition/intuition.h>


/** Dichiarazione e descrizione delle strutture usate nel programma. **/

/* Descrizione del set di caratteri da usare nel nostro schermo. */

struct TextAttr TOPAZ80 = {
    "topaz.font",       /* Nome del set di caratteri */
    8,          /* Altezza dei caratteri */
    0,          /* Stile (0 = nessuno) */
    0           /* Flags (ROM/DISK: 0=ROM) */
    };


/* Questa e' la descrizione del nuovo schermo che vogliamo aprire. */

struct NewScreen nuovo_schermo = {
    0,0,        /* Origine X,Y dello schermo sul display */
    640,200,    /* Larghezza, altezza dello schermo */
    2,      /* Numero di BitPlanes dello schermo. Questo valore
               determina il numero di colori che e' possibile
               visualizzare. Nel nostro caso 4 colori. */
    0,1,        /* Registri colore usati per i dettagli ed i
               blocchi, qui NERO, BIANCO */
    HIRES,      /* Questo flag (alta risoluzione) e' necessario nel
               nostro caso, perche' uno schermo largo 640 punti
               puo' solo essere in alta risoluzione. */
    CUSTOMSCREEN,   /* Non e' uno schermo standard di sistema, quindi
               va specificato CUSTOM.. */
    &TOPAZ80,   /* Puntatore alla struttura TextAttr per Topaz 8 */
    "Schermo Micro Paint",
            /* Titolo dello schermo, compare nella barra */
    NULL,       /* Puntatore al primo custom gadget, non usato */
    NULL        /* Puntatore ad una bitmap 'gia'pronta'. Non usato */
            
    };      /* Fine della struct NewScreen */


/*
 Descrizione di una struttura di tipo NewWindow. Contiene i parametri della
 finestra desiderata.
 */  

struct NewWindow nuova_finestra = {

    0,14,       /* Origine XY della finestra rispetto all'angolo
               superiore sinistro dello schermo */
    640,186,    /* Larghezza e altezza della finestra */
    0,1,        /* Penne (registri colore) da usare per dettagli
               e blocchi. Qui NERO,BIANCO */

            /* IDCMP Flags */
            /* Eventi che si desidera ricevere dalla finestra: */
    CLOSEWINDOW+    /* Chiusura della finestra */
    MOUSEBUTTONS+   /* Pressione/rilascio del tasto sinistro del mouse */
    MOUSEMOVE+  /* Movimento del mouse */
    MENUPICK,   /* Selezione di un menu */

            /* Window Flags, non confondere coi precedenti! */
            /* Flags per gadgets & c che vogliamo avere: */
    WINDOWSIZING+   /* Voglio il gadget di ridimensionamento */
    WINDOWDRAG+ /*  ""      ""  di spostamento */
    WINDOWDEPTH+    /*  ""      ""  di 'profondita' */
    REPORTMOUSE+    /* Voglio che Int. controlli i movimenti del mouse */
    WINDOWCLOSE+    /* Voglio il gadget di chiusura finestra */
    ACTIVATE+   /* Voglio che la finestra si attivi dopo l'apertura */
    NOCAREREFRESH,  /* Non mi interessa sapere se la finestra e' stata
               danneggiata e va ridisegnata (e'l'unica
               finestra sul nostro schermo) */

    NULL,       /* Puntatore al primo gadget 'custom', per noi 0 */
    NULL,       /* Puntatore all'immagine del CheckMark */
    "Micro Paint",  /* Nome che compare nella barra superiore della f. */
    NULL,       /* Puntatore allo schermo. PER ORA nullo */
    NULL,       /* Eventuale bitmap 'fuori schermo' */
    15,15,      /* Minima larghezza e altezza, */
    640,200,    /* Massima larghezza e altezza,*/
    CUSTOMSCREEN    /* Tipo di schermo su cui andra'. */
    };      /* Fine descrizione della struttura NewWindow */



/************************************************************************
 Definizione delle strutture necessarie per i menu. I menu creati
 hanno il seguente aspetto:

 ----------------------------------------
 Progetto   Disegno     Colori
 ----------------------------------------
 Cancella   Mano Libera Colore 0
 Fine       Linea       Colore 1
 ------     Rettangolo  Colore 2
        Ellisse     Colore 3
        ------------    ---------

 Le strutture sono state create con Power Windows 2.5 e ritoccate
 a mano successivamente.  Sono scritte in  ordine inverso,
 partendo cioe' dall'ultima voce dell'ultimo menu (Colore 3),
 per terminare col titolo del primo menu della finestra (Progetto).
 Questo e' necessario in quanto le strutture devono essere
 collegate con una catena di puntatori, ed in genere i compilatori
 hanno dei problemi se si tenta di definire un puntatore ad un
 oggetto che compare piu' avanti (forward reference).

 Compaiono strutture di tipo IntuiText, MenuItem, Menu. Solo la
 prima struttura di ogni tipo e' commentata campo per campo.
 *****************************************************************/

/***** Strutture per il menu COLORI ******************************/

struct IntuiText testo1 = {
    3,1,        /* Colori di testo e sfondo */
    JAM1,       /* Modo grafico */
    19,0,       /* XY dell'angolo sup sin relativo al contenitore */
    NULL,       /* Puntatore al font. NULL = default (topaz)*/
    (UBYTE *)"Colore 3",    /* Puntatore alla stringa di testo */
    NULL        /* Eventuale puntatore all'IntuiText successivo */
};


struct MenuItem voce_menu4 = {
    NULL,       /* Voce successiva in questo menu */
    0,24,       /* XY della voce rispetto alla testata del menu */
    124,8,      /* Larghezza e altezza del box di selezione. */

        /**** Flags Flags Flags Flags *****/
    ITEMTEXT+   /* Questa voce e' una SCRITTA (non un immagine) */
    COMMSEQ+    /* Vogliamo un comando equivalente da tastiera */
    ITEMENABLED+    /* La voce e' attiva e selezionabile */
    HIGHCOMP+   /* Verra' evidenziata in negativo */
    CHECKIT,    /* E' un'opzione che si puo' accendere/spegnere */
            /* piuttosto che un semplice comando da eseguire */

    0xf7,   /*
         Bits di mutua esclusione. L'unico bit spento e' il quarto
         da destra (bit n.3), corrispondente a questa voce, che
         e' la n. 3 nel suo menu. Significa: Quando seleziono
         questa voce, voglio che tutte le altre voci di questo
         menu si spengano (infatti scelgo un solo colore per volta).
        */
    (APTR)&testo1,  /* Oggetto (testo o immagine) Qui testo (IntuiText) */
    NULL,       /* Oggetto alternativo per la selezione */
    '3',        /* Tasto equivalente (Qui Amiga destro-3) */
    NULL,       /* Puntatore alla prima sotto-voce */
    MENUNULL    /* Usato da Intuition, non ci interessa. */
};



struct IntuiText testo2 = {
    2,1,JAM1,
    19,0,
    NULL,
    (UBYTE *)"Colore 2",
    NULL
};

struct MenuItem voce_menu3 = {
    &voce_menu4,
    0,16,
    124,8,
    ITEMTEXT+COMMSEQ+ITEMENABLED+HIGHCOMP+CHECKIT,
    0xfb,
    (APTR)&testo2,
    NULL,
    '2',
    NULL,
    MENUNULL
};



struct IntuiText testo3 = {
    1,0,JAM1,
    19,0,
    NULL,
    (UBYTE *)"Colore 1",
    NULL
};

struct MenuItem voce_menu2 = {
    &voce_menu3,
    0,8,
    124,8,
    ITEMTEXT+COMMSEQ+ITEMENABLED+
    HIGHCOMP+CHECKIT+
    CHECKED,    /****** MARCA questa voce come gia' selezionata *****/

    0xfd,
    (APTR)&testo3,
    NULL,
    '1',
    NULL,
    MENUNULL
};




struct IntuiText testo4 = {
    0,1,JAM1,
    19,0,
    NULL,
    (UBYTE *)"Colore 0",
    NULL
};

struct MenuItem voce_menu1 = {
    &voce_menu2,
    0,0,
    124,8,
    ITEMTEXT+COMMSEQ+ITEMENABLED+HIGHCOMP+CHECKIT,
    0xfe,
    (APTR)&testo4,
    NULL,
    '0',
    NULL,
    MENUNULL
};




/**** Questa struttura e' la testata del menu COLORI *******/
struct Menu menu2 = {
    NULL,       /* Puntatore al Menu successivo (questo e' l'ultimo) */
    200,0,      /* XY del menu rispetto all'angolo sup.sin. schermo */
    55,0,       /* Dimensioni del box di selezione del titolo */
    MENUENABLED,    /* Menu flags, questo menu e' attivo, e le sue voci
               sono selezionabili.  */
    "Colori",   /* Titolo del menu, compare nella barra dello schermo*/
    &voce_menu1 /* Puntatore alla prima voce di questo menu */
};




/***** Strutture per il menu' DISEGNO ******************************/

struct IntuiText testo5 = {
    0,1,JAM1,
    19,0,
    NULL,
    (UBYTE *)"Ellisse",
    NULL
};

struct MenuItem voce_menu8 = {
    NULL,
    0,24,
    155,8,
    ITEMTEXT+COMMSEQ+ITEMENABLED+HIGHCOMP+CHECKIT,
    0xf7,
    (APTR)&testo5,
    NULL,
    'e',
    NULL,
    MENUNULL
};




struct IntuiText testo6 = {
    0,1,JAM1,
    19,0,
    NULL,
    (UBYTE *)"Rettangolo",
    NULL
};

struct MenuItem voce_menu7 = {
    &voce_menu8,
    0,16,
    155,8,
    ITEMTEXT+COMMSEQ+ITEMENABLED+HIGHCOMP+CHECKIT,
    0xfb,
    (APTR)&testo6,
    NULL,
    'r',
    NULL,
    MENUNULL
};




struct IntuiText testo7 = {
    0,1,JAM1,
    19,0,
    NULL,
    (UBYTE *)"Linea",
    NULL
};

struct MenuItem voce_menu6 = {
    &voce_menu7,
    0,8,
    155,8,
    ITEMTEXT+COMMSEQ+ITEMENABLED+HIGHCOMP+CHECKIT,
    0xfd,
    (APTR)&testo7,
    NULL,
    'l',
    NULL,
    MENUNULL
};




struct IntuiText testo8 = {
    0,1,JAM1,
    19,0,
    NULL,
    (UBYTE *)"Mano Libera",
    NULL
};

struct MenuItem voce_menu5 = {
    &voce_menu6,
    0,0,
    155,8,
    ITEMTEXT+COMMSEQ+ITEMENABLED+HIGHCOMP+CHECKIT+CHECKED,
    0xfe,
    (APTR)&testo8,
    NULL,
    'm',
    NULL,
    MENUNULL
};




struct Menu menu1 = {
    &menu2,
    100,0,
    63,0,
    MENUENABLED,
    "Disegno",
    &voce_menu5
};



/***** Strutture per il menu PROGETTO ***************************/

struct IntuiText testo9 = {
    0,1,JAM1,
    0,0,
    NULL,
    (UBYTE *)"Fine",
    NULL
};

/*
 Le due voci del menu progetto non hanno il flag CHECKIT, quindi sono dei
 semplici comandi da lanciare, e non degli interruttori o delle opzioni da
 attivare/disattivare. Notate che gli IntuiText per queste due voci hanno
 un offset X dal contenitore di 0, mentre quelle dei menu precedenti
 avevano un offset di 19, per lasciar spazio all'indicatore di selezione
 "V "(Checkmark).
 */

struct MenuItem voce_menu10 = {
    NULL,
    0,8,
    102,8,
    ITEMTEXT+COMMSEQ+ITEMENABLED+HIGHCOMP,
    0,
    (APTR)&testo9,
    NULL,
    'f',
    NULL,
    MENUNULL
};



struct IntuiText testo10 = {
    0,1,JAM1,
    0,0,
    NULL,
    (UBYTE *)"Nuovo",
    NULL
};

struct MenuItem voce_menu9 = {
    &voce_menu10,
    0,0,
    102,8,
    ITEMTEXT+COMMSEQ+ITEMENABLED+HIGHCOMP,
    0,
    (APTR)&testo10,
    NULL,
    'n',
    NULL,
    MENUNULL
};



struct Menu menu0 = {
    &menu1,
    0,0,
    75,0,
    MENUENABLED,
    "Progetto",
    &voce_menu9
};

/*********************************************************************
 Fine delle definizioni per i menu'.. (phew!). Dato che le definizioni
 sono state scritte in ordine inverso, l'ultima struttura definita 
 e' la 'testa' di tutta la catena dei menu. Passeremo questa struttura
 alla funzione SetMenuStrip per attaccare tutto il menu alla finestra.
 ********************************************************************/



/* Dichiarazione delle variabili 'puntatore a libreria'. */

struct IntuitionBase *IntuitionBase;
struct GfxBase  *GfxBase;


/* Dichiarazione del tipo di valori ritornati dalle funzioni usate. */

extern struct Screen *OpenScreen();
extern struct Window *OpenWindow();
extern struct IntuiMessage *GetMsg();

/*
 Dichiarazione delle variabili che usiamo per immagazzinare i puntatori
 ritornati dall'apertura dello schermo e della finestra.
 */

struct Screen *schermo;
struct Window *finestra;
struct RastPort *RP;


/*****************************************************************
 Dichiarazione delle variabili usate nella gestione degli eventi,
 che ci vengono spediti da Intuition come IntuiMessages.
 Notate la dichiarazione attraverso le macro SHORT,ULONG,USHORT,
 definite in exec/types.h per garantire la compatibilita' di codice
 tra tutti i compilatori. (exec/types.h e' incluso da intuition.h)
 *****************************************************************/

struct IntuiMessage *messaggio; /* Puntatore al messaggio ricevuto */
SHORT   x,y;            /* Posizione del mouse */
ULONG   classe;         /* Classe del messaggio ricevuto */
USHORT  codice;         /* Codice del messaggio ricevuto */

BOOL    continua;       /* Flag. FALSE quando stiamo per uscire */
USHORT  pulsante;       /* Stato del pulsante sin Mouse */



/**** punti estremi del tratto per le routines grafiche ****/
SHORT   x1,y1;
SHORT   x2,y2;



/*********************************************************************
 *          FUNZIONI GRAFICHE
 *
 * Qui di seguito compaiono i moduli che eseguono i comandi grafici.
 * Per espandere il programma, aggiungendo nuove funzioni, basta 
 * inserire le nuove funzioni qui sotto, aggiungere le voci corrispon- 
 * denti nei menu ed inserire i puntatori alle nuove funzioni nella 
 * tabella che compare piu' sotto.
 *
 *********************************************************************/

#define MAX_COMANDI 5

/*  
 Questa costante serve ad evitare che, nell'espandere il programma,
 si selezionino funzioni non ancora implementate-->> GURU. E' scritto
 qui in modo da ricordarsi di correggerlo dopo avere modificato le
 routines, anche se di norma i #define andrebbero in testa al programma.
 */

/*
 Stato della funzione grafica attiva. L'utente puo' fare delle azioni
 (come selezionare i menu) mentre e' in corso un comando grafico. Prima
 di agire dobbiamo allora sapere a che punto sono le routines grafiche.
 */
USHORT  stato;



/*********************************************************************
 * Disegna a mano libera con il mouse. 
 *********************************************************************/
void mano_libera (comando)

    UBYTE comando;

    {
    /* Disegna un punto alla posizione corrente del mouse */
    WritePixel (RP,x,y);

    return();
    }


/*********************************************************************
 * Traccia delle linee rette con il mouse.
 *********************************************************************/
void linea (comando)

    UBYTE comando;

    {
    switch (comando)
        {
        case INIZIO:
            /* Memorizza il punto iniziale della linea */
            x2 = x1 = x;
            y2 = y1 = y;

            /* Usa un tratto 'cancellabile' */
            SetDrMd (RP,COMPLEMENT);

            /* Segnala che un comando e' in esecuzione */
            stato = IN_CORSO;

            break;

        case MUOVI:
            /* Cancella la linea precedente */
            Move (RP,x1,y1);
            Draw (RP,x2,y2);

            /* Memorizza la nuova posizione */
            x2 = x;
            y2 = y;

            /* Disegna una linea fino al nuovo punto */
            Move (RP,x1,y1);
            Draw (RP,x2,y2);

            break;

        case TERMINA:

            /* Usa un tratto non cancellabile */
            SetDrMd (RP,JAM1);

            /* Disegna la linea definitiva */
            Move (RP,x1,y1);
            Draw (RP,x2,y2);

            stato = FINITO;

            break;
        default:
            break;
        }

    return();
    }


/*********************************************************************
 * Traccia dei rettangoli con il mouse.
 *********************************************************************/
void rettangolo (comando)
    UBYTE comando;
    {

    static SHORT disegna;
    
    switch (comando)
        {
        case INIZIO:
            /* Memorizza il punto iniziale del rettangolo */
            x2 = x1 = x;
            y2 = y1 = y;

            /* Usa un tratto 'cancellabile' */
            SetDrMd (RP,COMPLEMENT);

            /* Segnala che un comando e' in esecuzione */
            stato = IN_CORSO;

            break;

        case MUOVI:
            /* Cancella il rett. precedente */
            RectFill (RP,x1,y1,x2,y2);

            /*
             Memorizza la nuova posizione. Consente solo un
             movimento verso destra e verso il basso. (BUG!)
             */
            if (x > x1) x2 = x;
            if (y > y1) y2 = y;

            /* Disegna un rett. fino al nuovo punto */
            RectFill (RP,x1,y1,x2,y2);

            break;

        case TERMINA:

            /* Usa un tratto non cancellabile */
            SetDrMd (RP,JAM1);

            /* Disegna il rett. definitivo */
            RectFill (RP,x1,y1,x2,y2);

            stato = FINITO;

            break;
        default:
            break;
        }
    return();
    }

/*********************************************************************
 * Traccia ellissi/cerchi con il mouse.
 * NB: Il comando grafico DrawEllipse e' L.E.N.T.O!
 *********************************************************************/

void ellisse (comando)
    UBYTE comando;
    {
    switch (comando)
        {
        case INIZIO:
            /* Memorizza il centro dell'ellisse */
            x1 = x;
            y1 = y;

            /* parti con un raggio minimo */
            x2 = 0;
            y2 = 0;

            /* Usa un tratto 'cancellabile' */
            SetDrMd (RP,COMPLEMENT);

            /* disegna il primo punto */
            DrawEllipse (RP,x1,y1,x2,y2);

            /* Segnala che un comando e' in esecuzione */
            stato = IN_CORSO;

            break;

        case MUOVI:
            /* Cancella l'ell. precedente */
            DrawEllipse (RP,x1,y1,x2,y2);

            /*
             usiamo le stesse variabili per memorizzare i
             raggi delle ellissi, come distanza del mouse
             dal centro.
             */
            x2 = ABS(x-x1);
            y2 = ABS(y-y1);

            /* Disegna un'ell. con i nuovi raggi */
            DrawEllipse (RP,x1,y1,x2,y2);

            break;

        case TERMINA:

            /* Usa un tratto non cancellabile */
            SetDrMd (RP,JAM1);

            /* Disegna l'ellisse definitiva */
            DrawEllipse (RP,x1,y1,x2,y2);

            stato = FINITO;

            break;
        default:
            break;
        }
    return();
    }

/**** ...... altre funzioni andranno qui...... ***/

void nulla (comando)
    UBYTE comando;
    {
    return();
    }



/**************************************************************************
 ATTENZIONE ATTENZIONE ATTENZIONE ATTENZIONE ATTENZIONE!

 Questa e' una delle cose piu' complicate che vedrete scritte in C......
 Si tratta dell'uso di una tabella di puntatori a funzioni. Non sarebbe
 strettamente necessario usare un oggetto cosi' criptico, ma, in casi come
 il nostro, consente di scrivere un codice molto compatto, efficiente e
 facilmente espandibile. In generale e' utilissimo ogni volta che il
 programma abbia la struttura di un interprete di comandi modulare.
 Se non altro, vi serva per il momento come allenamento nello scrivere e
 leggere dichiarazioni di variabili in C. Questa dichiarazione non viene
 mostrata nel K&R, ma e' deducibile dalle regole di dichiarazione che vi
 sono descritte.

 void (*comandi_grafici[]) () 

 Si legge:

 '.. comandi_grafici e' un vettore di puntatori a funzioni che non
  ritornano valori (o che non ritornano valori di alcun interesse).. '

 Infatti:
 *comandi_grafici[] Indica che questo e' un vettore di puntatori.

 (*comandi_grafici[])() Gli elementi del vettore sono puntatori a funzioni.
            le parentesi attorno a (*comandi_grafici[]) forzano
            il compilatore a valutare '..l'oggetto puntato dall'
            elemento...' prima di () '...e' una funzione'

 void (*comandi_grafici[])()
            Le funzioni puntate  ritornano void (cioe' nessun
            valore o valori non significativi).


 Cosi' come il NOME di un array o di una struttura per il compilatore
 rappresenta il puntatore al primo elemento della struttura, cosi' il nome
 di una funzione in C rappresenta il puntatore all'inizio del codice
 macchina di quella funzione. Per i programmatori Assembly diremo che
 questa ovviamente e' la versione C di una semplice 'JUMP TABLE'.
 ***************************************************************************/

/* Array di puntatori alle funzioni implementate (o quasi) */

long (*comandi_grafici [MAX_COMANDI]) () =
    {
    mano_libera,
    linea,
    rettangolo,
    ellisse,
    nulla
    };

/* Puntatore alla funzione correntemente attiva */
void (*comando)() = mano_libera;

/*
 Vorrei farvi notare che la notazione incontrata piu' avanti,
    (*comando)(xxxx)
 signfica (visto che 'comando' e' un puntatore a funzione);
 ' chiama la funzione puntata da 'comando' passando il parametro xxxx'
 In questo modo possiamo scrivere un codice unico, che chiama una funzione
 indeterminata (quella attivata da menu e che ha il suo puntatore in
 'comando'). Se non facessimo cosi' dovremmo scrivere:

  if (com==0) mano_libera(xxxx);
  if (com==1) linea(xxxx);
  ................
  e cosi' via per tutti i comandi implementati e per ogni comando che
  volessimo aggiungere. Prima di passare al comando il programma passerebbe
  sempre per una serie di test inutili, perdendo in velocita' e aumentando
  di dimensioni... potenza del C (provate a farlo in Pascal)!
  */



/*********************************************************************
 *          scelta_menu ()
 *
 * Decodifica un evento di selezione di una voce dai menu e agisce.
 * Si sarebbe potuto farlo in main() all'interno del ciclo di gestione
 * degli eventi, ma avrebbe portato allla scrittura di troppi switch()
 * nidificati ed il programma sarebbe diventato poco leggibile.
 *
 *********************************************************************/

/*********************************************************************
 Questa funzione contiene comandi switch() nidificati a 2 livelli.
 E' molto facile dimenticarsi dei break; o delle parentesi. Per
 semplificare le cose e ridurre la possibilita' di errori consiglio
 di scrivere uno schema switch(){} vuoto come il seguente :

        switch (xxxxxx)
            {

            case 0:
                break;

            case 1:
                break;

            case 2:
                break;

            case 3:
                break;

            .... etc.
                ... etc...

            } / fine switch (xxxxx) /

 ...e di copiarlo coi comandi CUT/PASTE dell'editor nei punti necessari.
 Potete poi procedere a riempire i case: con il codice del programma.

 NB: /.. / e' un commento intenzionalmente scritto senza asterischi:
     NON si possono scrivere commenti all'interno di altri commenti!

 ************************************************************************/


scelta_menu (menu,voce)
    ULONG   menu;
    USHORT  voce;
    {

    switch (menu)
        {

        /* PROGETTO = 0: costante #definita all'inizio.. */
        case PROGETTO:

            /* Termina il comando corrente */
            if (stato != FINITO) (*comando) (TERMINA);

            switch (voce)
                {

                case NUOVO:

                    /* Cancella tutta la finestra */
                    SetRast (RP,0);

                    /* Ri-disegna il contorno */
                    RefreshWindowFrame (finestra);

                    break;

                case FINE:

                    /* Causa uscita dal loop eventi */
                    continua = FALSE;
                    break;

                default:
                    break;

                } /* fine voci in PROGETTO */
            break;


        case DISEGNO:
            /*
             Nessun switch(), perche' la meccanica e'
             la stessa per tutte le voci del menu.
             */
            
            /* Termina il comando corrente */
            if (stato != FINITO)    (*comando) (TERMINA);

            /* Attiva il comando scelto */
            if (voce < MAX_COMANDI)
                comando  = comandi_grafici[voce];
            break;


        case COLORI:
            /*
             Nessun switch(), perche' la meccanica e'
             la stessa per tutte le voci del menu.
             */

            /* Usa colore corrispondente alla voce selezionata */
            SetAPen (RP,voce);
            break;

        } /* fine switch (menu) */

    return();
    } /* fine scelta_menu() */




/*********************************************************************
 *          main()
 * Funzione principale e punto d'ingresso nel programma.
 *
 * Apre le risorse (librerie, schermo finestra),
 * esegue in un ciclo di attesa_eventi-decodifica-azione,   
 * rilascia le risorse utilizzate ed esce.
 *
 *********************************************************************/

main () {

    /* Apertura delle librerie usate. Qualsiasi versione va bene. */

    IntuitionBase = (struct IntuitionBase *) OpenLibrary ("intuition.library",0);
    if (IntuitionBase == NULL) goto pulizia;

    GfxBase = (struct GfxBase *) OpenLibrary ("graphics.library",0);
    if (GfxBase == NULL) goto pulizia;


    /* Apertura dello schermo. */ 
    schermo = OpenScreen (&nuovo_schermo);
    if (schermo == NULL) goto pulizia;

    /* Mettiamo in nuova_finestra il puntatore allo schermo */
    nuova_finestra.Screen = schermo;

    /* Possiamo ora aprire la finestra. */
    finestra = OpenWindow (&nuova_finestra);
    if (finestra == NULL) goto pulizia;

    /* Recuperiamo il puntatore alla RastPort della finestra. */
    RP = finestra->RPort;

    /* Attacchiamo i nostri menu alla finestra */
    SetMenuStrip (finestra, &menu0);

    /* Scegliamo una 'penna' bianca, registro colore 1 nella palette. */
    scelta_menu (COLORI,1);

    /* Selezioniano la voce 'mano libera' */
    scelta_menu (DISEGNO, MANOLIBERA);


    /*****************************************************************
     Attesa e decodifica dei messaggi mandati da Intuition.
     ****************************************************************/

    continua = TRUE;

    while (continua)
        {
        /* Guarda se sono gia' arrivati dei messaggi */
        if ((messaggio = GetMsg (finestra->UserPort))==NULL) 
            {
            /* Attendi che Intuition suoni alla finestra (!) */
            Wait (1 << finestra->UserPort->mp_SigBit);

            /* Intuition ha suondato, torna a prendere il messaggio */
            continue;
            }

        /* Copia i campi che ci interessano nelle nostre variabili */
        classe = messaggio->Class;
        codice = messaggio->Code;
        x = messaggio->MouseX;
        y = messaggio->MouseY;
    
        /* Rimanda il messaggio al mittente */
        ReplyMsg (messaggio);

        /*
         Decodifica in base al tipo di evento. Gli eventi che
         compaiono qui corrispondono a quelli scritti nella
         definizione della finestra.
         */
        switch (classe)
            {
            case MENUPICK:
                /* esegue la decodifica in una funzione */
                scelta_menu (MENUNUM (codice), ITEMNUM (codice));
                break;

            case MOUSEBUTTONS:
                /* Registra lo stato del pulsante mouse */
                pulsante = codice;

                /* Inizia il comando corrente */
                switch (pulsante)
                    {
                    /* lancia il comando corrente */
                    case SELECTDOWN:
                        (*comando)(INIZIO);
                        break;

                    /* Termina il comando corrente */
                    case SELECTUP:
                        (*comando)(TERMINA);
                        break;

                    default:
                        break;
                    }
                break;

            case MOUSEMOVE:
                /* Trasmetti il movimento al comando attivo */
                if (pulsante==SELECTDOWN)
                    (*comando) (MUOVI);
                break;

            case CLOSEWINDOW:
                /* Termina il comando corrente */
                if (stato != FINITO)
                    (*comando) (TERMINA);

                /* Segnala che usciamo dal loop */
                continua = FALSE;
                break;

            default:
                break;
            }
        }
    /* */

pulizia:

    ClearMenuStrip (finestra);
    if (finestra != NULL)   CloseWindow (finestra);
    if (schermo != NULL)    CloseScreen (schermo);
    if (GfxBase != NULL)    CloseLibrary (GfxBase);
    if (IntuitionBase != NULL) CloseLibrary (IntuitionBase);

    exit (0);

    } /* fine della definizione di main() */
