/****************************************************************
* Module Name: TstPgm1C.C
* Function:    C Version of ScribblePad
*                - Used to develop C interface to MiniGRiD
*****************************************************************/

#pragma pack(1)

#include <stdio.h>

#define FALSE 0
#define  TRUE 1

/* This eventually will become the gpwindow.h include/header file */

typedef unsigned  char boolean;
typedef unsigned short word;
typedef   signed short integer;

enum directions    {up, down, left, right};
enum windowFormats {screenFormat, gridFormat};
enum windowTypes   {frameLessWindow, framedWindow, titleFramedWindow};
enum cursorTypes   {ptrCursor, penCursor, insCursor, boxCursor, crsCursor};
enum frameTypes    {simple=0,
                    sw3DShadow2=256,
                    boldFrame=512,
                    pictureFrame=768};

const integer cursorXOffsets [] = {1, 1,  3, 4, 4};
const integer cursorYOffsets [] = {1, 14, 7, 4, 4};

typedef struct {
  short x;
  short y;
} POINT;

/* Caution: Ms-C Graphics Library has function defined named 'rectangle' */

typedef struct {
  POINT topLeft;
  POINT extent;
} RECTANGLE;

extern void pascal near mniInitialize (void);
extern void pascal near mniTerminate (void);

extern word pascal near winCreateWindow
 (RECTANGLE far *pBounds, word windowType, word frameType,
  boolean modal, word far *pError);
extern word pascal near winCreateOffscreenWindow
 (integer width, integer height, integer format,
  word windowType, word frameType, boolean modal, word far *pError);
extern void pascal near winDeleteWindow
 (word windowID, word far *pError);
extern void pascal near winDrawWindowFrame (void);
extern void pascal near winEraseWindow (void);

extern void pascal near winSetActiveWindow (word windowID);
extern void pascal near winSetDrawWindow (word windowID);

extern void pascal near winGetWindowExtent (POINT far *pPt);
extern void pascal near winGetDisplayExtent (POINT far *pPt);
extern void pascal near winGetClip (RECTANGLE far *pRect);
extern void pascal near winSetClip (RECTANGLE far *pRect);
extern void pascal near winGetPattern (unsigned char far *pattern);
extern void pascal near winSetPattern (unsigned char far *pattern);

extern void pascal near winDrawLine
 (integer x1, integer y1, integer x2, integer y2);
extern void pascal near winEraseLine
 (integer x1, integer y1, integer x2, integer y2);
extern void pascal near winInvertLine
 (integer x1, integer y1, integer x2, integer y2);
extern void pascal near winPatternLine
 (integer x1, integer y1, integer x2, integer y2);
extern void pascal near winDrawRectangle (RECTANGLE far *pRect);
extern void pascal near winEraseRectangle (RECTANGLE far *pRect);
extern void pascal near winInvertRectangle (RECTANGLE far *pRect);

extern void pascal near winDrawRectFrame (RECTANGLE far *pRect);
extern void pascal near winInvertRectFrame (RECTANGLE far *pRect);
extern void pascal near winDrawCircleFrame
 (integer x, integer y, integer diameter);
extern void pascal near winInvertCircleFrame
 (integer x, integer y, integer diameter);
extern void pascal near winDrawRoundedRectFrame
 (RECTANGLE far *pRect, integer cornerDiameter);
extern void pascal near winInvertRoundedRectFrame
 (RECTANGLE far *pRect, integer cornerDiameter);

extern short pascal near fntCharsWidth (char far *pChars, unsigned short len);
extern short pascal near fntCharHeight (void);

extern void pascal near csrTurnCursorOff (void);
extern void pascal near csrTurnCursorOn (void);
extern void pascal near csrMoveCursor (integer newXLoc, integer newYLoc);
extern void pascal near csrSetCursor
 (word cursorNumber, integer xOffset, integer yOffset);

extern boolean pascal near rctPtInRectangle
 (integer x, integer y, RECTANGLE far *pRect);
extern void pascal near rctInsetRectangle
 (RECTANGLE far *pRect, integer insetAmt);
extern void pascal near rctOffsetRectangle
 (RECTANGLE far *pRect, integer xDelta, integer yDelta);

/* End of what will become the gpwindow.h include/header file */


/* This eventually will become the gpevents.h include/header file */

