/***************************************************************************/
/*                                                                         */
/*        demo.c  -  v. 2.0  -  8.88  -  Antonio Ferrillo                  */
/*                                                                         */
/*     programma dimostrativo dell'utilizzo delle funzioni di gestione     */ 
/*     del console.device e dei menus residenti in libreria privata        */ 
/*                                                                         */
/*         versione Aztec v. 3.4  -  Lattice v. 3.10                       */
/*                                                                         */
/***************************************************************************/ 

  #include <functions.h>  /* rimuovere questa linea se si usano i
                             compilatori Lattice v. 3.XX     */

  #include <prifunc.h>    /* vedere testo dell'articolo  */ 

  #include <exec/types.h>
  #include <intuition/intuition.h>
  #include <graphics/rastport.h>
  #include <devices/input.h>

/* definizione puntatore alla intuition library                            */

  struct IntuitionBase *IntuitionBase;

/* definizione della funzione esterna Window_Addr()  residente in 
   libreria privata che fornisce l'indirizzo della struct Window           */       

  struct  Window  *Window_Addr();

/* dichiarative per la gestione dell'input.device                          */  

  struct   InputEvent     Mousev;  /* struttura InputEvent       */
  struct   IOStdReq       *Req;   /* puntatore al blocco IORequest */
  struct   MsgPort        *Porto; /* puntatore alla MsgPort */

  char *cosa;	             /*      puntatori alle stringhe               */
  char *al_mess[4];          /*      per il display del recovery Alert     */ 
 
/* definizione e inizializzazione dell'array che passeremo come argomento 
   alla funzione Menu_Set.
   Essendo possibile gestire max 5 tendine ognuna delle quali puo' contenere 
   max 8 possibilita' di scelta (items) e nell'ambito di ognuna di queste 
   possono essere contenute ancora 4 possibilita' (subitem) noi definiremo
   una tabella quadridimensionale contenente max 5 elementi-menu' (tendine) 
   ognuno dei quali contiene max 9 elementi_item (1 per l'header sulla 
   barra + 8 per gli items) ognuno dei quali contiene max 5 elementi-stringhe
   (1 per l'item + 4 per i subitems associati) ognuno dei quali contiene
   max 12 elementi carattere (Il primo elemento e' il carattere di comando 
   da tastiera in alternativa al mouse : se non lo si vuol usare inserire
   uno spazio, seguono 10 caratteri per il testo + '\0' aggiunto dal 
   compilatore).
   Naturalmente inizializzeremo solo gli elementi che ci servono ma e' 
   necessario, per il buon funzionamento della routine Menu_Set, dimensionare
   l'array come indicato.                                                  */

  char menu[5][9][5][12] =
  {
       {
             {"PRIMI "},
             {" PENNE","BBOLOGNESE","RAL RAGU'","AARRABBIATA","ZZINGARA"}, 
             {" SPAGHETTI","PPOMODORO","V VONGOLE"},
             {" RISOTTO","MMILANESE"," PESCATORA"},
             {" MINESTRE","FAI FAGIOLI"," VERDURE"},
	     {"CCONSOMME'"}
       },
       {
             {"SECONDI"},
             {" CARNE"," BOLLITA"," ALLA BRACE"},
             {" FIORENTINA"},
             {" PESCE"," AL FORNO"," ALLA BRACE"},
             {" UOVA","TTEGAMINO","SSODE"}
       },
       {
             {"FORMAGGI"},
             {"GGRANA"},
             {" GORGONZOLA"},
             {" FRANCESI"," CAMEMBERT"," CAPRICE"},
	     {" PROVOLONE"},
	     {"EEDAM"},
             {" MOZZARELLA"},
             {" FONTINA"},
             {" STRACCHINO"} 
       },
       {
             {"DOLCI"},
             {" CASSATA"},
             {" TORTE"," CIOCCOLATO"," ST.HONORE'"},
             {" PASTIERA"},
	     {" CROSTATA"," DI MELE"," DI PESCHE"}
       },
       {
             {"FRUTTA"},
             {" ESOTICA","NANANAS"," MANGO"," PAPAYA","JBANANA"},
             {" NOSTRANA"," PERE"," PESCHE"},
             {"KMACEDONIA"}
       }

  };

  void Call_Al();       /*  arrangiamento messaggio per l'Alert  */
  void Alert_Dis();     /*  display recovery Alert   */
  void OpenIntuiLib();  /*  apertura intuition.library  */
  void OpenScr();       /*  apertura schermo  */
  void OpenWin();       /*  apertura finestra  */
  void ConsDevDemo();   /*  dimostrazione console.device  */ 
  void MenusDemo();     /*  dimostrazione menus  */
  void MenuMouse();     /*  emulazione scelta menus e chiusura finestra */
  void EndProg();       /*  operazioni di chiusura  */            
  void GestMessaggi();  /*  intercettazione messaggi IDCMPs */

  int indscr,indwin,indcondev,indinpdev,indmenu;

