/*
 * WBLoc.c - places a locator on the Workbench screen
 *
 * Bruno Costa - 22 Dec 90 - 24 Dec 90
 *
 * (compile & link with SAS/C using: lc -L wbloc)
 */

#include <exec/types.h>
#include <exec/memory.h>
#include <graphics/gfxmacros.h>
#include <intuition/intuition.h>
#include <proto/intuition.h>
#include <proto/layers.h>
#include <proto/exec.h>
#include <proto/graphics.h>

#include <clib/macros.h>
#include <stdlib.h>
#include <string.h>

#define	WIN_WIDTH 148

struct NewWindow nw = {
  (588 - WIN_WIDTH), 0, WIN_WIDTH, 12, 3, 2,
  MOUSEMOVE | MOUSEBUTTONS | ACTIVEWINDOW | INACTIVEWINDOW,
  RMBTRAP | SMART_REFRESH,
  NULL, NULL, NULL, NULL, NULL,
  5, 5, 640, 200, WBENCHSCREEN
};

struct Library *GfxBase = NULL;
struct Library *LayersBase = NULL;
struct Library *IntuitionBase = NULL;

struct RastPort *rp = NULL, *backrp = NULL;
struct Window *wind = NULL;
int maxx, maxy;
int textx, texty;


UWORD ptrtemplate[] = {
  0x0000, 0x0000,

  0x0000, 0x0000,
  0xffff, 0x0000,
  0x0000, 0x0000,
  0x0000, 0x0000,
  0x2000, 0x2000,
  0xf000, 0xf000,
  0x2000, 0x2000,
  0x0000, 0x0000,
  0x0000, 0x0000,
  0x4000, 0x4000,
  0x4000, 0x4000,
  0x4000, 0x4000,
  0xe000, 0xe000,
  0x4000, 0x4000,
  0x0000, 0x0000,
  0xffff, 0x0000,

  0x0000, 0x0000
};

#define PTRSIZE (sizeof (ptrtemplate) / sizeof (UWORD))

UWORD chip pointer[2][PTRSIZE];


static UBYTE nfont[11][5] = {
  {7, 5, 5, 5, 7},	/* 0 */
  {2, 6, 2, 2, 2},	/* 1 */
  {7, 1, 7, 4, 7},	/* 2 */
  {7, 1, 3, 1, 7},	/* 3 */
  {5, 5, 7, 1, 1},	/* 4 */
  {7, 4, 7, 1, 7},	/* 5 */
  {7, 4, 7, 5, 7},	/* 6 */
  {7, 1, 1, 2, 2},	/* 7 */
  {7, 5, 7, 5, 7},	/* 8 */
  {7, 5, 7, 1, 1},	/* 9 */
  {7, 1, 2, 0, 2}	/* ? */
};


void putdigit (UWORD *where, int pos, int n)
{
 int i;

 ++where;	/* optional */

 for (i = 0; i < 5; i++)
   where[i << 1] |= nfont[n][i] << (pos << 2);
}


void mkbitnumber (int n, UWORD *where)
{
 int i, len;
 char str[20];

 sprintf (str, "%d", n);
 len = strlen (str);
 if (len > 3)
 {
   putdigit (where, 0, 10);
   putdigit (where, 1, 10);
   putdigit (where, 2, 10);
 }
 else
   for (i = len - 1; i >= 0; i--)
     putdigit (where, len - i - 1, str[i] - '0');
}


void setptr (int x, int y)
{
 static int curptr = 0;

 CopyMem (ptrtemplate, &pointer[curptr][0], sizeof (ptrtemplate));

 mkbitnumber (x, &pointer[curptr][8]);
 mkbitnumber (y, &pointer[curptr][20]);

 SetPointer (wind, &pointer[curptr][0], 16, 16, 0, 0);

 curptr = 1 - curptr;	/* switch buffers */
}