#define DOUBLE_PENDOWN_MASK 1
#define SINGLE_PENDOWN      0
#define DOUBLE_PENDOWN      1

enum events {nullEvent, penDownEvent, penUpEvent, keyDownEvent, keyUpEvent,
             characterEvent, enterWindowEvent, exitWindowEvent, controlEvent,
             menuEvent, dialogEvent};

typedef struct {
  enum events    eType;
  unsigned long  timeOfEvent;
  unsigned char  penDown;     /* A Boolean value */
  unsigned short ch;
  short          screenX;
  short          screenY;
  short          overlayX;
  short          overlayY;
  unsigned short data1;
  unsigned short data2;
  unsigned short data3;
  unsigned short data4;
  unsigned short data5;
  unsigned short data6;
} EVENTRECD;

extern void pascal near evtGetEvent (EVENTRECD far *event, word far *error);
extern unsigned long pascal near evtCurrentTick (void);

/*
  PROCEDURE AddEventToQueue (VAR event: EventType);
*/

/* End of what will become the gpevents.h include/header file */


/* This eventually will become the gpoverly.h include/header file */

extern void pascal near ovlGetPt
 (integer far *pScreenX, integer far *pScreenY,
  boolean far *pPenDown, word far *pError);

/* End of what will become the gpoverly.h include/header file */


/* This eventually will become the gpcntrls.h include/header file */

enum controls {buttonCtrl=2, checkboxCtrl, radioCtrl,
               invButtonCtrl, a3dButtonCtrl};

typedef struct {
  unsigned short len;
  unsigned short max;
  unsigned char  dummy;
  char           chars[32];
} STRINGRECD;

typedef struct {
  unsigned char  visible;    /* A Boolean value */
  unsigned char  active;     /* A Boolean value */
  unsigned short ctrlID;
  unsigned short ctrlType;
  short          value;
  short          minValue;
  short          maxValue;
  unsigned long  userData;
  int        far *futureExp;
  RECTANGLE      rect;
  STRINGRECD far *text;
} CONTROLRECD;

extern void pascal near ctlInitControl
 (CONTROLRECD far *pControl, unsigned short controlID,
  unsigned short controlType, short initValue, short loValue, short hiValue,
  unsigned long usersData, RECTANGLE far *pRect, STRINGRECD far *pString);
extern void pascal near ctlFreeControlInfo (CONTROLRECD far *pControl);
extern void pascal near ctlOffsetControl
 (CONTROLRECD far *pControl, short deltaX, short deltaY);
extern void pascal near ctlMakeControlActive (CONTROLRECD far *pControl);
extern void pascal near ctlMakeControlInactive (CONTROLRECD far *pControl);
extern void pascal near ctlSetControlValue
 (CONTROLRECD far *pControl, short newValue);
extern void pascal near ctlDrawControl (CONTROLRECD far *pControl);
extern unsigned char pascal near ctlControlPressed
 (CONTROLRECD far *pControl, short x, short y);

/* End of what will become the gpoverly.h include/header file */

/****************************************************************/

/****************************************************************
                    Private module declarations
*****************************************************************/

#define BORDERSIZE       30
#define INSET_AMT         2
#define BUTTON_FUDGE      4  /* The white space around text in the buttons */
#define BUTTON_INSET_AMT  8  /* Distance between button and button or frame */
#define PALETTE_WIDTH    18  /* Width of cursor plus 1 pixel inversion frame*/
#define PALETTE_HEIGHT   18  /* Width of cursor plus 1 pixel inversion frame*/
#define NUM_PALETTES      6

enum drawChoices {penChoice, eraserChoice, lineChoice,
                  rectChoice, rndRectChoice, circleChoice};

enum myControls  {okayCtrlID, cancelCtrlID};

enum cursorTypes curDrawCursor;
enum cursorTypes currentCursor;
short            curDrawChoice;
short            lastDrawChoice;
word             windowID;
RECTANGLE        scribbleRect;
RECTANGLE        drawAreaRect;
RECTANGLE        paletteRect;
RECTANGLE        paletteRects [NUM_PALETTES];
CONTROLRECD      okayControl;
CONTROLRECD      cancelControl;

STRINGRECD       okayString   = {2, 2, 2, "OK"};
STRINGRECD       cancelString = {6, 6, 6, "Cancel"};

