/*
   Example of opening a simple window on a custom screen - #5
   written by Dan Schein April-88 for the 1988 AMIGA Developers Conference. 

   This example, and all those based on this example, were compiled and
   tested with the Lattice V4.0 compiler.
*/

#include <exec/types.h>
#include <intuition/intuition.h>
#include <graphics/display.h>
#include <libraries/dos.h>
#include <stdio.h>

/*
   Define the Version of the Amiga OS we want (require)

   Operating System Version Information

      0     Any version is OK
      30    1.0 or higher
      31    1.1 NTSC or Higher
      32    1.1 PAL  or Higher
      33    1.2 or higher
      34    1.3 or higher

*/

#define INTUITION_REV 0
#define GRAPHICS_REV  0

/*
   Define the Flags for use in our menu structure's - Refer to the Intuition
   Reference Manual for more detail
*/

#define FLAGSA ITEMTEXT|MENUTOGGLE|ITEMENABLED
#define FLAGSB CHECKIT|ITEMTEXT|MENUTOGGLE|ITEMENABLED|COMMSEQ
#define FLAGSC ITEMTEXT|MENUTOGGLE|ITEMENABLED|COMMSEQ

BOOL  Done;
ULONG WakeUpBits, class, code, selection, menuNum, itemNum;

struct TextAttr MyFont =
{
   "topaz.font",                             /* Font Name                 */
   TOPAZ_EIGHTY,                             /* Font Height               */
   FS_NORMAL,                                /* Style                     */
   FPF_ROMFONT                               /* Preferences               */
};

struct NewScreen OurScreen =
{
   0, 0,                                     /* LeftEdge and TopEdge     */
   640, 200,                                 /* Width and Height         */
   2,                                        /* Depth (4 colors)         */
   0, 1,                                     /* DetailPen and BlockPen   */
   HIRES,                                    /* Special Display Mode     */
   CUSTOMSCREEN,                             /* The Screen Type          */
   &MyFont,                                  /* Use our own Font         */
   "A Simple Screen",                        /* Screen Title             */
   NULL,                                     /* Special Screen Gadgets   */
   NULL                                      /* Special CustomBitMap     */
};

struct NewWindow OurWindow =
{
   20, 20,                                   /* LeftEdge and TopEdge      */
   400, 160,                                 /* Width and Height          */
   0, 1,                                     /* DetailPen and BlockPen    */
   CLOSEWINDOW|MENUPICK,                     /* IDCMP Flags               */
   WINDOWCLOSE|SMART_REFRESH|                /* Flags                     */
   ACTIVATE|WINDOWDRAG|WINDOWDEPTH|
   WINDOWSIZING|SMART_REFRESH,
   NULL, NULL,                               /* Gadget and Image pointers */
   "A Simple Window",                        /* Window Title              */
   NULL,                                     /* Screen pointer            */
   NULL,                                     /* BitMap pointer            */
   100, 25,                                  /* MinWidth and MinHeight    */
   500, 180,                                 /* MaxWidth and MaxHeight    */
   CUSTOMSCREEN                              /* Type of window            */
};

struct IntuiText IText[] =
{
             /* Breakdown of the IntuiText Structure */
   {
   0, 1,                                     /* FrontPen and BackPen      */
   JAM2,                                     /* DrawMode                  */
   CHECKWIDTH, 0,                            /* LeftEdge and TopEdge      */
   NULL,                                     /* TextAttr                  */
   "QUIT?",                                  /* Itext (text)              */
   NULL                                      /* NextText                  */
   },
             /* Most commonly used IntuiText syntax  */

   { 0, 1, JAM2, CHECKWIDTH, 0, NULL, "SURE!",   NULL},
   { 0, 1, JAM2, CHECKWIDTH, 0, NULL, "FLASHER", NULL},
   { 0, 1, JAM2, CHECKWIDTH, 0, NULL, "FLASH",   NULL},
   { 0, 1, JAM2, CHECKWIDTH, 0, NULL, "ON/OFF",  NULL},
   { 0, 1, JAM2, CHECKWIDTH, 0, NULL, "FLIP?",   NULL}
};

