/*
 * P x l S c o p e
 * 
 * Opens a window in the workbench screen and shows a magnified view of
 * the pixels at the mouse pointer location.
 *
 * May be freely distributed.
 *
 * Ed Karlo
 * CIS 76657,1445
 * November, 1986
 *
 */

#include <stdio.h>
#include <stdlib.h>

#include "proto/exec.h"
#include "exec/types.h"
#include "exec/devices.h"

#include "proto/graphics.h"
#include "graphics/copper.h"
#include "graphics/gels.h"
#include "graphics/gfxbase.h"
#include "graphics/regions.h"

#include "hardware/blit.h"

#include "proto/intuition.h"
#include "intuition/intuition.h"

#include "devices/keymap.h"

struct IntuitionBase *IntuitionBase;
struct GfxBase       *GfxBase;

#define BIGPIXW 8
#define BIGPIXH 7

struct NewWindow nw = {
       324 , 10 ,            /* LeftEdge, TopEdge   */
       316 , 181 ,           /* Width, Height       */
       0 , 1 ,               /* DetailPen, BlockPen */
       CLOSEWINDOW |         /* IDCMPFlags          */       
       NEWSIZE ,
       WINDOWCLOSE |         /* Flags               */
       WINDOWDRAG |
       WINDOWDEPTH |
       WINDOWSIZING |
       SMART_REFRESH ,
       NULL,                 /* *FirstGadget        */
       NULL,                 /* *CheckMark          */
       "PxlScope" ,          /* Title               */
       NULL ,                /* *Screen             */
       NULL ,                /* *BitMap             */
       121 , 28 ,            /* MinWidth, MinHeight */
       640 , 200 ,           /* MaxWidth, MaxHeight */
       WBENCHSCREEN          /* Type                */
};

struct Screen       *S;
struct Window       *W;
struct IntuiMessage *message;

ULONG  class;
USHORT code;

int   old_mx, old_my,        /* save mouse pos */
      wxmaxpix, wymaxpix,    /* max big pixels that will fit in window */
                             /* (includes any partial ones at borders) */
      forsx, forsy,          /* for loop start x and y pos */
      pen,                   /* hold pixel color */
      locsx, locsy;          /* local use start x and y locs */

char wkstr[15];              /* build text */

/* function prototypes */
void checkmsg(void);
void windowmax(void);
void splat(int, int);
void putrect(struct Window *, int, int, int, int, int);

void main(argc,argv)
int argc;
char **argv;
{
   IntuitionBase = (struct IntuitionBase *)
                      OpenLibrary("intuition.library", 0);
   if (IntuitionBase == NULL) exit (1);
   
   GfxBase = (struct GfxBase *)
                OpenLibrary("graphics.library", 0);
   if (GfxBase == NULL) exit (2);

   W = (struct Window *)OpenWindow(&nw);
   if (W == NULL) exit (3);

   S = W->WScreen;

   SetDrMd(W->RPort, JAM2); /* draw mode */
   SetBPen(W->RPort, 2); /* and backround for text */

   windowmax();

   splat(old_mx = S->MouseX, old_my = S->MouseY);


   for (;;) {

      checkmsg();

      if ( (old_mx != S->MouseX || old_my != S->MouseY) )
         splat(old_mx = S->MouseX, old_my = S->MouseY);

   }

}


/*
 * any messages ?
 */
void checkmsg()
{
   while ( message = (struct IntuiMessage *)
              GetMsg(W->UserPort) ) {
      class = message->Class;
      code  = message->Code;
      ReplyMsg(message);
      if (class == CLOSEWINDOW) { /* bye */
         CloseWindow (W);
         CloseLibrary((struct Library *)IntuitionBase);
         CloseLibrary((struct Library *)GfxBase);
         exit (0);
      }

      if (class == NEWSIZE)
         windowmax();

    } /* while loop for window messages */
}


/*
 * how many pixels can dance on the head of a pin ?
 */
void windowmax()
{
   wxmaxpix = (W->Width - 4) / BIGPIXW;
   if ( (W->Width - 4) % BIGPIXW ) wxmaxpix++;
   wymaxpix = (W->Height - 20) / BIGPIXH;
   if ( (W->Height - 20) % BIGPIXH ) wymaxpix++; 
}


/*
 * fills the window with big pixels
 */
void splat(mx, my)
int mx, my;
{
   putrect(W, 2, 2, 10, W->Width - 3, 18);
   sprintf(wkstr, "X=%4d  Y=%4d", mx, my);
   SetAPen(W->RPort, 1);
   Move(W->RPort, 5, 17);
   Text(W->RPort, wkstr, 14);

   for (forsy=0; forsy<=wymaxpix; forsy++) {
      for (forsx=0; forsx<=wxmaxpix; forsx++) {
         checkmsg();
         if ( (old_mx != S->MouseX || old_my != S->MouseY) )
            return; /* still moving */
         if ( mx+forsx > 639 || my+forsy > 199 ) { /* in the rough */
            putrect(W, 3,  2 + (forsx*BIGPIXW), 19 + (forsy*BIGPIXH),
                           9 + (forsx*BIGPIXW), 25 + (forsy*BIGPIXH) );
         } else { /* in the ball park */
            /* draw big pixel and blank out right and bottom of it */
            pen = ReadPixel(&S->RastPort, mx+forsx, my+forsy);
            locsx = forsx * BIGPIXW;
            locsy = forsy * BIGPIXH;
            putrect( W, pen,  2 + locsx, 19 + locsy,
                              6 + locsx, 24 + locsy );
            putrect( W, 0,    7 + locsx, 19 + locsy,
                              9 + locsx, 24 + locsy );
            putrect( W, 0,    2 + locsx, 25 + locsy,
                              9 + locsx, 25 + locsy );
         } /* drawing the big pixel */
      } /* for x loop */
   } /* for y loop */
}


/*
 * draws a rectangle in window w in pen color penn taking care
 * not to damage right and bottom border and size gadget
 */
void putrect(w, penn, sx, sy, ex, ey)
struct Window *w;
int penn, sx, sy, ex, ey;
{
int sgx, sgy; /* size gadget border pos */

   if ( sx > w->Width - 3 || sy > w->Height - 2 )   /* out of sight */
      return; 

   if ( ex > w->Width - 3 )   /* don't overwrite right border */
      ex = (w->Width) - 3; 

   if ( ey > w->Height - 2 )   /* don't overwrite bottom border */
      ey = w->Height - 2; 

   sgx = w->Width - 17;   /* compute boundary of size gadget */
   sgy = w->Height - 10;

   if ( sx > sgx && sy > sgy )   /* entirely behind size gadget */
      return;

   SetAPen(w->RPort, penn);

   if ( ex > sgx && ey > sgy ) { /* ends within size gadget */
      if ( sx > sgx )   /* entirely above */
         RectFill(w->RPort, sx, sy, ex, sgy);
      else
      if ( sy > sgy )   /* entirely beside */
         RectFill(w->RPort, sx, sy, sgx, ey);
      else { /* on the corner */
         RectFill(w->RPort, sx, sy, ex, sgy);
         RectFill(w->RPort, sx, sgy+1, sgx, ey);
      }
   } else
      RectFill(w->RPort, sx, sy, ex, ey);
}
