/************************************************************************
 *                                                                      *
 * This is the Henon Attractor                                          *
 * M. Henon, A Two-dimensional Mapping with a Strange Attractor,        *
 * Communications in Mathematical Physics, 50, 69-77, (1976)            *
 *                                                                      *
 * This implementation was written by:                                  *
 * E. Lenz                                                              *
 * Johann-Fichte-Strasse 11                                             *
 * 8 Munich 40                                                          *
 * Germany                                                              *
 *                                                                      *
 ************************************************************************/
#include <intuition/intuition.h>

struct NewWindow nw =
{ 0,0,640,256,0,1,
   CLOSEWINDOW            /*  IDCMP flags            */
 | MENUPICK
 | MOUSEBUTTONS
 | ACTIVATE,
                          /*  Regular flags for gadgets and such */
   WINDOWDEPTH
 | WINDOWSIZING
 | WINDOWDRAG
 | WINDOWCLOSE
 | SMART_REFRESH
 | ACTIVATE,

  NULL,NULL,
  (UBYTE *) "The Henon Attractor",
  NULL,NULL,100,40,-1,-1,WBENCHSCREEN
};

struct IntuiText Outt =
{       0,1,                           /* frontpen, backpen */
        JAM1,                          /* drawmode */
        1,1,                           /* leftedge, topedge */
        NULL,                          /* TextAttr */
        (UBYTE *)"Zoom out",           /* IText */
        NULL,                          /* NextText */
};


struct MenuItem Out =
{       (struct MenuItem *) NULL,
        0,10,                               /* LeftEdge, TopEdge */
        100,10,                             /* Width, Height */
        ITEMTEXT | HIGHCOMP | ITEMENABLED,  /* Flags */
        0,                                  /* Mutual Exclude */
        (APTR)&Outt,                        /* ItemFill */
        NULL,                               /* SelectFill */
        0,                                  /* Command    */
        NULL,                               /* Subitem */
        0,                                  /* NextSelect */
};

struct IntuiText Not =
{       0,1,                           /* frontpen, backpen */
        JAM1,                          /* drawmode */
        1,1,                           /* leftedge, topedge */
        NULL,                          /* TextAttr */
        (UBYTE *)"",                   /* IText */
        NULL,                          /* NextText */
};


struct MenuItem nothi =
{       (struct MenuItem *) &Out,
        0,0,                                /* LeftEdge, TopEdge */
        80,10,                              /* Width, Height */
        ITEMTEXT | HIGHCOMP | ITEMENABLED,  /* Flags */
        0,                                  /* Mutual Exclude */
        (APTR)&Not,                         /* ItemFill */
        NULL,                               /* SelectFill */
        0,                                  /* Command    */
        NULL,                               /* Subitem */
        0,                                  /* NextSelect */
};

struct Menu menu1 =
{       (struct Menu *) NULL,        /* NEXT menu */
        200, 0, 120, 0,              /* LeftEdge, TopEdge, Width, Height */
        MENUENABLED,                 /* Flags */
        (BYTE *) "Zoom",             /* MenuName */
        (struct MenuItem *)&nothi,   /* First item */
        0,0,0,0,                     /* JazzX,JazzY, BeatX, BeatY */
        };

struct IntuiText tParB =
{       0,1,                           /* frontpen, backpen */
        JAM1,                          /* drawmode */
        1,1,                           /* leftedge, topedge */
        NULL,                          /* TextAttr */
        (UBYTE *)" Parameter B",       /* IText */
        NULL,                          /* NextText */
};

struct MenuItem ParB =
{       (struct MenuItem *) NULL,
        0,20,                                   /* LeftEdge, TopEdge */
        80,10,                                  /* Width, Height */
        ITEMTEXT|HIGHCOMP|ITEMENABLED,          /* Flags */
        0x7b,                                   /* Mutual Exclude */
        (APTR)&tParB,                           /* ItemFill */
        NULL,                                   /* SelectFill */
        0,                                      /* Command    */
        NULL,                                   /* Subitem */
        0,                                      /* NextSelect */
};


struct IntuiText tParA =
{       0,1,                           /* frontpen, backpen */
        JAM1,                          /* drawmode */
        1,1,                           /* leftedge, topedge */
        NULL,                          /* TextAttr */
        (UBYTE *)" Parameter A",       /* IText */
        NULL,                          /* NextText */
};

struct MenuItem ParA =
{       (struct MenuItem *) &ParB,
        0,10,                                           /* LeftEdge, TopEdge */
        80,10,                                          /* Width, Height */
        ITEMTEXT|HIGHCOMP|ITEMENABLED,                  /* Flags */
        0x7d,                                           /* Mutual Exclude */
        (APTR)&tParA,                                   /* ItemFill */
        NULL,                                           /* SelectFill */
        0,                                              /* Command    */
        NULL,                                           /* Subitem */
        0,                                              /* NextSelect */
};