unsigned char    ptn1 [8] = {0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8};
unsigned char    ptn2 [8] = {0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x3E};
unsigned char    ptn3 [8] = {0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F};
unsigned char    ptn4 [8] = {0xE3, 0xE3, 0xE3, 0xE3, 0xE3, 0xE3, 0xE3, 0xE3};

/* Forward definitions (prototypes) of procedures in this module */

void scribblePad (word *error);
void checkForPenInPaletteOrDrawArea (EVENTRECD *pEvent);
void handleCurrentDrawingTask (integer screenX, integer screenY);
void drawAnchoredItem
 (integer anchorX, integer anchorY, integer x, integer y, boolean invertIt);
void setRectFromTwoPoints
 (RECTANGLE *pRect, integer x1, integer y1, integer x2, integer y2);
void checkForCursorChange (EVENTRECD *pEvent);
void initializeScribblePad (RECTANGLE *spRect);
void drawScribblePad (void);
void drawAroundRect (RECTANGLE *pRect);
void invertInsetRect (RECTANGLE *pRect);
integer min (integer x, integer y);


/****************************************************************/

main ()
{

  char      c;
  word      error;
  RECTANGLE r;


  mniInitialize ();
  c = getchar ();

  r.topLeft.x = 0;
  r.topLeft.y = 0;
  winGetDisplayExtent (&r.extent);
  rctInsetRectangle (&r, BORDERSIZE);
  windowID = winCreateWindow (&r, framedWindow, sw3DShadow2, FALSE, &error);
  if (error == 0) {
    winSetDrawWindow (windowID);
    scribblePad (&error);
  }

  c = getchar ();
  mniTerminate ();

}

/****************************************************************/

void scribblePad (word *pError)
{

  boolean   timeToExit;
  RECTANGLE spRect;
  EVENTRECD event;


  timeToExit = FALSE;
  spRect.topLeft.x = 0;
  spRect.topLeft.y = 0;
  winGetWindowExtent (&spRect.extent);
  initializeScribblePad (&spRect);

  {

  register unsigned int index;
  unsigned long startTime;

  for (index = 0; index < 100; ++index) {
    winSetPattern (&ptn1[0]);
    winPatternLine (100,100, 400,100);
    startTime = evtCurrentTick();
    for (;startTime == evtCurrentTick();)
      ; /* Wait for 55 mSecs to pass */

    winSetPattern (&ptn2[0]);
    winPatternLine (100,100, 400,100);
    startTime = evtCurrentTick();
    for (;startTime == evtCurrentTick();)
      ; /* Wait for 55 mSecs to pass */

    winSetPattern (&ptn3[0]);
    winPatternLine (100,100, 400,100);
    startTime = evtCurrentTick();
    for (;startTime == evtCurrentTick();)
      ; /* Wait for 55 mSecs to pass */

    winSetPattern (&ptn4[0]);
    winPatternLine (100,100, 400,100);
    startTime = evtCurrentTick();
    for (;startTime == evtCurrentTick();)
      ; /* Wait for 55 mSecs to pass */
  }

  }


  do {
    evtGetEvent (&event, pError);
    if (*pError == 0) {
      if (event.eType == penDownEvent) {
        if (rctPtInRectangle
             (event.screenX, event.screenY, &okayControl.rect)) {
          if (ctlControlPressed
               (&okayControl, event.screenX, event.screenY))
            timeToExit = TRUE;
        }
        else if (rctPtInRectangle
             (event.screenX, event.screenY, &cancelControl.rect)) {
          if (ctlControlPressed
               (&cancelControl, event.screenX, event.screenY))
            timeToExit = TRUE;
        }
        else
          checkForPenInPaletteOrDrawArea (&event);
      }
      else if ((event.eType == nullEvent) || (event.eType == penUpEvent)) {
        checkForCursorChange (&event);
      }
      else if (event.eType == keyUpEvent) {
        timeToExit = TRUE;
      }
    }
  } while (!timeToExit);
}

/****************************************************************/

