/*
 * Programm: Boopsi.c
 * Autor:    Rainer Zeitler
 * Es demonstriert die Kommunikations-
 * möglichkeiten zwischen zwei BOOPSI-Objekten,
 * ohne daß unser Programm die Steuerung übernehmen
 * muß. Dennoch erhält unser Programm eine
 * Mitteilung, sofern eines der Gadgets
 * modifiziert wurde. Das Programm muß vom CLI/Shell
 * gestartet werden.
 * Compiler: SAS-C
 * Aufruf:   lc -L boopsi.c
 */

#include <exec/types.h>
#include <utility/tagitem.h>
#include <intuition/intuition.h>
#include <intuition/gadgetclass.h>
#include <intuition/icclass.h>
#include <intuition/classusr.h>
#include <clib/exec_protos.h>
#include <clib/intuition_protos.h>

#include <stdio.h>

struct Library *IntuitionBase;
struct Window  *MyWindow;
struct IntuiMessage *IMsg;
struct Gadget *Prop, *Integer;

Object *model,*int2prop,*prop2int;

ULONG DoMethod(Object *, ULONG, ... );

/*
 * Teilt dem Prop-Gadget mit, sein Attribut
 * PGA_Top in STRINGA_LongVal zu konvertieren
 */
struct TagItem Prop_To_Int[] =
{
  PGA_Top, STRINGA_LongVal,
  TAG_END,0
};

/*
 * Teilt dem String-Gadget mit, sein Attribut
 * STRINGA_LongVal in PGA_Top zu konvertieren
 */
struct TagItem Int_To_Prop[] =
{
  STRINGA_LongVal, PGA_Top,
  TAG_END,0
};

/* Parameter fürs Öffnen des Fensters */
struct TagItem WindowTags[] =
{
  WA_Flags, WFLG_DEPTHGADGET | WFLG_DRAGBAR |
            WFLG_CLOSEGADGET,
  WA_IDCMP, IDCMP_CLOSEWINDOW | IDCMP_IDCMPUPDATE,
  WA_Height, 200, WA_Width, 300,
  WA_Title, (ULONG)"BOOPSI2-Test",
  TAG_END,0
};

void main(void)
{
  BOOL Fertig = FALSE; /* Für die Message-Schleife */

  /*
   * Öffnen der Library (mind. V37, also OS 2.0 und
   * höher
   */
  IntuitionBase = OpenLibrary("intuition.library", 37);

  if( IntuitionBase )
  {
    MyWindow = OpenWindowTagList(NULL,WindowTags);

    if( MyWindow )
    {
      /* Erzeugen eines propgclass-Objekts */
      Prop=(struct Gadget *)NewObject(NULL,"propgclass",
        GA_ID,     1, /* ID-Nummer des Gadgets */
        GA_Width,  10, /* Gadget-Breite */
        GA_Height, 80, /* Gadget-Höhe   */
        GA_Top,    MyWindow->BorderTop+2,
        GA_Left,   MyWindow->BorderLeft+2,
        PGA_Total, 100, /* 100 mögliche Positionen */
        PGA_Top,   10,  /* Startposition */
        PGA_Visible, 10, /* Sichtbare Größe des
                              Gadgetsknopfs */
        PGA_NewLook, TRUE,
        TAG_END);

      if( Prop )
      {
        /* Erzeugen eines Integer-String-Objekts */
        Integer=(struct Gadget *) NewObject(NULL,"strgclass",
          GA_ID,2,  /* ID-Nummer des Gadgets */
          GA_Width,  100, /* Gadget-Breite */
          GA_Height, 20,  /* Gadget-Höhe   */
          GA_Top,  (MyWindow->BorderTop) + 5,
          GA_Left, (MyWindow->BorderLeft) + 20,
          /* Vorgänger dieses Gadgets */
          GA_Previous, Prop,
          STRINGA_LongVal,  10, /* Startwert */
          STRINGA_MaxChars, 3,  /* Max. Zeichen */
          TAG_END);

        if( Integer )
        {
          /* Einrichten des modelclass-Objekts */
          model=(Object *)NewObject(NULL,
                          "modelclass", TAG_DONE );
          if( model )
          {
            /* Einrichten eines icclass-Objekts */
            int2prop=(Object *)NewObject(NULL,
                              "icclass", TAG_END );
            if( int2prop )
            {
              prop2int=(Object *)NewObject(NULL,
                              "icclass", TAG_END );
              if( prop2int )
              {
                /* Den Gadgets als Zielobjekt das
                 * modelclass-Objekt angeben */
                SetGadgetAttrs(Prop, MyWindow, NULL,
                       ICA_TARGET, model, TAG_DONE);
                SetGadgetAttrs(Integer, MyWindow,
                  NULL,ICA_TARGET, model, TAG_DONE);

                /* Dem modelclass-Objekt beide
                 * icclass-Objekte in die Liste
                 * zu benachrichtigender Objekte
                 * anfügen */
                DoMethod(model,OM_ADDMEMBER,int2prop);
                DoMethod(model,OM_ADDMEMBER,prop2int);

                /* Die Konvertierungsvorschriften und
                 * das Zielobjekt beiden icclass-
                 * Objekten angeben */
                SetAttrs(int2prop, ICA_TARGET, Prop,
                      ICA_MAP, Int_To_Prop, TAG_DONE);

                SetAttrs(prop2int, ICA_TARGET,Integer,
                      ICA_MAP, Prop_To_Int, TAG_DONE);

                /* Dem modelclass-Objekt als Ziel den
                 * IDCMP-Port unseres Fensters
                 * angeben */
                SetAttrs(model, ICA_TARGET,
                            ICTARGET_IDCMP, TAG_DONE);

                /* Gadgets ans Fenster anhängen und
                 * anzeigen. */
                AddGList(MyWindow,Prop,-1,-1,NULL);
                RefreshGList(Prop,MyWindow,NULL,-1);

                while (Fertig == FALSE)
                {
                  /* Auf CLOSEWINDOW-Message warten*/
                  WaitPort(MyWindow->UserPort);

                  while(IMsg=(struct IntuiMessage *)
                     GetMsg(MyWindow->UserPort)) {
                    switch( IMsg->Class )
                    {
                      case IDCMP_CLOSEWINDOW:
                           Fertig = TRUE;
                           break;
                      case IDCMP_IDCMPUPDATE:
                           printf("Nachricht von"
                                  " Gadget\n");
                           break;
                    }
                    ReplyMsg((struct Message *)IMsg);
                  }
                }
                RemoveGList(MyWindow, Prop, -1);
              }
              else DisposeObject(int2prop);
            }
            /* Modelclass-Objekte löschen auch die
             * via OM_ADDMEMBER angefügten Objekte.
             * Die icclass-Objekte prop2int und
             * int2prop müssen also nicht explizit
             * selbst gelöscht werden. Dieser Aufruf
             * reicht aus. */
            DisposeObject(model);
          }
          DisposeObject(Integer);
        }
        DisposeObject(Prop);
      }
      CloseWindow(MyWindow);
    }
    CloseLibrary(IntuitionBase);
  }
}