struct MenuItem M0I1S0[] =                   /* This is Menu 0 - Item 1   */
{                                            /*               SubItem 0   */
   {
   NULL,                                     /* Next Item                 */
   100, 6,                                   /* LeftEdge and TopEdge      */
   80+CHECKWIDTH, 10,                        /* Width and Height          */
   FLAGSC,                                   /* Flags (see #define)       */
   0,                                        /* Mutual Exclude            */
   (APTR)&IText[3],                          /* ItemFill                  */
   NULL,                                     /* SelectFill                */
   'F',                                      /* Command                   */
   NULL                                      /* NextSelect                */
   } 
};

struct MenuItem M0I2S0[] =                   /* This is Menu 0 - Item 2   */
{                                            /*               SubItem 0   */
   {
   NULL,                                     /* Next Item                 */
   100,  6,                                  /* LeftEdge and TopEdge      */
   80+CHECKWIDTH, 10,                        /* Width and Height          */
   FLAGSB,                                   /* Flags (see #define)       */
   0,                                        /* Mutual Exclude            */
   (APTR)&IText[5],                          /* ItemFill                  */
   NULL,                                     /* SelectFill                */
   'R',                                      /* Command                   */
   NULL                                      /* NextSelect                */
   } 
};

struct MenuItem M0[] = 
{
   {                                         /* This is Menu 0 - Item 0   */
   &M0[1],                                   /* Next Item                 */
   0, 0,                                     /* LeftEdge and TopEdge      */
   56+CHECKWIDTH, 10,                        /* Width and Height          */
   FLAGSA,                                   /* Flags (see #define)       */
   0,                                        /* Mutual Exclude            */
   (APTR)&IText[0],                          /* ItemFill (text)           */
   (APTR)&IText[1],                          /* SelectFill (alt-text)     */
   NULL,                                     /* Command                   */
   NULL,                                     /* SubItem                   */
   NULL                                      /* NextSelect                */
   },

   {                                         /* This is Menu 0 - Item 1   */
   &M0[2],                                   /* Next Item                 */
   0, 12,                                    /* LeftEdge and TopEdge      */
   56+CHECKWIDTH, 10,                        /* Width and Height          */
   FLAGSA,                                   /* Flags (see #define)       */
   0,                                        /* Mutual Exclude            */
   (APTR)&IText[2],                          /* ItemFill (text)           */
   NULL,                                     /* SelectFill (alt-text)     */
   NULL,                                     /* Command                   */
   &M0I1S0[0],                               /* SubItem                   */
   NULL                                      /* NextSelect                */
   },

   {                                         /* This is Menu 0 - Item 2   */
   NULL,                                     /* Next Item                 */
   0, 24,                                    /* LeftEdge and TopEdge      */
   56+CHECKWIDTH, 10,                        /* Width and Height          */
   FLAGSA,                                   /* Flags (see #define)       */
   0,                                        /* Mutual Exclude            */
   (APTR)&IText[4],                          /* ItemFill (text)           */
   NULL,                                     /* SelectFill (alt-text)     */
   NULL,                                     /* Command                   */
   &M0I2S0[0],                               /* SubItem                   */
   NULL                                      /* NextSelect                */
   } 
};

struct Menu TheMenu[] =
{
   {
   NULL,                                     /* Next Menu                 */
   0, 0,                                     /* LeftEdge and TopEdge      */
   56+CHECKWIDTH, 10,                        /* Width and Height          */
   MENUENABLED,                              /* Flags                     */
   "OUR MENU",                               /* Menu Title                */
   &M0[0]                                    /* First Item                */
   } 
};

struct Screen *screen;
struct Window *window;
struct GfxBase *GfxBase;
struct IntuiMessage *message;
struct Menu *MyMenu = &TheMenu[0];
struct IntuitionBase *IntuitionBase;

/*
   The following items have been added for use by the console IO routines 
*/

UBYTE inKey;
ULONG  conSigMask;
#define SBUFSZ  (128)
extern struct MsgPort *cmPort;
int   scnt, OpenedCon = 0;
char  *sbp, sbuf[SBUFSZ];

void main(), chkmsg(), flash(), cleanexit(), cleanup();
void chkkey(), addchar(), backspace(), escape(), CDClose();
void enter(), queue_read(), CDPutChar(), CDPutStr(), CDPutStrL();



