 /********************************************************************/
 /****                                                            ****/
 /****                                                            ****/
 /****    Program          : SimpleMenu.c                         ****/
 /****                                                            ****/
 /****    Version          :    03.71                             ****/
 /****                                                            ****/
 /****    Erstversion      : 14.03.1990                           ****/
 /****                                                            ****/
 /****    Letzte Änderung  : 08.08.1990                           ****/
 /****                                                            ****/
 /****    Compiliert mit   : siehe MAKEFILE                       ****/
 /****                                                            ****/
 /****    Gelinkt mit      : siehe MAKEFILE                       ****/
 /****                                                            ****/
 /********************************************************************/
 /****                                                            ****/
 /****                                                            ****/
 /****               Copyright by Rüdiger Dreier                  ****/
 /****                                                            ****/
 /****                                                            ****/
 /********************************************************************/
 
 #include <exec/types.h>
 #include <stdio.h>
 #include <intuition/intuition.h>
 #include <intuition/intuitionbase.h>
 #include <exec/types.h>
 #include <exec/memory.h>
 #include <proto/dos.h>
 #include <proto/exec.h>
 #include <proto/intuition.h>
 #include <stdio.h>
 #include <string.h>
 
 /* Gibt Zeiger auf das letzte definierte Menu zurück */
 struct Menu * __asm LastMenu(register __a0 struct Menu *menu)
  {
   if(menu==NULL)return(NULL); /* Kein Menu definiert */
   
   while(menu->NextMenu!=NULL)
    {
     menu=menu->NextMenu;
    }
   return(menu);
  }
 
 
 /* Gibt Zeiger auf das letzte definierte Item zurück */
 struct MenuItem * __asm LastItem(register __a0 struct Menu *menu)
  {
   struct MenuItem *item;
   if(menu==NULL)return(NULL); /* Kein Menu definiert  */
   
   menu=LastMenu(menu);        /* Der letzte MenuPunkt */
   
   item=menu->FirstItem;
   if(item==NULL)return(NULL); /* Kein Item */
   
   
   while(item->NextItem!=NULL)
    {
     item=item->NextItem;
    }
   return(item);               /* Das letzte Item      */
  }
 
 
 /* Gibt Zeiger auf das letzte definierte SubItem zurück */
 struct MenuItem * __asm LastSub(register __a0 struct Menu *menu)
  {
   struct MenuItem *item,*sub;
   if(menu==NULL)return(NULL); /* Kein Menu definiert   */
   
   item=LastItem(menu);        /* Der letzte ItemPunkt  */
   
   sub=item->SubItem;
   if(sub==NULL)return(NULL); /* Kein SubItem */
   
   while(sub->NextItem!=NULL)
    {
     sub=sub->NextItem;
    }
   return(sub);                /* Das letzte SubItem    */
  }
 
 
 /* Hängt ein Menu an */ 
 struct Menu * __asm AddMenu(register __a0 struct Menu *menu,
                             register __a1 char *Titel,
                             register __d0 USHORT Flags)
  {
   struct Menu *newmenu,*lastmenu;
   struct IntuiText Hilfe;
   
   newmenu=AllocMem(sizeof(struct Menu),MEMF_CLEAR|MEMF_PUBLIC);
   if(newmenu==NULL)return(NULL); /* Kein Speicher für Menu */
   
   /* Den Speicher hab ich jetzt. Jetzt kann die Struktur */
   /* gefüllt werden.                                     */
   
   lastmenu=LastMenu(menu);
   if(lastmenu!=NULL)
    {
     /* Wenn schon ein Menu vorhanden, sonst 0 */
     newmenu->LeftEdge=lastmenu->LeftEdge+lastmenu->Width;
     lastmenu->NextMenu=newmenu;
    }
   newmenu->MenuName=Titel;
   newmenu->Flags=Flags;
   Hilfe.ITextFont=0;
   Hilfe.IText=Titel;
   newmenu->Width=(IntuiTextLength(&Hilfe)+8);
   return(newmenu);  /* Ist das erste Menu    */
  }
 
 
 /* Hängt ein Item an */ 
 struct Item * __asm AddItem(register __a0 struct Menu *menu,
                             register __a1 char *Titel,
                             register __d0 USHORT Flags,
                             register __d1 char HotKey)
  {
   struct Menu *lastmenu;
   struct MenuItem *newitem,*lastitem;
   
   newitem=GetItem(menu,Titel,Flags,HotKey); /* Speicher für Item holen */
   if(!newitem)return(NULL);
   
   lastmenu=LastMenu(menu);
   lastitem=LastItem(menu);
   
   if(lastitem==NULL) /* Item in Liste einfügen */
    {
     lastmenu->FirstItem=newitem;
    }
   else
    {
     lastitem->NextItem=newitem;
    }
   return(newitem);
  }
 
 
 /* Hängt ein SubItem an */ 
 struct Item * __asm AddSub(register __a0 struct Menu *menu,
                            register __a1 char *Titel,
                            register __d0 USHORT Flags,
                            register __d1 char HotKey)
  {
   struct MenuItem *newsub,*lastitem,*lastsub;
   
   lastitem=LastItem(menu);
   lastsub =LastSub(menu);
   if(lastitem==NULL)return(NULL); /* Ohne Item kein SubItem */
   
   newsub=GetItem(menu,Titel,Flags,HotKey); /* Speicher für Item holen */
   if(newsub==NULL)return(NULL); /* Kein Speicher für Item */
   
   if(lastsub==NULL) /* Item in Liste einfügen */
    {
     lastitem->SubItem=newsub;
    }
   else
    {
     lastsub->NextItem=newsub;
    }
   return(newsub);
  }
 
 
 /* Holt und füllt dem Speicher für ein Item oder SubItem */
 struct MenuItem * __asm GetItem(register __a0 struct Menu *menu,
                                 register __a1 char *Titel,
                                 register __d0 USHORT Flags,
                                 register __d1 char HotKey)
  {
   struct IntuiText *newtext;
   struct MenuItem *newitem;
   SHORT addwidth=0;
   
   if(menu==NULL)return(NULL);  /* Ohne Menu kein Item             */
   if(Titel==NULL)return(NULL); /* Ohne Text oder Grafik kein Item */
   
   newitem=AllocMem(sizeof(struct MenuItem),MEMF_CLEAR|MEMF_PUBLIC);
   if(newitem==NULL)return(NULL); /* Kein Speicher für Menu */
   if(Titel&&(Flags&ITEMTEXT))
    {
     /* Nur, wenn keine Grafik */
     newtext=AllocMem(sizeof(struct IntuiText),MEMF_CLEAR|MEMF_PUBLIC);
     if(newtext==NULL)
      {
       /* Kein Speicher für IntuiText */
       FreeMem(newitem,sizeof(struct MenuItem));
       return(NULL);
      }
     /* Den Speicher hab ich jetzt. Jetzt können die Strukturen */
     /* gefüllt werden.                                         */
     if(menu->FirstItem)
      {
       newtext->FrontPen=((struct IntuiText *)menu->FirstItem->ItemFill)->FrontPen;
       newtext->BackPen =((struct IntuiText *)menu->FirstItem->ItemFill)->BackPen;
       newtext->DrawMode=((struct IntuiText *)menu->FirstItem->ItemFill)->DrawMode;
      }
     else
      {
       newtext->FrontPen=2;   /* BackPen = 0 */
       newtext->DrawMode=JAM1;
      }
     newtext->IText=Titel;
     newtext->LeftEdge=3;
    }
   
   if(Flags&COMMSEQ)addwidth=40; /* reicht für Standart-Symbol */
   if(Flags&ITEMTEXT)
    {
     newitem->ItemFill=(APTR)newtext;
     newitem->Width=IntuiTextLength(newtext)+addwidth+7;
    }
   else
    {
     newitem->ItemFill=(APTR)Titel;
     newitem->Width=addwidth+((struct Image *)Titel)->Width+((struct Image *)Titel)->LeftEdge;
     newitem->Height=((struct Image *)Titel)->Height+((struct Image *)Titel)->TopEdge;
    }
   newitem->Flags=Flags;
   newitem->Command=HotKey;
   
   return(newitem);
  }
 
 
 /* Gibt den ganzen Speicher wieder frei */
 VOID __asm ClearMenu(register __a0 struct Menu *menu)
  {
   struct MenuItem *item,*sub;
   if(menu==NULL)return;
   
   while(menu)
    {
     item=menu->FirstItem;
     while(item)
      {
       sub=item->SubItem;
       while(sub)
        {
         sub=FreeItem(sub);
        }
       item=FreeItem(item);
      }
     menu=FreeMenu(menu);
    }
  }
 
 
 struct MenuItem * __asm FreeItem(register __a0 struct MenuItem *item)
  {
   struct MenuItem *next=item->NextItem;
   if((item->Flags&ITEMTEXT))FreeMem(item->ItemFill,sizeof(struct IntuiText));
   FreeMem(item,sizeof(struct MenuItem));
   return(next);
  }
 
 
 struct Menu * __asm FreeMenu(register __a0 struct Menu *menu)
  {
   struct Menu *next=menu->NextMenu;
   FreeMem(menu,sizeof(struct Menu));
   return(next);
  }
 
 
 /* Gleicht die Höhe der Items an, je nach Font im RastPort */
 VOID __asm NewSetMenuStrip(register __a1 struct Window *Window,
                            register __a0 struct Menu *menu)
  {
   struct MenuItem *item,*sub;
   struct Menu *MENU;
   SHORT hoehe,topedges,topedgei,maxwidthi,maxwidths,diff,v;
   
   if(menu==NULL)return; /* Notausgang */
   
   MENU=menu;            /* Merken     */
   hoehe=Window->RPort->TxHeight; /* Fonthöhe        */
   v=Window->WScreen->Height-16;  /* Höhe des Screen */
   
   while(menu)
    {
     item=menu->FirstItem;
     if(item)topedgei=item->TopEdge;
     while(item)
      {
       sub=item->SubItem;
       if(sub)topedges=5;
       while(sub)
        {
         /* Subs einpassen */
         sub->TopEdge=topedges;
         if(sub->Height==NULL)
          {
           sub->Height=hoehe;
           topedges+=hoehe;
          }
         else
          {
           topedges+=sub->Height;
          }
         sub=sub->NextItem;
         if(!sub)
          {
           diff=v-topedges-topedgei;
           /* Hier wird kontrolliert, ob die SubItems zu weit nach unten reichen */
           /* Wenn dies der Fall ist, werden sie nach oben verschoben.           */
           /* Es wird NICHT geprüft, ob sie dadurch zu weit nach oben reichen.   */
           /* Der Vergleichswert von 240 gilt für eine Screen mit 256 Zeichen.   */
           if(diff<0)
            {
             sub=item->SubItem;
             while(sub)
              {
               sub->TopEdge+=diff;
               sub=sub->NextItem;
              }
            }
          }
        }
       
       /* Items einpassen */
       item->TopEdge=topedgei;
       if(item->Height==NULL)
        {
         item->Height=hoehe;
         topedgei+=hoehe;
        }
       else
        {
         topedgei+=item->Height;
        }
       item=item->NextItem;
      }
     menu=menu->NextMenu;
    }
   
   menu=MENU;
   while(menu)
    {
     maxwidthi=menu->Width;
     item=menu->FirstItem;
     while(item)
      {
       /* 1. Pass: maxwidth feststellen */
       maxwidths=0;
       sub=item->SubItem;
       while(sub)
        {
         /* 1. Pass: maxwidth feststellen */
         maxwidths=max(sub->Width,maxwidths);
         sub=sub->NextItem;
        }
       sub=item->SubItem;
       while(sub)
        {
         /* 2. Pass: maxwidth einsetzen */
         sub->Width=maxwidths;
         sub=sub->NextItem;
        }
       
       /* Items einpassen */
       maxwidthi=max(item->Width,maxwidthi);
       item=item->NextItem;
      }
     
     item=menu->FirstItem;
     while(item)
      {
       /* 2. Pass: maxwidth einsetzen */
       item->Width=maxwidthi;
       sub=item->SubItem;
       while(sub)
        {
          /* In der Hoffnung, daß jedes Item mind. */
          /* 5 Pixel breit ist....                 */
         sub->LeftEdge=max(maxwidthi/2,maxwidthi-sub->Width/2);
         sub=sub->NextItem;
        }
       item=item->NextItem;
      }
     menu=menu->NextMenu;
    }
   SetMenuStrip(Window,MENU);
  }
 