void writetext (char *str, int c, int x)
{
 SetRast (wind->RPort, 0);
 SetAPen (wind->RPort, c);
 SetDrMd (wind->RPort, JAM1);
 Move (wind->RPort, x, wind->BorderTop + wind->RPort->TxBaseline);
 Text (wind->RPort, str, strlen (str));
 RefreshWindowFrame (wind);
}


void writetitle (void)
{
 writetext ("WBLocator", 1, 43);
}


void writeauthor (void)
{
 writetext ("\2511991 Bruno Costa", 2, 6);
}


void setwindow (void)
{
 MoveWindow (wind, (2 * maxx / 3) - wind->LeftEdge, 0);
}


void draw (int x, int y)
{
 SetDrMd (rp, COMPLEMENT);
 Move (rp, 0, y);
 Draw (rp, maxx, y);
 Move (rp, x, 0);
 Draw (rp, x, maxy);

 setptr (x, y);
}


void drawloc (int x, int y)
{
 static int ox = -1, oy = -1;

 if (ox >= 0  &&  oy >= 0)
   draw (ox, oy);

 if (x >= 0  &&  y >= 0)
   draw (x, y);

 ox = x;
 oy = y;
}


void saverp (void)
{
 CopyMem (rp, backrp, sizeof (*rp));
}


void restorerp (void)
{
 CopyMem (backrp, rp, sizeof (*rp));
}


#define abort(code) {err=code; goto abort;}

void main (void)
{
 int err = 0;
 struct IntuiMessage *msg;
 int drawing = FALSE, GoOn = TRUE;

 GfxBase = OpenLibrary ("graphics.library", 0L);
 LayersBase = OpenLibrary ("layers.library", 0L);
 IntuitionBase = OpenLibrary ("intuition.library", 0L);

 wind = OpenWindow (&nw);
 if (wind == NULL)
   abort (20);

 rp = &wind->WScreen->RastPort;
 maxx = wind->WScreen->Width - 1;
 maxy = wind->WScreen->Height - 1;

 backrp = (struct RastPort *) AllocMem (sizeof (struct RastPort), 0);
 if (backrp == NULL)
   abort (20);

 setwindow ();
 writetitle ();

 GoOn=TRUE;
 while (GoOn)
 {
   WaitPort (wind->UserPort);

   while ((msg = (struct IntuiMessage *) GetMsg (wind->UserPort))  &&  GoOn)
   {
     ULONG class = msg->Class;
     ULONG code= msg->Code;

     ReplyMsg (&msg->ExecMessage);

     if (drawing)
       drawloc (wind->WScreen->MouseX, wind->WScreen->MouseY);

     switch (class)
     {
       case ACTIVEWINDOW:
         if (!drawing)
         {
           writeauthor ();
           drawing = TRUE;
           ReportMouse (wind, TRUE);
           LockLayerInfo (&wind->WScreen->LayerInfo);
           saverp ();
         }
         break;

       case INACTIVEWINDOW:
         if (drawing)
         {
           drawloc (-1, -1);
           restorerp ();
           UnlockLayerInfo (&wind->WScreen->LayerInfo);
           ReportMouse (wind, FALSE);
           drawing = FALSE;
           writetitle ();
         }
         break;

       case MOUSEBUTTONS:
         if (code == MENUDOWN)
           GoOn = FALSE;
         break;
     }
   }
 }

 if (drawing)
 {
   drawloc (-1, -1);
   restorerp ();
   UnlockLayerInfo (&wind->WScreen->LayerInfo);
   ReportMouse (wind, FALSE);
   drawing = FALSE;
 }

abort:
 if (backrp)
   FreeMem (backrp, sizeof (struct RastPort));
 if (wind)
   CloseWindow (wind);
 if (IntuitionBase)
   CloseLibrary (IntuitionBase);
 if (LayersBase)
   CloseLibrary (LayersBase);
 if (GfxBase)
   CloseLibrary (GfxBase);

 exit (err);
}