struct IntuiText Noth =
{       0,1,                           /* frontpen, backpen */
        JAM1,                          /* drawmode */
        1,1,                           /* leftedge, topedge */
        NULL,                          /* TextAttr */
        (UBYTE *)"",                   /* IText */
        NULL,                          /* NextText */
};


struct MenuItem nothing =
{       (struct MenuItem *) &ParA,
        0,0,                                /* LeftEdge, TopEdge */
        80,10,                              /* Width, Height */
        ITEMTEXT | HIGHCOMP | ITEMENABLED,  /* Flags */
        0,                                  /* Mutual Exclude */
        (APTR)&Noth,                        /* ItemFill */
        NULL,                               /* SelectFill */
        0,                                  /* Command    */
        NULL,                               /* Subitem */
        0,                                  /* NextSelect */
};

struct Menu menu =
{       (struct Menu *) &menu1,      /* NEXT menu */
        20, 0, 120, 0,               /* LeftEdge, TopEdge, Width, Height */
        MENUENABLED,                 /* Flags */
        (BYTE *) "Parameters",       /* MenuName */
        (struct MenuItem *)&nothing, /* First item */
        0,0,0,0,                     /* JazzX,JazzY, BeatX, BeatY */
        };

extern void *OpenLibrary();
extern void *OpenWindow();
extern void *GetMsg();

struct IntuitionBase *IntuitionBase;
struct GfxBase *GfxBase;
struct IntuiMessage *message;
struct RastPort *rp;
struct Window *w;

float a,b;
float number();
float xl,xu,yl,yu;

#define STRINGSIZE 10
 UBYTE DefString[STRINGSIZE];
 UBYTE Undo [STRINGSIZE];

#define NOTFRAMING      0         /* We are not framing */
#define NOPOINT         1         /* We have no points of a frame */
#define POINT1          2         /* We have 1 point of a frame */
#define CENTERFRAMING   3         /* We have a center and are busy with a corner */
#define FLASHING        4         /* We are still flashing the frame */

short MouseStatus = NOTFRAMING;
unsigned short FrameX1, FrameX2, FrameY1, FrameY2;
int stop;

void quit()
{ if (w) CloseWindow(w);
  if (GfxBase) CloseLibrary(GfxBase);
  if (IntuitionBase) CloseLibrary(IntuitionBase);
  exit(0);
}

void cls()
{ SetDrMd(rp,JAM1);
  SetAPen(rp,0L);
  RectFill(rp,0L,10L,640L,256L);
  SetAPen(rp,1L);
}

/***************
  Get new range
 ***************/

void RectDraw(rp, x1, y1, x2, y2)
struct RastPort *rp;
SHORT x1, y1, x2,y2;
{ Move(rp, (long) x1, (long) y1);
  Draw(rp, (long) x2, (long) y1);
  Draw(rp, (long) x2, (long) y2);
  Draw(rp, (long) x1, (long) y2);
  if (y2 > y1) y1++; else y1--;   /* Don't XOR the first pixel twice */
  Draw(rp, (long) x1, (long) y1);
}

void CrossDraw(rp, x, y, left, right, top, bottom)
struct RastPort *rp;
SHORT x, y, top, bottom, left, right;
{ Move(rp, (long) left, (long) y);
  Draw(rp, (long) right, (long) y);
  Move(rp, (long) x, (long) top);
  Draw(rp, (long) x, (long) bottom);
}

void DisableSystemGadgets(gadget)
struct Gadget *gadget;
{ while (gadget)
    { if (gadget->GadgetType & SYSGADGET)
         {  if ((gadget->GadgetType & 0x00F0) != WDRAGGING) OffGadget(gadget, w, NULL);
            gadget->Flags |= GADGDISABLED;
         }
      gadget = gadget->NextGadget;
    }
}

void EnableSystemGadgets(gadget)
struct Gadget *gadget;
{ USHORT Flags = 0;

  while (gadget)
    { if (gadget->GadgetType & SYSGADGET)
         { Flags |= gadget->Flags;
           gadget->Flags &= ~GADGDISABLED;
         }
      gadget = gadget->NextGadget;
    }
  if (Flags & GADGDISABLED) RefreshWindowFrame(w);
}

void StopFraming()
{ EnableSystemGadgets(w->FirstGadget);
  ModifyIDCMP(w, w->IDCMPFlags & ~INTUITICKS);
  MouseStatus = NOTFRAMING;
}