void checkForPenInPaletteOrDrawArea (EVENTRECD *pEvent)
{
  boolean          penDown;
  integer          screenX;
  integer          screenY;
  enum drawChoices index;

  checkForCursorChange (pEvent);
  screenX = pEvent->screenX;
  screenY = pEvent->screenY;
  if (rctPtInRectangle (screenX, screenY, &paletteRect)) {
    for (index = penChoice; index <= lastDrawChoice; ++index) {
      if (rctPtInRectangle (screenX, screenY, &paletteRects[index])) {
        if (index != curDrawChoice) {
          invertInsetRect (&paletteRects[curDrawChoice]);
          curDrawChoice = index;
          invertInsetRect (&paletteRects[curDrawChoice]);
          if (curDrawChoice == penChoice)
            curDrawCursor = penCursor;
          else if (curDrawChoice == eraserChoice)
            curDrawCursor = boxCursor;
          else /* curDrawChoice == line, rect, rndRect or circle choice */
            curDrawCursor = crsCursor;
        }
        else if ((pEvent->data1 & DOUBLE_PENDOWN_MASK) == DOUBLE_PENDOWN) {
          if (index == eraserChoice)
            winEraseRectangle (&drawAreaRect);
        }
      }
    }
  }
  else if (rctPtInRectangle (screenX, screenY, &drawAreaRect)) {
    handleCurrentDrawingTask (screenX, screenY);
  }
}

/****************************************************************/

void handleCurrentDrawingTask (integer screenX, integer screenY)
{
  boolean   penDown, firstTime, anchoredChoice;
  boolean   ptInDrawArea, lastPtInDrawArea;
  word      error;
  integer   lastScreenX, lastScreenY, anchorX, anchorY;
  RECTANGLE r, saveClip;


  penDown = TRUE;
  firstTime = TRUE;
  lastPtInDrawArea = TRUE;
  lastScreenX = screenX;
  lastScreenY = screenY;
  anchoredChoice = 
   ((curDrawChoice == lineChoice) || (curDrawChoice == rectChoice) ||
    (curDrawChoice == rndRectChoice) || (curDrawChoice == circleChoice));
  if (anchoredChoice) {
    anchorX = screenX;
    anchorY = screenY;
  }
  do {
    ptInDrawArea = rctPtInRectangle (screenX, screenY, &drawAreaRect);
    if (ptInDrawArea || lastPtInDrawArea || anchoredChoice) {
      winGetClip (&saveClip);
      winSetClip (&drawAreaRect);
      if (curDrawChoice == penChoice)
        winDrawLine (lastScreenX, lastScreenY, screenX,  screenY);
      else if (curDrawChoice == eraserChoice) {
        r.topLeft.x = screenX - 4;
        r.topLeft.y = screenY - 4;
        r.extent.x  = 9;
        r.extent.y  = 9;
        winEraseRectangle (&r);
      }
      else { /* Only anchored choices remain */
        if (! firstTime)
          drawAnchoredItem (anchorX, anchorY, lastScreenX, lastScreenY, TRUE);
        drawAnchoredItem (anchorX, anchorY, screenX, screenY, TRUE);
      }
      winSetClip (&saveClip);
    }
    lastScreenX = screenX;
    lastScreenY = screenY;
    lastPtInDrawArea = ptInDrawArea;
    do {
      ovlGetPt (&screenX, &screenY, &penDown, &error);
    } while ((penDown) && (error == 0) &&
             (screenX == lastScreenX) && (screenY == lastScreenY));
    firstTime = FALSE;
  } while ((penDown) && (error == 0));
  if (anchoredChoice) {
    winGetClip (&saveClip);
    winSetClip (&drawAreaRect);
    drawAnchoredItem (anchorX, anchorY, lastScreenX, lastScreenY, FALSE);
    winSetClip (&saveClip);
  }
}

/****************************************************************/

void drawAnchoredItem
 (integer anchorX, integer anchorY, integer x, integer y, boolean invertIt)
{
  RECTANGLE r;

  if (curDrawChoice == lineChoice) {
    if (invertIt)
      winInvertLine (anchorX, anchorY, x, y);
    else
      winDrawLine (anchorX, anchorY, x, y);
  }
  else { /* Only other anchored choices are rect, rndRect & circle choices */
    setRectFromTwoPoints (&r, anchorX, anchorY, x, y);
    if (curDrawChoice == rectChoice) {
      if (invertIt)
        winInvertRectFrame (&r);
      else
        winDrawRectFrame (&r);
    }
    else if (curDrawChoice == rndRectChoice) {
      if (invertIt)
        winInvertRoundedRectFrame (&r, min(min(r.extent.x, r.extent.y), 18));
      else
        winDrawRoundedRectFrame (&r, min(min(r.extent.x, r.extent.y), 18));
    }
    else { /* circle choice is only choice left over */
      if (invertIt)
        winInvertCircleFrame (r.topLeft.x, r.topLeft.y, r.extent.x);
      else
        winDrawCircleFrame (r.topLeft.x, r.topLeft.y, r.extent.x);
    }
  }
}