/*         corpo principale del programma                                  */  
  void
  main()
  {
    OpenIntuiLib();
    OpenScr();
    OpenWin();
    ConsDevDemo();
    MenusDemo();
  }


/* routine elaborative richiamate nel corpo principale, quelle di 
   apertura comprendono il controllo di successo dell'operazione con il 
   display di un Alert di tipo 'RECOVERY' e uscita dall'elaborazione in 
   caso di fallimento                                                      */

/* routine apertura della libreria delle routines per la gestione di 
   Intuition residenti in ROM richiamate durante l'esecuzione              */

    void	
    OpenIntuiLib()
    {
      IntuitionBase =  (struct IntuitionBase *)
                        OpenLibrary("intuition.library", 0L);
        if (IntuitionBase == NULL)
        {
          cosa="intuition.library";
          Call_Al();
          EndProg(); 	
        } 
    }

/* apertura dello schermo  mediante il richiamo della routine 
   Screen_Open() catalogata in libreria privata                            */

    void
    OpenScr()
    {
       indscr = Screen_Open (1,"DEMO console.device - menus",0,256,0,1,2,3); 
          if (indscr == 0)         
          {
            cosa="SCHERMO";
            Call_Al();
            EndProg();
          }
    } 


/* apertura finestra                                                       */

    void
    OpenWin()
    {
        indwin =  Window_Open (1,"DEMO console.device",0,10,640,246,1,0,1);
           if (indwin == 0)
           {
             cosa="FINESTRA";
             Call_Al();
             EndProg();      
           }
    } 

/*  dimostrazione console.device                                           */    

    void
    ConsDevDemo()
    {
      int colbg = 7;
      int linea = 1;
      int colonna = 1;
      int nchar;
      char buflet[78];
      char *stringa;

/*  apertura console.device         */   

      indcondev = Con_Open(1);  
      if (indcondev == 0)
           {
             cosa="console.device";
             Call_Al();
             EndProg();
           }
 
/* reset finestra col colore colbg  */    

      while(colbg)           
      {
        Delay(50L);
        Con_Clescr(colbg);
        colbg--;
      }

/* posizionamento cursore e reset finestra da cursore col colore colbg    */
   
      for ( linea=2; linea < 28; linea++) 
      {        
        Delay(30L);
        colbg = linea % 7;
        Con_Poscur(linea,colonna);
        Con_Clecur(colbg);
      }
   
/* posizionamento cursore e reset linea da cursore in poi      */ 

      for (colonna = 1 ; colonna < 79; colonna++)
      {                              
        Delay(10L);
        colbg = colonna % 7;
        Con_Poscur(linea,colonna);
        Con_Clelin(colbg);
      }   

/* scrittura di un testo e sparizione cursore  */

     
      Con_Write(29,1,3,2,3,"SPARIZIONE CURSORE  ----------------->");
      Delay(50L);     
      Con_Cursoff();  

/* scrittura di un testo e riapparizione cursore  */

      Delay(100L);
      Con_Write(29,1,3,2,3,"RIAPPARIZIONE CURSORE  -------------->");
      Con_Curson();

/* scrittura di un testo e lettura di una stringa di max 10 caratteri */
     
      Delay(100L);
      Con_Write(15,1,0,1,2,"digitare max 10 caratteri e premere return");
      nchar =  Con_Read(15,50,1,4,5,buflet,10);

/* scrittura stringa digitata e numero dei caratteri digitati    */

      stringa = "stringa digitata :           n. caratteri :   ";
      stringa[44] = nchar / 10 | 48;
      stringa[45] = nchar % 10 | 48;
      nchar = 0;
      while( stringa[19+nchar] = buflet[nchar] ) nchar++;  
      stringa[19+nchar] = ' ';
      Con_Write(17,1,0,2,3,stringa);

/* scroll in alto                 */

      for (nchar=0; nchar < 29; nchar++)
      {
        Delay(10L);
        Con_Scrollup();
        Con_Write(30,1,7,2,6,"----------SCROLL  UP-------------");
      }

/* scroll in basso                 */

      for (nchar=0; nchar < 36; nchar++)
      {
        Delay(10L);
        Con_Scrolldown();
        Con_Write(1,1,7,2,5,"----------SCROLL  DOWN-----------");
      }
  }