void CheckMouse(Class, Code, MouseX, MouseY, Secs, Micros)
ULONG Class;
USHORT Code;
SHORT MouseX, MouseY;
ULONG Secs, Micros;
{ register SHORT top = w->BorderTop,
  bottom = w->Height - w->BorderBottom - 1,
  left = w->BorderLeft,
  right = w->Width - w->BorderRight - 1;
  static ULONG OldSecs, OldMicros;
  static SHORT MidX, MidY;

  if (MouseStatus != FLASHING &&
       (MouseX < left || MouseX > right || MouseY < top || MouseY > bottom))
                return;

  MouseX -= left;
  MouseY -= top;

  if (Class == MOUSEBUTTONS)
     { if (Code == SELECTDOWN)
          { switch (MouseStatus)
               { case NOTFRAMING:
                 case FLASHING:
                                  MouseStatus = NOPOINT;
                                  DisableSystemGadgets(w->FirstGadget);
                                  ModifyIDCMP(w, w->IDCMPFlags | INTUITICKS);
                                  stop=1;
                                  /* Now we can select our first corner */
                                  break;
                 case NOPOINT:    FrameX1 = FrameX2 = MouseX;
                                  FrameY1 = FrameY2 = MouseY;
                                  MouseStatus = POINT1;
                                  OldMicros = Micros;
                                  OldSecs = Secs;
                                  /* We have the first point. Now go for the second */
                                  break;
                 case POINT1:     if (DoubleClick(OldSecs, OldMicros, Secs, Micros))
                                     { /* Did we double-click? Then we have selected a center */
                                       MouseStatus = CENTERFRAMING;
                                       MidX = FrameX1;
                                       MidY = FrameY1;
                                       break;
                                     }
                                  FrameX2 = MouseX;
                                  FrameY2 = MouseY;
                                  /* Fall through to CENTERFRAMING */
                 case CENTERFRAMING: if (FrameX1 == FrameX2 || FrameY1 == FrameY2) break;
                                  /* Point 1 should be upper left */
                                  if (FrameX2 < FrameX1)
                                      { /* I DO know I am reusing a variable here. Sorry! */
                                        left=FrameX2; FrameX2=FrameX1; FrameX1=left;
                                      }
                                  if (FrameY2 < FrameY1)
                                      { left=FrameY2;
                                        FrameY2=FrameY1;
                                        FrameY1=left;
                                      }
                                  stop=2;
                                  StopFraming();
                                  break;
               }       /* End switch MouseStatus */
          }       /* End if Code == SELECTDOWN */
                return;
     }       /* End if Class == MOUSEBUTTONS */

  /* We are moving the mouse. Show something! */

  SetDrMd(rp, (ULONG) COMPLEMENT);

  switch (MouseStatus)
    { case NOPOINT: FrameX1 = FrameX2 = MouseX;
                    FrameY1 = FrameY2 = MouseY;
                    WaitTOF();
                    CrossDraw(rp, FrameX1, FrameY1,
                                        0, w->GZZWidth-1, 0, w->GZZHeight-1);
                    WaitTOF();
                    CrossDraw(rp, FrameX1, FrameY1,
                                        0, w->GZZWidth-1, 0, w->GZZHeight-1);
                    break;
      case CENTERFRAMING: FrameX1 = MouseX;
                    FrameY1 = MouseY;
                    FrameX2 = 2*MidX - FrameX1;
                    FrameY2 = 2*MidY - FrameY1;
                    goto flashing;
      case POINT1:  FrameX2 = MouseX;
                    FrameY2 = MouseY;
                    /* Deliberate Fall-Through to FLASHING */
      case FLASHING:
flashing:           WaitTOF();
                    RectDraw(rp, FrameX1, FrameY1, FrameX2, FrameY2);
                    WaitTOF();
                    RectDraw(rp, FrameX1, FrameY1, FrameX2, FrameY2);
    }
}