/****************************************************************/

void setRectFromTwoPoints
 (RECTANGLE *pRect, integer x1, integer y1, integer x2, integer y2)
{
  pRect->topLeft.x = (x1 < x2) ? x1 : x2; /* Min */
  pRect->topLeft.y = (y1 < y2) ? y1 : y2; /* Min */
  pRect->extent.x  = abs (x2 - x1) + 1;
  pRect->extent.y  = abs (y2 - y1) + 1;
}

/****************************************************************/

void checkForCursorChange (EVENTRECD *pEvent)
{
  enum cursorTypes newCursor;

  newCursor = currentCursor;
  if (rctPtInRectangle (pEvent->screenX, pEvent->screenY, &drawAreaRect)) {
    if (currentCursor != curDrawCursor) {
      newCursor = curDrawCursor;
    }
  }
  else if (currentCursor == curDrawCursor) {
    newCursor = ptrCursor;
  }
  if (newCursor != currentCursor) {
    currentCursor = newCursor;
    csrSetCursor (currentCursor,
                  cursorXOffsets[currentCursor],
                  cursorYOffsets[currentCursor]);
  }
}

/****************************************************************/

void initializeScribblePad (RECTANGLE *spRect)
{

  integer      scribbleRight;
  integer      scribbleBottom;
  integer      bottomMargin;
  integer      buttonHeight;
  integer      buttonWidth;
  integer      controlTop;
  integer      okayLeft;
  integer      cancelLeft;
  RECTANGLE    r;


  scribbleRect.topLeft.x = spRect->topLeft.x;
  scribbleRect.topLeft.y = spRect->topLeft.y;
  scribbleRect.extent.x  = spRect->extent.x;
  scribbleRect.extent.y  = spRect->extent.y;

  scribbleRight  = scribbleRect.topLeft.x + scribbleRect.extent.x - 1;
  scribbleBottom = scribbleRect.topLeft.y + scribbleRect.extent.y - 1;
  bottomMargin   = (fntCharHeight() * 2) + INSET_AMT;

  buttonHeight = fntCharHeight() + BUTTON_FUDGE;
  buttonWidth  = fntCharsWidth (&cancelString.chars[0], cancelString.len);
  controlTop   = scribbleBottom - ((bottomMargin >> 1) + (buttonHeight >> 1));
  okayLeft     = scribbleRight - (buttonWidth + BUTTON_INSET_AMT);
  cancelLeft   = okayLeft - (buttonWidth + BUTTON_INSET_AMT);

  r.topLeft.x = okayLeft;
  r.topLeft.y = controlTop;
  r.extent.x  = buttonWidth;
  r.extent.y  = buttonHeight;
  ctlInitControl (&okayControl, okayCtrlID, buttonCtrl,
                  0, 0, 0, 0, &r, &okayString);

  r.topLeft.x   = cancelLeft;
/* These values were just set above -
  r.topLeft.y   = controlTop;
  r.extent.x    = buttonWidth;
  r.extent.y    = buttonHeight;
*/
  ctlInitControl (&cancelControl, cancelCtrlID, buttonCtrl,
                  0, 0, 0, 0, &r, &cancelString);

  drawAreaRect = scribbleRect;
  rctInsetRectangle (&drawAreaRect, INSET_AMT+1);

  drawAreaRect.extent.y = drawAreaRect.extent.y - bottomMargin + INSET_AMT+1;
  drawAreaRect.extent.x = drawAreaRect.extent.x - (PALETTE_WIDTH+1);
  rctOffsetRectangle (&drawAreaRect, PALETTE_WIDTH+1, 0);

  paletteRect = drawAreaRect;
  paletteRect.extent.x = PALETTE_WIDTH;
  rctOffsetRectangle (&paletteRect, -(PALETTE_WIDTH+1), 0);

  r = paletteRect;
  r.extent.x = PALETTE_WIDTH;
  r.extent.y = PALETTE_HEIGHT;

  curDrawChoice = penChoice;
  lastDrawChoice = circleChoice;

  {
    register enum drawChoices index;

    for (index = penChoice; index <= lastDrawChoice; ++index) {
      paletteRects[index] = r;
      rctOffsetRectangle (&r, 0, PALETTE_HEIGHT+1);
    }
  }

  /* Defer drawing the window frame and erasing the window until after */
  /* most initialization is complete to make things look faster.       */

  winEraseWindow ();
  winDrawWindowFrame ();
  drawScribblePad ();

  currentCursor = ptrCursor;
  curDrawCursor = penCursor;
}