/*   dimostrazione gestione menus                                          */
 
    void
    MenusDemo()
    {

/* cambio del titolo della finestra il terzo argomento : -1L 
   fa lasciare inalterato il titolo dello schermo                          */  

  SetWindowTitles(Window_Addr(1),"DEMO GESTIONE menus",-1L);

/* apertura input device per emulare i movimenti del mouse                */

   Porto  = (struct MsgPort *)CreatePort (0L,0L);
   if (Porto == NULL)
   {
     cosa="Porto input.device";
     Call_Al();
     EndProg();
   }

   Req    = (struct IOStdReq *)CreateStdIO (Porto);
   if (Req == NULL)
   {
     cosa="IORequest input.device";
     Call_Al();
     EndProg();
   }

   if ( OpenDevice ("input.device",0L,Req,0L) != 0L )
   {
    indinpdev = 0;
    cosa="input.device";
    Call_Al();
    EndProg();      
   }

   Req -> io_Command = IND_WRITEEVENT;
   Req -> io_Flags   = 0;
   Req -> io_Length  = sizeof (struct InputEvent);
   Req -> io_Data    = (APTR) &Mousev;

/* aggancio menus alla finestra                               */

   indmenu = Menu_Set(1,1,menu);
   if (indmenu == 0)         
   {
     cosa="MENUS";
     Call_Al();
     EndProg();
   }

/* emulazione selezione menus                             */

   MenuMouse(1,3,1);    /* selezione menu  */
   GestMessaggi();      /* cattura messaggio menu selezionato */
   MenuMouse(1,3,1);    /* visualizzazione stesso menu disattivato  */

   MenuMouse(2,2,0);
   GestMessaggi();
   MenuMouse(2,2,0);

   MenuMouse(5,1,4);
   GestMessaggi();
   MenuMouse(5,1,4);
  
   MenuMouse(3,3,2);
   GestMessaggi();
   MenuMouse(3,3,2);
  
   MenuMouse(4,4,1);
   GestMessaggi();
   MenuMouse(4,4,1);

/*  emulazione chiusura finestra                 */

   Mousev.ie_Class = IECLASS_RAWMOUSE;
   Mousev.ie_Code = IECODE_NOBUTTON ;
   Mousev.ie_Y   = -524;
   Mousev.ie_X   = -704;
   DoIO (Req); 
     
   Mousev.ie_Y   = 30;
   Mousev.ie_X   = 10;
   DoIO (Req);

   Mousev.ie_Y   = 0;
   Mousev.ie_X   = 0; 
   Mousev.ie_Code = IECODE_LBUTTON;
   DoIO(Req);   
   Delay(150L); 

   Mousev.ie_Code = IECODE_LBUTTON + IECODE_UP_PREFIX;
   DoIO(Req);
   GestMessaggi();
  }

/* intercettazione dei messaggi riguardanti i movimenti del mouse emulati
con l'input device, e ricevuti tramite IDCMPs di Intuition             */ 
 
   void
   GestMessaggi()
   {

/* definizione campi per la gestione dei messaggi ricevuti da Intuition 
   mediante IDCMP. ULONG e USHORT sono ridefinizioni di tipo di dato 
   contenute nella <exec.types.h>                                          */

  struct IntuiMessage *messaggio;
  ULONG TipoMessaggio;  
  USHORT numes;         

/* definizione comodi di lavoro                      */
    
      int nmenu,nitem,nsub,k;
      char *strmen;
      cosa = "menu selezionato :                                    "; 
      strmen = cosa;
      cosa += 19;

      Wait(1L << Window_Addr(1)->UserPort->mp_SigBit);

      while ( messaggio = (struct IntuiMessage *)
                GetMsg(Window_Addr(1)->UserPort))
      {
        TipoMessaggio = messaggio->Class;
        numes = messaggio->Code;
        ReplyMsg(messaggio);
        switch (TipoMessaggio)
        {
          case CLOSEWINDOW :  EndProg();
          case MENUPICK    :  if (numes == MENUNULL) break; 
                              nmenu = MENUNUM(numes);
                              nitem = ITEMNUM(numes);
                              nsub = SUBNUM(numes); 
             k = 0;
             while(*++cosa = menu[nmenu][0][0][k]) k++;                   
             *cosa = ' ';
             k=1;           
             while(*++cosa = menu[nmenu][nitem+1][0][k]) k++;
             if (nsub != NOITEM)
             {
              *cosa = ' ';
              k= 1;                   
              while(*++cosa = menu[nmenu][nitem+1][nsub+1][k]) k++;                   
             }
              
             Con_Write(15,1,0,0,1,strmen);
             Con_Scrollup();

             Menu_OnOff(1,0,nmenu+1,nitem+1,nsub+1);
             break;
   
           }   /* switch */
      }  /* while */
   }   /* GestMessaggi() */
      