main()
{ float x,y,x1;
  long ix,iy;
  ULONG Class;
  USHORT code;
  SHORT mousex,mousey;
  ULONG secs,micros;

  if (!(GfxBase = OpenLibrary("graphics.library",NULL))) quit();
  if (!(IntuitionBase = OpenLibrary("intuition.library",NULL))) quit();
  if (!(w = OpenWindow(&nw)))
    {  nw.Height=200;
       if (!(w = OpenWindow(&nw))) quit();
    }
  rp = w->RPort;
  SetMenuStrip(w,&menu);

  a=1.4;
  b=0.3;
  x=.1;
  y=.2;
  stop=0;
  xl=-1.6;
  xu=1.6;
  yl=-0.42;
  yu=0.42;
  cls();

  FOREVER
    {  if (message = GetMsg(w->UserPort))
        { Class = message->Class;
          code = message->Code;
          mousex = message->MouseX;
          mousey = message->MouseY;
          secs = message->Seconds;
          micros = message->Micros;
          ReplyMsg(message);
          switch (Class)
            { case MENUPICK:     switch(code&0xff)
                                    { case 0x20: a=number(a);
                                                 break;
                                      case 0x21: xl=-1.6;
                                                 xu=1.6;
                                                 yl=-0.42;
                                                 yu=0.42;
                                                 cls();
                                                 break;
                                      case 0x40: b=number(b);
                                                 break;
                                    }
                                 break;
              case INTUITICKS:   if (!(stop)) break;
              case MOUSEBUTTONS: CheckMouse(Class,code,mousex,mousey,secs,micros);
                                 break;
              case CLOSEWINDOW : quit();
            }
        }
       if (stop==2)
         { x1=FrameX1*(xu-xl)/640;
           xu-=(640-FrameX2)*(xu-xl)/640;
           xl+=x1;
           iy=nw.Height-10;
           FrameY1-=10;
           FrameY2-=10;
           x1=(iy-FrameY2)*(yu-yl)/iy;
           yu-=FrameY1*(yu-yl)/iy;
           yl+=x1;
           stop=0;
           StopFraming();
           cls();
         }
       if (!(stop))
         { x1=1.0+y-a*x*x;
           y=b*x;
           x=x1;
           if ((x>=xl)&&(x<=xu)&&(y>=yl)&&(y<=yu))
              { ix=(x-xl)/(xu-xl)*640;
                iy=(yu-y)/(yu-yl)*(nw.Height-10)+10;
                Move(rp,ix,iy);
                Draw(rp,ix,iy);
              }
         }
    }
}

/*******************
  Get an real number
 *******************/

 struct IntuiMessage *message1;
 struct Window *w1;

 struct IntuiText ntext = {2,2,JAM1, 10, -11, 0,
   (UBYTE *) "Number entry", 0};

 struct StringInfo TexString = {
    DefString,                      /* Buffer - Pointer to Buffer */
    Undo,                           /* UndoBuffer - Undo buf ptr  */
    0,                              /* BufferPos - Init Chr Posn */
    STRINGSIZE,                     /* MaxChars - Max number of Chars */
    0, 0,                           /* DispPos - First Disp Chr */
    13,                             /* NumChars - Number of Characters */
    0, 0, 0,                        /* Posn Vars calc by Intuition */
    NULL,                           /* No pointer to Rasport */
    0,                              /* Longint Value */
    NULL                            /* No pointer to alt Keyboard */
 };

 SHORT Pairs[] = {
 -1,  -1,                            /* Information describing the */
 160, -1,                            /* border around the gadget */
 160, 9,
 -1, 9,
 -1, -1
  };

 #define NUM_PAIRS 5                /* There are Four pairs above */

 struct Border StrBorder = {
  -1, -1,                           /* LeftEdge, TopEdge */
  1, 0, JAM1,                       /* FrontPen,  BackPen  DrawMode  */
  NUM_PAIRS,                        /* Number of XY Pairs */
  Pairs,                            /* XY, Pointer to XY Pairs */
  NULL                              /* No more borders */
 };

 struct Gadget tex_gad = {
    0, 30, 30, 150,11, GADGHCOMP, STRINGCENTER | RELVERIFY,
    STRGADGET, (APTR)&StrBorder, 0,
    &ntext, 0, (APTR)&TexString, 0, 0
 };

 struct NewWindow nw1 =
{  100, 100,              /*  Start position       */
   220, 70,               /*  width, height,       */
   0, 1,                  /*  detail, block pens   */
   CLOSEWINDOW            /*  IDCMP flags          */
 | REFRESHWINDOW
 | GADGETUP,
                          /*  Regular flags for gadgets and such */
   WINDOWDEPTH
 | WINDOWSIZING
 | WINDOWDRAG
 | WINDOWCLOSE
 | SMART_REFRESH,

   &tex_gad,                       /* First gadget in list         */
   NULL,                           /* User checkmark               */
   (UBYTE *)"Enter real Number",   /* Window Title                 */
   NULL,                           /* Pointer to screen            */
   NULL,                           /* Pointer to superbitmap       */
   0, 0, 1, 1,                     /* Ignored because not sizeable */
   WBENCHSCREEN,                   /* screen   */
   };

float number(x)
float x;
{  ULONG MessageClass;
   float val;
   extern double atof();

   sprintf(DefString,"%.1f",x);
   if (!(w1 = OpenWindow(&nw1) )) return(x);

   FOREVER
    {  if (message1 = GetMsg(w1->UserPort))
        { MessageClass = message1->Class;
          ReplyMsg(message1);
          switch (MessageClass)
            { case GADGETUP    : CloseWindow(w1);
                                 val = atof(DefString);
                                 return(val);
              case CLOSEWINDOW : CloseWindow(w1);
                                 return(x);
            }
        }
    }
}