void main()
{
              /* Method #1 of opening and error testing */

   IntuitionBase=(struct IntuitionBase*)
      OpenLibrary("intuition.library",INTUITION_REV);

   if (IntuitionBase == NULL)
   {
      cleanexit ("Open Intuition Library failed!\n", RETURN_FAIL);
   }

   GfxBase=(struct GfxBase*)OpenLibrary("graphics.library",GRAPHICS_REV);

   if (GfxBase == NULL)
   {
      cleanexit ("Open Graphics Library failed!\n", RETURN_FAIL);
   }

              /* Method #2 of opening and error testing */

   if((screen=(struct Screen*)OpenScreen(&OurScreen))==NULL)
   {
      cleanexit ("Open Screen failed!\n", RETURN_FAIL);
   }

   OurWindow.Screen=screen;

   if((window=(struct Window *)OpenWindow(&OurWindow))==NULL)
   {
      cleanexit ("Open Window failed!\n", RETURN_FAIL);
   }

   SetMenuStrip(window, MyMenu);

   Move(window->RPort, 20, 20);
   Text(window->RPort, "Our own TEXT string!", 20);
   Delay(50);

   if(!(OpenedCon=CDOpen(window)))
      {
      cleanexit ("Open Console Device Error!\n", RETURN_FAIL);
      }

   CDPutStr("This string output to console device\n");

   sbp = sbuf;
   *sbp = '\0';
   scnt = 0;
   Done = FALSE;

   while(!Done)
   {
      WakeUpBits = Wait((1<<window->UserPort->mp_SigBit) |
                       (1<<cmPort->mp_SigBit));

      if(WakeUpBits & (1<<window->UserPort->mp_SigBit))
      {
         chkmsg();
      }

      if(WakeUpBits & (1<<cmPort->mp_SigBit))
      {
         chkkey();
      }

   }

   cleanup();
   exit (RETURN_OK);
}



void chkkey()
{
int i;
UBYTE c;

   while((i=CDMayGetChar()) != -1)
   {
      c = (UBYTE)i;
      if(c == 0x08) backspace();
      else if((c == 0x1b)||(c == 0x9b)) escape();
      else if(c == 0x0d) enter();
      else if(((c>=0x20)&&(c<=0x7e)) || (c>=0xa0))  /* printable */
      {
         inKey = c;
         addchar(c);
      }
   }
}

void addchar(c)
UBYTE c;
{
   if((scnt<SBUFSZ-2) || ((scnt<SBUFSZ-1)&&(c='\n')))
   {
      *sbp++ = c;
      scnt++;
      CDPutChar(c);
   }
}

void backspace()
{
   if (scnt>0)
   {
      CDPutStr("\b \b");
      *sbp-- = (' ');
      scnt--;
   }
}

void escape()
{
UBYTE c;
   /*
      We'll just discard ESC sequences (cursors, help, etc) in this example
      You could parse them and act on them
   */
   do
   {
      c = CDGetChar();
   }
   while((c == '[')||(c < 0x40)||(c > 0x7e));
}


void enter()
{
   *sbp = '\0';
   CDPutChar('\n');

   CDPutStr("Buffer contains:\n");
   CDPutStr(sbuf);
   CDPutChar('\n');

   sbp = sbuf;
   *sbp = '\0';
   scnt = inKey = 0;
}

void chkmsg()
{
   while(message = (struct IntuiMessage *)GetMsg(window->UserPort))
   {
      class = message->Class;
      code  = message->Code;
      switch(class)
      {
         case CLOSEWINDOW:
            Done = TRUE;
            break;
         case MENUPICK:
            selection = code;
            while (selection != MENUNULL)
            {
               menuNum = MENUNUM(selection);
               itemNum = ITEMNUM(selection);
               switch(menuNum)
               {
                  case 0:    /* Project Menu */
                  switch(itemNum)
                  {
                     case 0:
                        Done = TRUE;
                        break;
                     case 1:
                        flash();
                        break;
                     case 2:
                        break;
                     default:
                        break;
                  }
                  break;

                  default:
                     break;
               }
               selection = ((struct MenuItem *)ItemAddress
                     (&TheMenu,selection))->NextSelect;
            }
            break;
         default:
            break;
      }
   ReplyMsg(message);
   }
}