/****************************************************************/

void drawScribblePad ()
{

  integer   x, y, index;
  RECTANGLE r;


  winEraseRectangle (&scribbleRect);
  drawAroundRect (&paletteRect);
  drawAroundRect (&drawAreaRect);

  for (index = penChoice; index <= lastDrawChoice; ++index) {
    r = paletteRects[index];
    /* Draw image for each palette choice */
    switch (index) {
      case penChoice:
        x = r.topLeft.x + 1;
        y = r.topLeft.y + 1;
        /* This mess draws a pen image - yeech!! */
        winDrawLine (x+9,  y+4,  x+12, y+1);
        winDrawLine (x+2,  y+12, x+13, y+1);
        winDrawLine (x+1,  y+14, x+14, y+1);
        winDrawLine (x+3,  y+13, x+14, y+2);
        winDrawLine (x+11, y+6,  x+14, y+3);
        winDrawLine (x+9,  y+9,  x+12, y+6);
        break;
      case eraserChoice:
        x = r.topLeft.x + 1;
        y = r.topLeft.y + 1;
        /* This mess draws a chalkboard eraser image - yeech!! */
        winDrawLine (x+8,  y+2,  x+1,  y+9);
        winDrawLine (x+8,  y+2,  x+14, y+2);
        winDrawLine (x+14, y+2,  x+7,  y+9);
        winDrawLine (x+14, y+2,  x+14, y+6);
        winDrawLine (x+14, y+5,  x+7,  y+12);
        winDrawLine (x+14, y+6,  x+7,  y+13);
        winDrawLine (x+1,  y+9,  x+7,  y+9);
        winDrawLine (x+1,  y+9,  x+1,  y+12);
        winDrawLine (x+1,  y+12, x+7,  y+12);
        winDrawLine (x+7,  y+9,  x+7,  y+13);
        winDrawLine (x+7,  y+13, x+2,  y+13);
        break;
      case lineChoice:
        rctInsetRectangle (&r, +4);
        winDrawLine (r.topLeft.x + r.extent.x-1, r.topLeft.y,
                     r.topLeft.x, r.topLeft.y + r.extent.y-1);
        rctInsetRectangle (&r, -4);
        break;
      case rectChoice:
      case rndRectChoice:
        rctInsetRectangle (&r, +3);
        r.topLeft.y = r.topLeft.y + 1;
        r.extent.y  = r.extent.y - 2;
        if (index == rectChoice)
          winDrawRectFrame (&r);
        else
          winDrawRoundedRectFrame (&r, 8);
        r.topLeft.y = r.topLeft.y - 1;
        r.extent.y  = r.extent.y + 2;
        rctInsetRectangle (&r, -3);
        break;
      case circleChoice:
        winDrawCircleFrame (r.topLeft.x+4, r.topLeft.y+4, r.extent.x-8);
        break;
    }
    drawAroundRect (&r);
  }

  invertInsetRect (&paletteRects[curDrawChoice]);
  ctlDrawControl (&cancelControl);
  ctlDrawControl (&okayControl);
}

/****************************************************************/

void drawAroundRect (RECTANGLE *pRect)
{
  rctInsetRectangle (pRect, -1);
  winDrawRectFrame (pRect);
  rctInsetRectangle (pRect, +1);
}


void invertInsetRect (RECTANGLE *pRect)
{
  rctInsetRectangle (pRect, +1);
  winInvertRectangle (pRect);
  rctInsetRectangle (pRect, -1);
}


integer min (integer x, integer y)
{
  return ((x < y) ? x : y);
}