/* routine simulazione selezione menus                                     */

  void 
  MenuMouse(men,it,sub)
  int men,it,sub;
  {
   int mx,my;

/* azzeramento posizione del mouse  */

   Mousev.ie_NextEvent          = NULL;            
   Mousev.ie_Class              = IECLASS_RAWMOUSE;
   Mousev.ie_TimeStamp.tv_secs  = 0;
   Mousev.ie_TimeStamp.tv_micro = 0;
   Mousev.ie_Code               = IECODE_RBUTTON;
   Mousev.ie_Qualifier          = IEQUALIFIER_RELATIVEMOUSE;
   Mousev.ie_Y   = -524;
   Mousev.ie_X   = -704;
   DoIO (Req);     

   Mousev.ie_Y  = 5;
   DoIO(Req);

/* posizionamento sul menu  */

   Mousev.ie_Y   = 0;
   Mousev.ie_X   = 1;
   for(mx = 0; mx < (men * 100 - 50); mx++)  DoIO (Req); 

/* posizionamento sull'item  */
 
   Mousev.ie_Y   = 2;
   Mousev.ie_X   = 0;
   for(my = 0; my < (it * 10 + 5); my++) { Delay(1L); DoIO (Req); }

/* posizionamento sul subitem  */

   mx = 0;
   my = 0;

   Mousev.ie_Y   = 0;
   Mousev.ie_X   = 1;
   while(sub != 0 && mx < 120) { mx++; DoIO (Req); }

   Mousev.ie_Y   = 2;
   Mousev.ie_X   = 0;
   while(sub != 0 && my < (sub * 10 - 10)) { Delay(1L);  my++; DoIO (Req); }

   Delay(100L);
   Mousev.ie_Code = IECODE_RBUTTON + IECODE_UP_PREFIX;
   DoIO (Req);

  }


/* routine di arrangiamento prima riga di messaggio dell'Alert             */       
   void
   Call_Al()
   {
   int k=0;
   al_mess[0] = "ERRORE IN APERTURA                    ";
   al_mess[1] = "PROSECUZIONE IMPOSSIBILE";
   al_mess[2] = "CLICKARE SU UNO DEI PULSANTI DEL MOUSE";
   while(*(al_mess[0]+19+k) = *cosa++) k++;
   al_mess[3] = '\0';
   Alert_Dis(al_mess);
   }

/* routine di arrangiamento degli argomenti richiesti dalla funzione di 
   Intuition  DisplayAlert()                                               */
 
   void
   Alert_Dis(testo)
     char  *testo[];
   {
   short colonna = 84;
   char dispmess[260];
   char *mess, *col;
   int n;
   long tipo = RECOVERY_ALERT;
   mess = dispmess;
   col = &colonna;
      for ( n=0; n<4; n++ )
      {
      if(*testo[n] == '\0') break;
      *mess = *col;
      *++mess =*(col+1);
      *++mess = (char)3+(9*(n+1));
      while(*++mess = *testo[n]++); 
      *++mess = (char)1;
      mess++;
      }
   *mess = '\0';
   DisplayAlert(tipo,dispmess,50L);
   }

  void
  EndProg()
  {
    if (indmenu) Menu_Reset(1);
    if (indinpdev) CloseDevice(Req);
    if (Req)  DeleteStdIO(Req);
    if (Porto) DeletePort(Porto);
    if (indcondev) Con_Close();
    if (indwin) Window_Close(1);
    if (indscr) Screen_Close(1);
    if (IntuitionBase) CloseLibrary(IntuitionBase);
    exit(0L);
  }