void flash()
{
   int i;

   for (i=0;i<4;i++)      /* do it four times  */
   {
      DisplayBeep(0);     /* screen flash!     */
      Delay (15);         /* wait 15/50ths sec */
   }
}

void cleanexit(s, err)
UBYTE *s;
int err;
{
   if(*s) printf(s);
   cleanup();
   exit(err);
}

void cleanup()
{
   if(OpenedCon)  CDClose();
      
   if(window)
   {
      ClearMenuStrip(window);
      CloseWindow(window);
   }

   if(screen)
   {
      CloseScreen(screen);
   }

   if(GfxBase)
   {
      CloseLibrary(GfxBase);
   }

   if(IntuitionBase)
   {
      CloseLibrary(IntuitionBase);
   }
}

/*********************************************************************/
/*                                                                   */
/*  Program name:  cdio                                              */
/*                                                                   */
/*  Modified 04/14/88 by Carolyn Schepper - Commodore Amiga          */
/*                                                                   */
/*  Purpose:  To provide standard console device interface routines  */
/*            such as Open, GetChar, PutChar, etc.                   */
/*                                                                   */
/*  Arguments:  (window)    - The window to associate the console    */
/*                            device with. Used in CDOpen.           */
/*              (character) - The char to output. Used in CDPutChar  */
/*              (string)    - The string to output. Used in CDPutStr */
/*                                                                   */
/*********************************************************************/

struct IOStdReq *cwIO;
struct IOStdReq *crIO;
struct MsgPort  *cmPort;

UBYTE consoleReadChar  = 0;
UBYTE OutChar = 0;

int CDOpen(window)
struct Window *window;
{
int error;

   cwIO = 0L;
   crIO = 0L;
   cmPort = 0L;

   if(!(cmPort = (struct MsgPort *)CreatePort("myConPort",0)))
   {
      return(0);
   }
   if(!(cwIO = (struct IOStdReq *)CreateStdIO(cmPort)))
   {
      DeletePort(cmPort);
      return(0);
   }
   if(!(crIO = (struct IOStdReq *)CreateStdIO(cmPort)))
   {
      DeleteStdIO(cwIO);
      DeletePort(cmPort);
      return(0);
   }

   /* Open the console device for our window */
   cwIO->io_Data = (APTR)window;
   cwIO->io_Length = sizeof(*window);
   if((error = OpenDevice("console.device", 0, cwIO, 0)))
   {
      printf("CDInit OpenDevice error: %d.\n", error);
      return(0);
   }

   /* Copy the initialized writeIO request to the readIO request */
   *crIO = *cwIO;

   /* Send off the initial read request */
   queue_read();
   /* Return success */
   return(1);
}

void CDClose()
{
   if((cwIO)&&(cwIO->io_Device)) CloseDevice(cwIO);
   if(cwIO)   DeleteStdIO(cwIO);
   if(crIO)   DeleteStdIO(crIO);
   if(cmPort) DeletePort(cmPort);
}

int CDGetChar()
{
register temp;

   WaitPort(cmPort);
   GetMsg(cmPort);
   /* Copy char to temp before queue_read() which reuses it */
   temp = consoleReadChar;
   queue_read();
   return(temp);
}


int CDMayGetChar()
{
register temp;

   if(!(CheckIO(crIO))) return(-1);
   GetMsg(cmPort);
   temp = consoleReadChar;
   queue_read();
   return(temp);
}


void queue_read()
{
   crIO->io_Command = CMD_READ;
   crIO->io_Data = (APTR)&consoleReadChar;
   crIO->io_Length = 1;
   SendIO(crIO);
}


void CDPutChar(character)
char character;
{
   OutChar = character;
   cwIO->io_Command = CMD_WRITE;
   cwIO->io_Data = (APTR)&OutChar;
   cwIO->io_Length = 1;
   DoIO(cwIO);
}

void CDPutStr(string)
char *string;                     /*  NULL terminated string to output */
{
   CDPutStrL(string,-1);
}

void CDPutStrL(string,length)
char *string;                     /* output string of length length    */
int length;
{
   cwIO->io_Command = CMD_WRITE;
   cwIO->io_Data = (APTR)string;
   cwIO->io_Length = length;
   DoIO(cwIO);
}

