TweetFollow Us on Twitter

MACINTOSH C

Demonstration Program

Go to Contents
// ××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××
// QuickDraw.c
// ××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××
// 
// This program:
//
// Ą  Opens a window in which the results of various QuickDraw drawing operations are
//    displayed.  Individual line and text drawing, framing, painting, filling, erasing, 
//    inverting, and copying operations are chosen from a Demonstration pull-down menu.
//
// Ą  Quits when the user chooses Quit from the File menu.
//
// To keep the non-QuickDraw code to a minimum, the program contains no functions for
// updating the window or for responding to activate and operating system events.
//
// The program utilises the following resources:
//
// Ą  'WIND' resources for the main window, and a small window used for the CopyBits
//    demonstration (purgeable) (initially visible).
//
// Ą  An 'MBAR' resource and associated 'MENU' resources (preload, non-purgeable).
//
// Ą  Two 'ICON' resources (purgeable) used for the boolean source modes demonstration. 
//
// Ą  Two 'PICT' resources (purgeable) used in the arithmetic source modes demonstration.
//
// Ą  'STR#' resources (purgeable) containing strings used in the source modes and text
//    drawing demonstrations.
//
// Ą  Three 'ppat' resources (purgeable), two of which are used in various drawing, 
//    framing, painting, filling, and erasing demonstrations.  The third is used in the
//    drawing with mouse demonstration.
//
// Ą  A 'SIZE' resource with with is32BitCompatible flag set.
//
// ××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××

// ............................................................................. includes

#include <Appearance.h>
#include <Devices.h>
#include <Gestalt.h>
#include <LowMem.h>
#include <Sound.h>
#include <ToolUtils.h>

// .............................................................................. defines

#define rMenubar                 128
#define mApple                   128
#define  iAbout                  1
#define mFile                    129
#define  iQuit                   11
#define mDemonstration           131
#define  iLine                   1
#define  iFrameAndPaint          2
#define  iFillEraseInvert        3
#define  iPolygonRegion          4
#define  iText                   5
#define  iScrolling              6
#define  iBooleanSourceModes     7
#define  iArithmeticSourceModes  8
#define  iHighlighting           9
#define  iDrawWithMouse          10
#define  iDrawingState           11
#define rWindow                  128
#define rPixelPattern1           128
#define rPixelPattern2           129
#define rPixelPattern3           130
#define rDestinationIcon         128
#define rSourceIcon              129
#define rFontsStringList         128
#define rBooleanStringList       129
#define rArithmeticStringList    130
#define rPicture                 128
#define MAXLONG                  0x7FFFFFFF

// ............................................................................. typedefs

struct drawingState
{
  PenState       penLocSizeModePat;
  RGBColor       requestedForeColour;
  RGBColor       requestedBackColour;
  SInt16         textTransferMode;
  PixPatHandle   penPixelPattern;
  PixPatHandle   backPixelPattern;
  Pattern        penBitPattern;
  Pattern        backBitPattern;
};
typedef struct drawingState drawingState;

// ..................................................................... global variables

Boolean    gMacOS85Present  = false;
Boolean    gDone;
WindowPtr  gWindowPtr;
Boolean    gDrawWithMouseActivated;
SInt16     gPixelDepth;  
Boolean    gIsColourDevice  = false;
RGBColor   gWhiteColour     = { 0xFFFF, 0xFFFF, 0xFFFF };
RGBColor   gBlackColour     = { 0x0000, 0x0000, 0x0000 };
RGBColor   gRedColour       = { 0xAAAA, 0x0000, 0x0000 };
RGBColor   gYellowColour    = { 0xFFFF, 0xCCCC, 0x0000 };
RGBColor   gGreenColour     = { 0x0000, 0x9999, 0x0000 };
RGBColor   gBlueColour      = { 0x6666, 0x6666, 0x9999 };

// .................................................................. function prototypes

void    main                       (void);
void    doInitManagers             (void);
void    doEvents                   (EventRecord *);
void    doDemonstrationMenu        (SInt16);
void    doLines                    (void);
void    doFrameAndPaint            (void);
void    doFillEraseInvert          (void);
void    doPolygonAndRegion         (void);
void    doScrolling                (void);
void    doText                     (void);
void    doBooleanSourceModes       (void);
void    doArithmeticSourceModes    (void);
void    doHighlighting             (void);
void    doDrawWithMouse            (void);
void    doDrawingState             (void);
void    doGetDrawingState          (drawingState *);
void    doSetDrawingState          (drawingState *);
void    doNormalizeDrawingState    (void);
void    doDrawingStateProof        (SInt16);
void    doGetDepthAndDevice        (void);
UInt16  doRandomNumber             (UInt16,UInt16);

// ××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× main

void  main(void)
{
  OSErr        osError;
  SInt32       response;
  Handle       menubarHdl;
  MenuHandle   menuHdl;
  EventRecord  eventStructure;
  Boolean      gotEvent;    

  // ................................................................ initialise managers

  doInitManagers();

  // ....................................... check whether Mac OS 8.5 or later is present

  osError = Gestalt(gestaltSystemVersion,&response);
  
  if(osError == noErr && response >= 0x00000850)
    gMacOS85Present = true;
  
  // ........................................................ see random number generator
  
  GetDateTime((UInt32 *) (&qd.randSeed));
  
  // .......................................................... set up menu bar and menus
  
  if(!(menubarHdl = GetNewMBar(rMenubar)))
    ExitToShell();
  SetMenuBar(menubarHdl);
  DrawMenuBar();

  if(!(menuHdl = GetMenuHandle(mApple)))
    ExitToShell();
  else
    AppendResMenu(menuHdl,'DRVR');

  // ........................................................................ open window

  if(!(gWindowPtr = GetNewCWindow(rWindow,NULL,(WindowPtr)-1)))
    ExitToShell();

  SetPort(gWindowPtr);
  TextSize(10);

  // ......... get pixel depth and whether colour device for certain Appearance functions   
  
  doGetDepthAndDevice();

  // .......................................................................... eventLoop

  gDone = false;

  while(!gDone)
  {
    gotEvent = WaitNextEvent(everyEvent,&eventStructure,MAXLONG,NULL);
    if(gotEvent)
      doEvents(&eventStructure);
  }
}

// ××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doInitManagers

void  doInitManagers(void)
{
  MaxApplZone();
  MoreMasters();

  InitGraf(&qd.thePort);
  InitFonts();
  InitWindows();
  InitMenus();
  TEInit();
  InitDialogs(NULL);

  InitCursor();  
  FlushEvents(everyEvent,0);

  RegisterAppearanceClient();
}

// ××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doEvents

void  doEvents(EventRecord *eventStrucPtr)
{
  SInt8      charCode;
  SInt32     menuChoice;
  SInt16     menuID, menuItem;
  SInt16     partCode;
  WindowPtr  windowPtr;
  Str255     itemName;
  SInt16     daDriverRefNum;
  
  switch(eventStrucPtr->what)
  {
    case keyDown:
    case autoKey:
      charCode = eventStrucPtr->message & charCodeMask;
      if((eventStrucPtr->modifiers & cmdKey) != 0)
      {
        menuChoice = MenuEvent(eventStrucPtr);
        menuID = HiWord(menuChoice);
        menuItem = LoWord(menuChoice);
        if(menuID == mFile && menuItem  == iQuit)
          gDone = true;
      }
      break;

    case mouseDown:
      if(partCode = FindWindow(eventStrucPtr->where,&windowPtr))
      {
        switch(partCode)
        {
          case inMenuBar:
            menuChoice = MenuSelect(eventStrucPtr->where);
            menuID = HiWord(menuChoice);
            menuItem = LoWord(menuChoice);

            if(menuID == 0)
              return;

            switch(menuID)
            {
              case mApple:
                if(menuItem == iAbout)
                  SysBeep(10);
                else
                {
                  GetMenuItemText(GetMenuHandle(mApple),menuItem,itemName);
                  daDriverRefNum = OpenDeskAcc(itemName);
                }
                break;

              case mFile:
                if(menuItem == iQuit)
                  gDone = true;
                break;
                
              case mDemonstration:
                doDemonstrationMenu(menuItem);
                break;
            }
            HiliteMenu(0);
            break;
          
          case inDrag:
            DragWindow(windowPtr,eventStrucPtr->where,&qd.screenBits.bounds);
            break;
    
          case inContent:
            if(windowPtr != FrontWindow())
              SelectWindow(windowPtr);
            else
              if(gDrawWithMouseActivated)
                doDrawWithMouse();
            break;
        }
      }
      break;
      
    case updateEvt:
      windowPtr = (WindowPtr) eventStrucPtr->message;
      BeginUpdate(windowPtr);
      EndUpdate(windowPtr);
      break;
  }
}

// ×××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doDemonstrationMenu

void  doDemonstrationMenu(SInt16 menuItem)
{
  gDrawWithMouseActivated = false;

  switch(menuItem)
  {
    case iLine:
      doLines();
      break;

    case iFrameAndPaint:
      doFrameAndPaint();
      break;      

    case iFillEraseInvert:
      doFillEraseInvert();
      break;

    case iPolygonRegion:
      doPolygonAndRegion();
      break;

    case iText:
      doText();
      break;

    case iScrolling:
      doScrolling();
      break;

    case iBooleanSourceModes:
      doBooleanSourceModes();
      break;
  
    case iArithmeticSourceModes:
      doArithmeticSourceModes();
      break;

    case iHighlighting:
      doHighlighting();
      break;

    case iDrawWithMouse:
      SetWTitle(gWindowPtr,"\pDrawing with the mouse");
      RGBBackColor(&gWhiteColour);
      FillRect(&gWindowPtr->portRect,&qd.white);
      gDrawWithMouseActivated = true;
      break;
    
    case iDrawingState:
      doDrawingState();
      break;
  }
}

// ×××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doLines

void  doLines(void)
{
  RgnHandle      oldClipRgn;
  Rect           newClipRect;
  SInt16         a, b, c, top, left, bottom, right;
  RGBColor       theColour;
  UInt32         finalTicks;
  Pattern        systemPattern;
  PixPatHandle   pixpatHdl;  

  PenNormal();

  RGBBackColor(&gBlueColour);
  FillRect(&gWindowPtr->portRect,&qd.white);

  newClipRect = gWindowPtr->portRect;
  InsetRect(&newClipRect,10,10);
  oldClipRgn = NewRgn();
  GetClip(oldClipRgn);
  ClipRect(&newClipRect);
  
  // ........................... lines drawn with foreground colour and black pen pattern

  SetWTitle(gWindowPtr,"\pDrawing lines with colours");
  RGBBackColor(&gWhiteColour);
  FillRect(&gWindowPtr->portRect,&qd.white);

  for(a=1;a<60;a++)
  {
    b = doRandomNumber(0,gWindowPtr->portRect.right - gWindowPtr->portRect.left);
    c = doRandomNumber(0,gWindowPtr->portRect.right - gWindowPtr->portRect.left);

    theColour.red   = doRandomNumber(0,65535);
    theColour.green = doRandomNumber(0,65535);
    theColour.blue  = doRandomNumber(0,65535);
    RGBForeColor(&theColour);
  
    PenSize(a * 2,1);    

    MoveTo(b,gWindowPtr->portRect.top);
    LineTo(c,gWindowPtr->portRect.bottom);

    Delay(2,&finalTicks);
  }    

  // ...................................... lines drawn with system-supplied bit patterns

  SetWTitle(gWindowPtr,"\pClick mouse for more lines");
  while(!Button()) ;  
  SetWTitle(gWindowPtr,"\pDrawing lines with system-supplied bit patterns");
  FillRect(&gWindowPtr->portRect,&qd.white);
  c = 0;
    
  for(a=1;a<39;a++)
  {
    b = doRandomNumber(0,gWindowPtr->portRect.bottom - gWindowPtr->portRect.top);
    c = doRandomNumber(0,gWindowPtr->portRect.bottom - gWindowPtr->portRect.top);

    theColour.red   = doRandomNumber(0,32767);
    theColour.green = doRandomNumber(0,32767);
    theColour.blue  = doRandomNumber(0,32767);
    RGBForeColor(&theColour);
  
    GetIndPattern(&systemPattern,sysPatListID,a);
    PenPat(&systemPattern);

    PenSize(1, a * 2);    

    MoveTo(gWindowPtr->portRect.left,b);
    LineTo(gWindowPtr->portRect.right,c);

    Delay(5,&finalTicks);
  }    

  // ................................................... lines drawn with a pixel pattern

  SetWTitle(gWindowPtr,"\pClick mouse for more lines");
  while(!Button()) ;  
  SetWTitle(gWindowPtr,"\pDrawing lines with a pixel pattern");
  FillRect(&gWindowPtr->portRect,&qd.white);

  if(!(pixpatHdl = GetPixPat(rPixelPattern1)))
    ExitToShell();
  PenPixPat(pixpatHdl);

  for(a=1;a<60;a++)
  {
    b = doRandomNumber(0,gWindowPtr->portRect.right - gWindowPtr->portRect.left);
    c = doRandomNumber(0,gWindowPtr->portRect.right - gWindowPtr->portRect.left);

    PenSize(a * 2,1);    
  
    MoveTo(b,gWindowPtr->portRect.top);
    LineTo(c,gWindowPtr->portRect.bottom);

    Delay(5,&finalTicks);
  }    

  DisposePixPat(pixpatHdl);

  SetClip(oldClipRgn);
  DisposeRgn(oldClipRgn);

  // ............................................... lines drawn with pattern mode patXor

  SetWTitle(gWindowPtr,"\pClick mouse for more lines");
  while(!Button()) ;  
  SetWTitle(gWindowPtr,"\pDrawing lines using pattern mode patXor");

  RGBBackColor(&gRedColour);
  FillRect(&gWindowPtr->portRect,&qd.white);

  PenSize(1,1);    
  PenPat(&qd.black);
  PenMode(patXor);

  left    = gWindowPtr->portRect.left + 10;
  top      = gWindowPtr->portRect.top + 10;
  right    = gWindowPtr->portRect.right - 10;
  bottom  = gWindowPtr->portRect.bottom - 10;

  for(a=left,b=right;a<right+1;a++,b--)
  {
    MoveTo(a,top);
    LineTo(b,bottom);
  }

  for(a=bottom,b=top;b<bottom+1;a--,b++)
  {
    MoveTo(left,a);
    LineTo(right,b);
  }
}

// ×××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doFrameAndPaint

void  doFrameAndPaint(void)
{
  SInt16         a;
  Rect           theRect;
  UInt32         finalTicks;
  Pattern        systemPattern;
  PixPatHandle   pixpatHdl;  

  PenNormal();
  PenSize(30,20);
  
  for(a=0;a<3;a++)
  {
    RGBBackColor(&gWhiteColour);
    FillRect(&gWindowPtr->portRect,&qd.white);

    // ...................................................................... preparation

    if(a == 0)
    {
      SetWTitle(gWindowPtr,"\pFraming and painting with a colour");

      RGBForeColor(&gRedColour);                            // set foreground colour to red
    }
    else if(a == 1)
    {
      SetWTitle(gWindowPtr,"\pFraming and painting with a bit pattern");

      RGBForeColor(&gBlueColour);                         // set foreground colour to blue
      RGBBackColor(&gYellowColour);                     // set foreground colour to yellow
      GetIndPattern(&systemPattern,sysPatListID,16);           // get bit pattern for pen
      PenPat(&systemPattern);                                       // set pen bit pattern
    }
    else if (a == 2)
    {
      SetWTitle(gWindowPtr,"\pFraming and painting with a pixel pattern");

      if(!(pixpatHdl = GetPixPat(rPixelPattern1)))           // get pixel pattern for pen
        ExitToShell();
      PenPixPat(pixpatHdl);                                       // set pen pixel pattern
    }

    // ............................................................. framing and painting
  
    SetRect(&theRect,30,32,151,191);    
    FrameRect(&theRect);                                                     // FrameRect
    MoveTo(30,29);
    DrawString("\pFrameRect");  
    Delay(30,&finalTicks);

    OffsetRect(&theRect,140,0);
    FrameRoundRect(&theRect,30,50);                                      // FrameRoundRect
    MoveTo(170,29);
    DrawString("\pFrameRoundRect");  
    Delay(30,&finalTicks);

    OffsetRect(&theRect,140,0);
    FrameOval(&theRect);                                                     // FrameOval
    MoveTo(310,29);
    DrawString("\pFrameOval");  
    Delay(30,&finalTicks);

    OffsetRect(&theRect,140,0);
    FrameArc(&theRect,330,300);                                                // FrameArc
    MoveTo(450,29);
    DrawString("\pFrameArc");  
    Delay(30,&finalTicks);
  
    OffsetRect(&theRect,-420,186);
    PaintRect(&theRect);                                                     // PaintRect
    MoveTo(30,214);
    DrawString("\pPaintRect");  
    Delay(30,&finalTicks);

    OffsetRect(&theRect,140,0);
    PaintRoundRect(&theRect,30,50);                                      // PaintRoundRect
    MoveTo(170,214);
    DrawString("\pPaintRoundRect");  
    Delay(30,&finalTicks);

    OffsetRect(&theRect,140,0);
    PaintOval(&theRect);                                                     // PaintOval
    MoveTo(310,214);
    DrawString("\pPaintOval");  
    Delay(30,&finalTicks);

    OffsetRect(&theRect,140,0);
    PaintArc(&theRect,330,300);                                                // PaintArc
    MoveTo(450,214);
    DrawString("\pPaintArc");  
    Delay(30,&finalTicks);
  
    if(a < 2)
    {
      SetWTitle(gWindowPtr,"\pClick mouse for more");
      while(!Button()) ;
    }  
  }

  DisposePixPat(pixpatHdl);
}

// ×××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doFillEraseInvert

void  doFillEraseInvert(void)
{
  SInt16         a;
  Pattern        fillPat, backPat;
  PixPatHandle   fillPixpatHdl, backPixpatHdl;  
  Rect           theRect;
  UInt32         finalTicks;

  PenNormal();
  PenSize(30,20);
  
  for(a=0;a<4;a++)
  {
    if(a < 3)
    {
      RGBBackColor(&gWhiteColour);
      FillRect(&gWindowPtr->portRect,&qd.white);
    }

    // ...................................................................... preparation

    if(a == 0)
    {
      SetWTitle(gWindowPtr,"\pFilling and erasing with colours");

      RGBForeColor(&gBlueColour);                        // set blue colour for foreground
      RGBBackColor(&gRedColour);                         // set red colour for background
      GetIndPattern(&fillPat,sysPatListID,1);  // get black bit pattern for fill functions
      BackPat(&qd.white);                          // set white bit pattern for background
    }
    else if(a == 1)
    {
      SetWTitle(gWindowPtr,"\pFilling and erasing with bit patterns");

      RGBForeColor(&gBlueColour);                        // set blue colour for foreground
      RGBBackColor(&gYellowColour);                    // set yellow colour for background
      GetIndPattern(&fillPat,sysPatListID,37);      // get bit pattern for fill functions
      GetIndPattern(&backPat,sysPatListID,19);          // get bit pattern for background
      BackPat(&backPat);                                // set bit pattern for background
    }
    else if (a == 2)
    {
      SetWTitle(gWindowPtr,"\pFilling and erasing with pixel patterns");

      if(!(fillPixpatHdl = GetPixPat(rPixelPattern1))) // get pixel patt - fill functions
        ExitToShell();
      if(!(backPixpatHdl = GetPixPat(rPixelPattern2)))  // get pixel pattern - background
        ExitToShell();
      BackPixPat(backPixpatHdl);                        // set pixel pattern - background
    }
    else if(a == 3)
    {
      SetWTitle(gWindowPtr,"\pInverting");
      BackPat(&qd.white);
      SetRect(&theRect,30,15,570,29);
      EraseRect(&theRect);
      SetRect(&theRect,30,200,570,214);
      EraseRect(&theRect);
    }

    // .................................................. filling, erasing, and inverting
    
    SetRect(&theRect,30,32,151,191);    
    MoveTo(30,29);
    if(a < 2)
    {
      FillRect(&theRect,&fillPat);                                            // FillRect
      DrawString("\pFillRect");  
    }
    else if(a == 2)
    {
      FillCRect(&theRect,fillPixpatHdl);                                     // FillCRect
      DrawString("\pFillCRect");  
    }
    else if(a == 3)
    {
      InvertRect(&theRect);                                                  // InvertRect
      DrawString("\pInvertRect");  
    }    
    Delay(30,&finalTicks);

    OffsetRect(&theRect,140,0);
    MoveTo(170,29);
    if(a < 2)
    {
      FillRoundRect(&theRect,30,50,&fillPat);                             // FillRoundRect
      DrawString("\pFillRoundRect");  
    }
    else if(a == 2)
    {
      FillCRoundRect(&theRect,30,50,fillPixpatHdl);                      // FillCRoundRect
      DrawString("\pFillCRoundRect");  
    }
    else if(a == 3)
    {
      InvertRoundRect(&theRect,30,50);                                 // InvertRoundRect
      DrawString("\pInvertRoundRect");  
    }    
    Delay(30,&finalTicks);

    OffsetRect(&theRect,140,0);
    MoveTo(310,29);
    if(a < 2)
    {
      FillOval(&theRect,&fillPat);                                            // FillOval
      DrawString("\pFillOval");  
    }
    else if(a == 2)
    {
      FillCOval(&theRect,fillPixpatHdl);                                     // FillCOval
      DrawString("\pFillCOval");  
    }
    else if(a == 3)
    {
      InvertOval(&theRect);                                                  // InvertOval
      DrawString("\pInvertOval");  
    }    
    Delay(30,&finalTicks);

    OffsetRect(&theRect,140,0);
    MoveTo(450,29);
    if(a < 2)
    {
      FillArc(&theRect,330,300,&fillPat);                                       // FillArc
      DrawString("\pFillArc");  
    }
    else if(a == 2)
    {
      FillCArc(&theRect,330,300,fillPixpatHdl);                                // FillCArc
      DrawString("\pFillCArc");  
    }
    else if(a == 3)
    {
      InvertArc(&theRect,330,300);                                           // InvertArc
      DrawString("\pInvertArc");  
    }    
    Delay(30,&finalTicks);
  
  
    OffsetRect(&theRect,-420,186);
    MoveTo(30,214);
    if(a < 3)
    {
      EraseRect(&theRect);                                                   // EraseRect
      DrawString("\pEraseRect");  
    }
    else
    {
      InvertRect(&theRect);                                                  // InvertRect
      DrawString("\pInvertRect");  
    }
    Delay(30,&finalTicks);

    OffsetRect(&theRect,140,0);
    MoveTo(170,214);
    if(a < 3)
    {
      EraseRoundRect(&theRect,30,50);                                    // EraseRoundRect
      DrawString("\pEraseRoundRect");  
    }
    else
    {
      InvertRoundRect(&theRect,30,50);                                 // InvertRoundRect
      DrawString("\pInvertRoundRect");  
    }
    Delay(30,&finalTicks);

    OffsetRect(&theRect,140,0);
    MoveTo(310,214);
    if(a < 3)
    {  
      EraseOval(&theRect);                                                   // EraseOval
      DrawString("\pEraseOval");  
    }
    else
    {
      InvertOval(&theRect);                                                  // InvertOval
      DrawString("\pInvertOval");  
    }
    Delay(30,&finalTicks);

    OffsetRect(&theRect,140,0);
    MoveTo(450,214);
    if(a < 3)
    {
      EraseArc(&theRect,330,300);                                              // EraseArc
      DrawString("\pEraseArc");  
    }
    else
    {
      InvertArc(&theRect,330,300);                                           // InvertArc
      DrawString("\pInvertArc");  
    }
    Delay(30,&finalTicks);
  
    if(a < 3)
    {
      SetWTitle(gWindowPtr,"\pClick mouse for more");
      while(!Button()) ;
    }  
  }

  DisposePixPat(fillPixpatHdl);
  DisposePixPat(backPixpatHdl);
}

// ××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doPolygonAndRegion

void  doPolygonAndRegion(void)
{
  Pattern        backPat;
  PixPatHandle   fillPixpatHdl;  
  PolyHandle     polygonHdl;
  RgnHandle      regionHdl;
  UInt32         finalTicks;
  Rect           theRect;

  SetWTitle(gWindowPtr,"\pFraming, painting, filling, and erasing polygons and regions");

  RGBBackColor(&gWhiteColour);
  FillRect(&gWindowPtr->portRect,&qd.white);

  // ........................................................................ preparation
  
  GetIndPattern(&backPat,sysPatListID,17);              // get bit pattern for background
  BackPat(&backPat);                                    // set bit pattern for background
  if(!(fillPixpatHdl = GetPixPat(rPixelPattern2)))// get pixel pattern for fill functions
    ExitToShell();
  RGBForeColor(&gRedColour);                             // set red colour for foreground
  RGBBackColor(&gYellowColour);                       // set yellow colour for background
  PenNormal();  
  
  polygonHdl = OpenPoly();                                              // define polygon
  MoveTo(30,32);
  LineTo(151,32);
  LineTo(96,103);
  LineTo(151,134);  
  LineTo(151,191);
  LineTo(30,191);
  LineTo(66,75);
  ClosePoly();

  regionHdl = NewRgn();                                                   // define region
  OpenRgn();
  SetRect(&theRect,30,218,151,279);
  FrameRect(&theRect);
  SetRect(&theRect,30,316,151,377);
  FrameRect(&theRect);
  SetRect(&theRect,39,248,142,341);
  FrameOval(&theRect);
  CloseRgn(regionHdl);

  // ............................................ framing, painting, filling, and erasing  
  

  FramePoly(polygonHdl);                                                     // FramePoly
  MoveTo(30,29);
  DrawString("\pFramePoly (colour)");  
  Delay(30,&finalTicks);

  OffsetPoly(polygonHdl,140,0);
  PaintPoly(polygonHdl);                                                     // PaintPoly
  MoveTo(170,29);
  DrawString("\pPaintPoly (colour)");  
  Delay(30,&finalTicks);

  OffsetPoly(polygonHdl,140,0);
  FillCPoly(polygonHdl,fillPixpatHdl);                                       // FillCPoly
  MoveTo(310,29);
  DrawString("\pFillCPoly (pixel pattern)");  
  Delay(30,&finalTicks);

  OffsetPoly(polygonHdl,140,0);
  ErasePoly(polygonHdl);                                                     // ErasePoly
  MoveTo(450,29);
  DrawString("\pErasePoly (bit pattern)");  
  Delay(30,&finalTicks);
  
  FrameRgn(regionHdl);                                                        // FrameRgn
  MoveTo(30,214);
  DrawString("\pFrameRgn (colour)");  
  Delay(30,&finalTicks);

  OffsetRgn(regionHdl,140,0);
  PaintRgn(regionHdl);                                                        // PaintRgn
  MoveTo(170,214);
  DrawString("\pPaintRgn (colour)");  
  Delay(30,&finalTicks);

  OffsetRgn(regionHdl,140,0);
  FillCRgn(regionHdl,fillPixpatHdl);                                          // FillCRgn
  MoveTo(310,214);
  DrawString("\pFillCRgn (pixel pattern)");  
  Delay(30,&finalTicks);

  OffsetRgn(regionHdl,140,0);
  EraseRgn(regionHdl);                                                        // EraseRgn
  MoveTo(450,214);
  DrawString("\pEraseRgn (bit pattern)");  
  Delay(30,&finalTicks);

  KillPoly(polygonHdl);
  DisposeRgn(regionHdl);
  DisposePixPat(fillPixpatHdl);
  BackPat(&qd.white);    
}

// ××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doText

void  doText(void)
{
  SInt16    windowCentre, a, fontNum, stringWidth;
  Rect      theRect;
  Str255    textString;
  UInt32    finalTicks;
    
  RGBBackColor(&gWhiteColour);
  FillRect(&gWindowPtr->portRect,&qd.white);

  SetWTitle(gWindowPtr,"\pDrawing text with default source mode (srcOr)");
  
  windowCentre = (gWindowPtr->portRect.right - gWindowPtr->portRect.left) / 2;
  SetRect(&theRect,windowCentre,gWindowPtr->portRect.top,gWindowPtr->portRect.right,
          gWindowPtr->portRect.bottom);
  RGBBackColor(&gBlueColour);
  FillRect(&theRect,&qd.white);

  for(a=1;a<9;a++)
  {
    // ...................... set various text fonts, text styles, and foreground colours

    if(a == 1)
    {
      GetFNum("\pGeneva",&fontNum);
      TextFont(fontNum);
      TextFace(normal);
      RGBForeColor(&gRedColour);
    }
    else if(a == 2)
      TextFace(bold);
    else if(a == 3)
    {
      GetFNum("\pTimes",&fontNum);
      TextFont(fontNum);
      TextFace(italic);
      RGBForeColor(&gYellowColour);
    }
    else if(a == 4)
      TextFace(underline);
    else if(a == 5)
    {
      GetFNum("\pHelvetica",&fontNum);
      TextFont(fontNum);
      TextFace(outline);
      RGBForeColor(&gGreenColour);
    }
    else if(a == 6)
      TextFace(shadow);
    else if(a == 7)
    {
      GetFNum("\pChicago",&fontNum);
      TextFont(fontNum);
      TextFace(condense);
      RGBForeColor(&gBlackColour);
    }
    else if(a == 8)
    {
      TextFace(extend);
    }

    // .................................................................... set text size

    if(a < 7)
      TextSize(a * 2 + 15);
    else
      TextSize(12);
      
    // ..... get a string and draw it in the set font, style, size, and foreground colour

    GetIndString(textString,rFontsStringList,a);
    stringWidth = StringWidth(textString);
    MoveTo(windowCentre - (stringWidth / 2),a * 46 - 10);
    DrawString(textString);

    Delay(30,&finalTicks);
  }

  // ........................................................ reset to Geneva 10pt normal

  GetFNum("\pGeneva",&fontNum);
  TextFont(fontNum);
  TextSize(10);
  TextFace(normal);

  // ....... erase a rectangle, get a string, and use TETextBox to draw it left justified

  SetRect(&theRect,gWindowPtr->portRect.left + 5,gWindowPtr->portRect.bottom - 55,
          gWindowPtr->portRect.left + 138,gWindowPtr->portRect.bottom - 5);
  EraseRect(&theRect);
  InsetRect(&theRect,5,5);
  GetIndString(textString,rFontsStringList,9);
  RGBForeColor(&gWhiteColour);
  TETextBox(&textString[1],textString[0],&theRect,teFlushLeft);
}

// ×××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doScrolling

void  doScrolling(void)
{
  PixPatHandle   pixpat1Hdl, pixpat2Hdl;
  Rect           theRect;
  RgnHandle      oldClipHdl, regionAHdl, regionBHdl, regionCHdl, scrollRegionHdl;
  SInt16         a;

  SetWTitle(gWindowPtr,"\pScrolling pixels");

  RGBBackColor(&gWhiteColour);
  FillRect(&(gWindowPtr->portRect),&qd.white);

  if(!(pixpat1Hdl = GetPixPat(rPixelPattern1)))
    ExitToShell();
  PenPixPat(pixpat1Hdl);
  PenSize(50,0);
  SetRect(&theRect,30,30,286,371);
  FrameRect(&theRect);
  SetRect(&theRect,315,30,571,371);
  FillCRect(&theRect,pixpat1Hdl);

  if(!(pixpat2Hdl = GetPixPat(rPixelPattern2)))
    ExitToShell();  
  BackPixPat(pixpat2Hdl);

  regionAHdl = NewRgn();
  regionBHdl = NewRgn();
  regionCHdl = NewRgn();
  SetRect(&theRect,80,30,236,371);
  RectRgn(regionAHdl,&theRect);
  SetRect(&theRect,315,30,571,371);
  RectRgn(regionBHdl,&theRect);
  UnionRgn(regionAHdl,regionBHdl,regionCHdl);

  oldClipHdl = NewRgn();
  GetClip(oldClipHdl);
  SetClip(regionCHdl);

  SetRect(&theRect,80,30,571,371);

  scrollRegionHdl = NewRgn();

  for(a=0;a<371;a++)
  {
    ScrollRect(&theRect,0,1,scrollRegionHdl);
    theRect.top ++;
  }

  SetRect(&theRect,80,30,571,371);
  BackPixPat(pixpat1Hdl);

  for(a=0;a<371;a++)
  {
    ScrollRect(&theRect,0,-1,scrollRegionHdl);
    theRect.bottom --;
  }

  SetClip(oldClipHdl);

  DisposePixPat(pixpat1Hdl);
  DisposePixPat(pixpat2Hdl);
  DisposeRgn(oldClipHdl);
  DisposeRgn(regionAHdl);
  DisposeRgn(regionBHdl);
  DisposeRgn(regionCHdl);
  DisposeRgn(scrollRegionHdl);
}

// ××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doBooleanSourceModes

void  doBooleanSourceModes(void)
{
  Rect    theRect;
  Handle  destIconHdl, sourceIconHdl;
  SInt16  a, b;
  UInt32  finalTicks;
  BitMap  sourceIconMap;
  Str255  sourceString;

  SetWTitle(gWindowPtr,"\pBoolean source modes");

  RGBForeColor(&gBlackColour);
  RGBBackColor(&gGreenColour);
  FillRect(&gWindowPtr->portRect,&qd.white);
  SetRect(&theRect,gWindowPtr->portRect.left,gWindowPtr->portRect.top,
          gWindowPtr->portRect.right,(gWindowPtr->portRect.bottom - 
          gWindowPtr->portRect.top) / 2);
  RGBBackColor(&gWhiteColour);
  FillRect(&theRect,&qd.white);
  
  destIconHdl = GetIcon(rDestinationIcon);
  sourceIconHdl = GetIcon(rSourceIcon);

  for(a=0;a<2;a++)
  {
    if(a == 1)
    {
      RGBForeColor(&gYellowColour);
      RGBBackColor(&gRedColour);
    }

    SetRect(&theRect,235,a * 191 + 30,299,a * 191 + 94);
    PlotIcon(&theRect,destIconHdl);
    MoveTo(235,a * 191 + 27);
    DrawString("\pDestination");

    SetRect(&theRect,304,a * 191 + 30,368,a * 191 + 94);
    PlotIcon(&theRect,sourceIconHdl);
    MoveTo(304,a * 191 + 27);
    DrawString("\pSource");
  }

  RGBForeColor(&gBlackColour);
  RGBBackColor(&gWhiteColour);

  for(a=0;a<2;a++)
  {
    if(a == 1)
    {
      RGBForeColor(&gYellowColour);
      RGBBackColor(&gRedColour);
    }
    
    for(b=0;b<8;b++)
    {
      SetRect(&theRect,b * 69 + 28,a * 191 + 121,b * 69 + 92,a * 191 + 185);
      PlotIcon(&theRect,destIconHdl);
    }
  }

  RGBForeColor(&gBlackColour);
  RGBBackColor(&gWhiteColour);

  HLock(sourceIconHdl);
  sourceIconMap.baseAddr = *sourceIconHdl;
  sourceIconMap.rowBytes = 4;
  SetRect(&sourceIconMap.bounds,0,0,32,32);

  for(a=0;a<2;a++)
  {
    if(a == 1)
    {
      RGBForeColor(&gYellowColour);
      RGBBackColor(&gRedColour);
    }
    
    for(b=0;b<8;b++)
    {
      Delay(30,&finalTicks);
      SetRect(&theRect,b * 69 + 28,a * 191 + 121,b * 69 + 92,a * 191 + 185);
      CopyBits(&sourceIconMap,&qd.thePort->portBits,&sourceIconMap.bounds,&theRect,
               b,NULL);
      GetIndString(sourceString,rBooleanStringList,b + 1);
      MoveTo(b * 69 + 28,a * 191 + 118);
      DrawString(sourceString);
    }
  }

  HUnlock(sourceIconHdl);
}

// ×××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doArithmeticSourceModes

void  doArithmeticSourceModes(void)
{
  PicHandle  sourceHdl, destinationHdl;
  Rect       sourceRect, destRect;
  SInt16     a, b, arithmeticMode = 32;
  Str255     modeString;
  UInt32     finalTicks;

  SetWTitle(gWindowPtr,"\pCopyBits with arithmetic source modes");

  RGBForeColor(&gBlackColour);
  RGBBackColor(&gWhiteColour);
  FillRect(&(gWindowPtr->portRect),&qd.white);

  if(!(sourceHdl = GetPicture(rPicture)))
    ExitToShell();
  SetRect(&sourceRect,44,21,201,133);
  HNoPurge((Handle) sourceHdl);
  DrawPicture(sourceHdl,&sourceRect);
  HPurge((Handle) sourceHdl);
  MoveTo(44,19);
  DrawString("\pSOURCE IMAGE");

  if(!(destinationHdl = GetPicture(rPicture + 1)))
    ExitToShell();
  HNoPurge((Handle) destinationHdl);
  for(a=44;a<403;a+=179)
  {
    for(b=21;b<274;b+=126)
    {
      if(a == 44 && b == 21)
       continue;
      SetRect(&destRect,a,b,a+157,b+112);
      DrawPicture(destinationHdl,&destRect);
    }
  }
  HPurge((Handle) destinationHdl);

  for(a=44;a<403;a+=179)
  {
    for(b=21;b<274;b+=126)
    {
      if(a == 44 && b == 21)
       continue;
    
      Delay(60,&finalTicks);

      GetIndString(modeString,rArithmeticStringList,arithmeticMode - 31);
      MoveTo(a,b - 2);
      DrawString(modeString);

      SetRect(&destRect,a,b,a+157,b+112);

      CopyBits(&((GrafPtr) gWindowPtr)->portBits,
               &((GrafPtr) gWindowPtr)->portBits,
               &sourceRect,&destRect,
               arithmeticMode + ditherCopy,NULL);

      arithmeticMode ++;
    }
  }
  
  ReleaseResource((Handle) sourceHdl);
  ReleaseResource((Handle) destinationHdl);  
}

// ××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doHighlighting

void  doHighlighting(void)
{
  RGBColor   oldHighlightColour;
  SInt16     a;
  Rect       theRect;
  UInt8      hiliteVal;
  UInt32     finalTicks;

  SetWTitle(gWindowPtr,"\pHighlighting");

  RGBForeColor(&gBlackColour);
  RGBBackColor(&gWhiteColour);
  FillRect(&(gWindowPtr->portRect),&qd.white);

  LMGetHiliteRGB(&oldHighlightColour);

  for(a=0;a<3;a++)
  {
    MoveTo(50,a * 100 + 60);
    DrawString("\pClearing the highlight bit and calling InvertRect.");
    Delay(60,&finalTicks);
    SetRect(&theRect,44,a * 100 + 44,557,a * 100 + 104);

    hiliteVal = LMGetHiliteMode();
    BitClr(&hiliteVal,pHiliteBit);
    LMSetHiliteMode(hiliteVal);

    if(a == 1)
      HiliteColor(&gYellowColour);
    else if(a == 2)
      HiliteColor(&gGreenColour);

    InvertRect(&theRect);

    MoveTo(50,a * 100 + 75);
    Delay(60,&finalTicks);
    DrawString("\pClick mouse to unhighlight.  ");
    DrawString("\p(Note:  The call to InvertRect reset the highlight bit ...");

    while(!Button()) ;

    MoveTo(45,a * 100 + 90);
    DrawString("\p... so we clear the highlight bit again before calling InvertRect.)");
    Delay(60,&finalTicks);

    LMSetHiliteMode(hiliteVal);

    InvertRect(&theRect);  
  }

  HiliteColor(&oldHighlightColour);

  Delay(60,&finalTicks);
  MoveTo(50,350);
  DrawString("\pOriginal highlight colour has been reset.");
}

// ×××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doDrawWithMouse

void  doDrawWithMouse(void)
{
   PixPatHandle  pixpatHdl;
  Point          initialMouse, previousMouse, currentMouse;
  Rect           drawRect;
  UInt16         randomNumber;
  RGBColor       theColour;
     
  RGBBackColor(&gWhiteColour);
  FillRect(&gWindowPtr->portRect,&qd.white);

  if(!(pixpatHdl = GetPixPat(rPixelPattern3)))
    ExitToShell();
  PenPixPat(pixpatHdl);
  PenSize(1,1);
  PenMode(patXor);

  GetMouse(&initialMouse);                     
  drawRect.left = drawRect.right  = initialMouse.h;
  drawRect.top  = drawRect.bottom = initialMouse.v;

  GetMouse(&previousMouse);

  while(StillDown())
  {
    GetMouse(¤tMouse);

    if(currentMouse.v != previousMouse.v || currentMouse.h != previousMouse.h)
    {
      FrameRect(&drawRect);

      if(currentMouse.h >= initialMouse.h)
        drawRect.right = currentMouse.h;
      if(currentMouse.v >= initialMouse.v)
        drawRect.bottom = currentMouse.v;
      if(currentMouse.h <= initialMouse.h)
        drawRect.left = currentMouse.h;
      if(currentMouse.v <= initialMouse.v)
        drawRect.top = currentMouse.v;
      
      FrameRect(&drawRect);
    }

    previousMouse.v = currentMouse.v;
    previousMouse.h = currentMouse.h;
  }

  FrameRect(&drawRect);

  theColour.red   = doRandomNumber(0,65535);
  theColour.green = doRandomNumber(0,65535);
  theColour.blue  = doRandomNumber(0,65535);
  RGBForeColor(&theColour);

  PenMode(patCopy);
  PenPat(&qd.black);
  BackPixPat(pixpatHdl);

  randomNumber = doRandomNumber(0,4);
  
  if(randomNumber == 0)
    PaintRect(&drawRect);
  else if(randomNumber == 1)
    EraseRoundRect(&drawRect,50,50);  
  else if(randomNumber == 2)
    PaintOval(&drawRect);  
  else if(randomNumber == 3)
    PaintArc(&drawRect,0,doRandomNumber(0,360));  

  BackPat(&qd.white);
}      

// ×××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doDrawingState

void  doDrawingState(void)
{
  ThemeDrawingState   themeDrawingState;
  drawingState        portDrawingState;
  Rect                theRect;
  SInt16              a;
  UInt32              finalTicks;
  
  RGBBackColor(&gBlueColour);
  FillRect(&gWindowPtr->portRect,&qd.white);
  SetWTitle(gWindowPtr,"\pSaving and restoring the graphics port drawing state");

#if TARGET_CPU_PPC
  if(gMacOS85Present)
    NormalizeThemeDrawingState();
  else
    doNormalizeDrawingState();
#else
    doNormalizeDrawingState();
#endif

  doDrawingStateProof(0);
  Delay(120,&finalTicks);

#if TARGET_CPU_PPC
  if(gMacOS85Present)
    GetThemeDrawingState(&themeDrawingState);
  else
    doGetDrawingState(&portDrawingState);
#else
    doGetDrawingState(&portDrawingState);
#endif

  theRect = gWindowPtr->portRect;
  theRect.right -= 300;

  SetThemeBackground(kThemeBrushListViewBackground,gPixelDepth,gIsColourDevice);
  EraseRect(&theRect);

  theRect.left += 150;
  
  SetThemeBackground(kThemeBrushListViewSortColumnBackground,gPixelDepth,gIsColourDevice);
  EraseRect(&theRect);
  
  SetThemePen(kThemeBrushListViewSeparator,gPixelDepth,gIsColourDevice);

  theRect.left -= 150;
  for(a=theRect.top;a<=theRect.bottom;a+=18)
  {
    MoveTo(theRect.left,a);
    LineTo(theRect.right - 1,a);
  }

  Delay(120,&finalTicks);  
  doDrawingStateProof(1);
  Delay(120,&finalTicks);  

#if TARGET_CPU_PPC
  if(gMacOS85Present)
    SetThemeDrawingState(themeDrawingState,true);
  else
    doSetDrawingState(&portDrawingState);
#else
    doSetDrawingState(&portDrawingState);
#endif

  doDrawingStateProof(2);
}

// ××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doGetDrawingState

void  doGetDrawingState(drawingState *portDrawingState)
{
  GrafPtr  currentPort;
  
  GetPort(¤tPort);
  
  GetPenState(&portDrawingState->penLocSizeModePat);
  GetForeColor(&portDrawingState->requestedForeColour);
  GetBackColor(&portDrawingState->requestedBackColour);
  portDrawingState->textTransferMode  = currentPort->txMode;

  portDrawingState->penPixelPattern  = NULL;
  portDrawingState->backPixelPattern  = NULL;
          
  if((**((CGrafPtr) currentPort)->pnPixPat).patType != 0)
    portDrawingState->penPixelPattern = ((CGrafPtr) currentPort)->pnPixPat;
          
  if((**((CGrafPtr) currentPort)->bkPixPat).patType != 0)
    portDrawingState->backPixelPattern = ((CGrafPtr) currentPort)->bkPixPat;
  else
    portDrawingState->backBitPattern = 
                         *(PatPtr) (*(**((CGrafPtr) currentPort)->bkPixPat).patData);
}

// ××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doSetDrawingState

void  doSetDrawingState(drawingState *portDrawingState)
{
  GrafPtr  currentPort;
  
  GetPort(¤tPort);

  SetPenState(&portDrawingState->penLocSizeModePat);
  RGBForeColor(&portDrawingState->requestedForeColour);
  RGBBackColor(&portDrawingState->requestedBackColour);
  TextMode(portDrawingState->textTransferMode);

  if(portDrawingState->penPixelPattern)
    PenPixPat(portDrawingState->penPixelPattern);

  if(portDrawingState->backPixelPattern)
    BackPixPat(portDrawingState->backPixelPattern);
  else
    BackPat(&portDrawingState->backBitPattern);
}

// ××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doNormalizeDrawingState

void  doNormalizeDrawingState()
{
  PenNormal();
  RGBForeColor(&gBlackColour);
  RGBBackColor(&gWhiteColour);
  TextMode(srcOr);
  BackPat(&qd.white);
}

// ××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doDrawingStateProof

void  doDrawingStateProof(SInt16 phase)
{
  Rect    theRect;
  
  MoveTo(324,phase * 117 + 41);
  if(phase == 0)
    DrawString("\pBefore calls to SetThemePen and SetThemeBackground");
  else if(phase == 1)
    DrawString("\pAfter calls to SetThemePen and SetThemeBackground");
  else if(phase == 2)
    DrawString("\pAfter restoration of graphics port drawing state");

  MoveTo(324,phase * 117 + 54);
  DrawString("\pPen pattern/colour");
  MoveTo(462,phase * 117 + 54);
  DrawString("\pBackgrd pattern/colour");

  SetRect(&theRect,324,phase * 117 + 58,438,phase * 117 + 132);    
  PaintRect(&theRect);
  SetRect(&theRect,462,phase * 117 + 58,576,phase * 117 + 132);    
  EraseRect(&theRect);  
}

// ×××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doGetDepthAndDevice

void doGetDepthAndDevice(void)
{
  GDHandle  deviceHdl;

  deviceHdl = LMGetMainDevice();
  gPixelDepth = (*(*deviceHdl)->gdPMap)->pixelSize;
  if(BitTst(&(*deviceHdl)->gdFlags,gdDevType))
    gIsColourDevice = true;
}

// ××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doRandomNumber

UInt16  doRandomNumber(UInt16 minimum, UInt16 maximum)
{
  UInt16  randomNumber;
  SInt32  range, t;

  randomNumber = Random();
  range = maximum - minimum;
  t = (randomNumber * range) / 65535;
  return(t + minimum);
}

// ××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××

Demonstration Program Comments

When this program is run, the user should choose items from the Demonstration menu and
click the mouse button when instructed to do so by the advisory text in the window's
title bar.

#define

In addition to the usual constants relating to menus and the window, constants are
established for pixel pattern, icon, string list, and picture resource IDs.

#typedef

A variable of type drawingState will be used in the function doDrawingState to save
and restore the drawing state on either side of calls to the Appearance Manager 
functions SetThemeBackground and SetThemePen.  (These functions change the pen and 
background colours or patterns.)

Global Variables

gMacOS85Present will be set to true if Mac OS 8.5 (Appearance Manager 1.1) or later
is present.  gDone will be set to true when the user selects Quit from the File menu, 
thus causing program termination.  gWindowPtr will be assigned the pointer to the main 
window's colour graphics port. gDrawWithMouseActivated will be set to true when the Draw
With Mouse item is chosen from the Demonstration menu, and to false when other items are
chosen.

gPixelDepth will be assigned the pixel depth of the main device.  gIsColourDevice will
be assigned true if the graphics device is a colour device and false if it is a
monochrome device.  The values in these two variables are required by the Appearance
Manager functions SetThemeBackground and SetThemePen.

The fields of the RGBColor global variables are assigned values representing the colours
described by the variable names.

main

Random numbers are used by various application-defined functions in the demonstration. 
The call to GetDateTime seeds the random number generator.  randSeed is a QuickDraw
global variable which holds the seed value for the random number generator.  Unless
randSeed is modified, the same sequence of numbers will be generated each time the
program is run.  Calling GetDateTime is one way to seed the generator.  The parameter to
the GetDateTime call receives the number of seconds since midnight, January 1, 1904, a
value that is bound to be different each time the program is run.

Note that error handling in main(), as in other areas of the program, is somewhat
rudimentary in that the program simply terminates.

doEvents

Within the mouseDown case, at the inContent case, if the mouseDown is within the content
region of the window when it is the front window and gDrawWithMouseActivated is true,
the application-defined function doDrawWithMouse is called.

doDemonstrationMenu

doDemonstrationMenu switches according to the user's choices in the Demonstration menu. 
In all but the iDrawWithMouse case, the only action taken is to call the relevant
application-defined function.

Note that the global variable gDrawWithMouseActivated is set to false at function entry,
and is set to true within the iDrawWithMouse case (which executes if the user chooses
the Draw With Mouse item).  Also note that the window's background is filled with the
white colour, using the white pattern, within this case.

doLines

doLines demonstrates line drawing using colours, bit patterns, pixel patterns, and with
the Boolean pattern mode patXor.  doLines also demonstrates modifying the colour
graphics port's clipping region so as to clip drawing to that modified region.

The first line sets the graphics pen's size, pattern, and pattern mode to the defaults. 
The next two lines fill the window's content area with blue.

The next block sets the window's clipping region to a rectangle 10 pixels inside the
port rectangle.  The first two lines define such a rectangle.  The next two lines save
the current clipping region for later restoration.  The call to ClipRect establishes the
new clipping region, in effect assigning it to the colour graphics port's clipRgn field.

Lines Drawn With Foreground Colour And Black Pen Pattern

After the window title is set, FillRect is called with the white pattern while the
background colour is set to white.  This fill is clipped to the current clipping region,
which is a rectangle 10 pixels inside the port rectangle.

Within the for loop, random numbers between 0 and the width of the port rectangle are
assigned to two variables which will be used to specify the starting and finishing
horizontal coordinates for each of 60 drawn lines.  The fields of an RGBColor variable
are also assigned random values, this time between 0 and 65534 (one less than the
maximum possible value for a UInt16).  The call to RGBColor assigns this random colour
as the requested foreground colour.  The pen width is increased by two pixels.  Finally,
the call to MoveTo moves the pen to the random horizontal location at the top of the
port rectangle, and the call to LineTo draws a line to the random horizontal location at
the bottom of the port rectangle.  The line drawing is clipped to the current clipping
region.

Lines Drawn With System-Supplied Bit Patterns

This line drawing operation is similar to the previous one except that a system-supplied
bit pattern is assigned to the graphics pen and the lines are drawn from left to right
rather than top to bottom.  The bit patterns are loaded by the call to GetIndPattern and
are drawn from the 38 patterns in the 'PAT#' resource in the System file with resource
ID sysPatListID (0).  The call to PenPat assigns the specified bit pattern to the
graphics pen.  In this operation, the height of the pen, rather than the width is
increased by two each time around the for loop.

Lines Drawn With A Pixel Pattern

In this line drawing operation, before the for loop is entered, GetPixPat is called to
allocate a PixPat structure and initialise it with information from the specified 'ppat'
resource.  The call to PenPixPat then assigns this pixel pattern to the graphics pen.

After the last line is drawn, DisposePixPat is called to free the memory obtained by the
GetPixPat call.

At this point, the clipping region saved at the start of the function is restored, and
all of the memory obtained by the NewRgn call is freed.

Lines Drawn With Pattern Mode patXor

This block demonstrates a well-known but nonetheless exotic capability of the humble
line when it operates in the pattern mode patXor.

The content area is filled with red, following which the pen size and pen pattern are
set to the defaults.  The call to PenMode sets the pen mode to patXor  The next four
lines assign values to four variables which will be used to ensure that the starting and
ending locations of each drawn line will be ten pixels inside the port rectangle. The
for loops, proceeding clockwise, draw lines from points 10 pixels inside the periphery
of the port rectangle through the centre of the rectangle to points on the opposite side
of the rectangle.  The effect of patXor on any destination pixel is to invert it.  For
example, assuming a white background and black pen colour, any white pixel in the path
of the drawn lines will be turned black and any black pixel will be turned white.  This
produces a pattern known as a moire (watered silk) pattern.

doFrameAndPaint

doFrameAndPaint demonstrates the use of QuickDraw's framing and painting functions with
the exception of those relating to polygons and regions.  

At the first two lines, the pen pattern and mode are set to the defaults and the pen
size is set to 30 pixels wide and 20 pixels high.

The for loop is traversed three times, once for framing and painting with a colour, once
for framing and painting with a bit pattern, and once for framing and painting with a
pixel pattern.  The first action is to fill the port rectangle with the colour white
using the white pattern.

Preparation

The first time around the loop, RGBForeColor is called to set the requested foreground
colour to red.

The second time around the loop, RGBForeColor and RGBBackColor are called to set the
requested foreground and background colours to, respectively, blue and yellow,
GetIndPattern loads one of the system-supplied bit patterns, and PenPat makes that
pattern the pen's current bit pattern.

The third time around the loop, a call to GetPixPat loads a 'ppat' resource, creating a
new PixPat structure, and a call to PenPixPat assigns that pixel pattern to the pen.

Framing and Painting

In this section, SetRect is used to assign the coordinates of a rectangle to the fields
of a Rect structure, and OffsetRect is used to move the rectangle horizontally and
vertically between the calls to the various framing and painting functions.

Before doFrameAndPaint exits, DisposePixPat is called to free the memory obtained by the
GetPixPat call.

doFillEraseInvert

doFillEraseInvert demonstrates the use of QuickDraw's filling, erasing, and inverting
functions with the exception of those relating to polygons and regions.  

At the first two lines, the pen pattern and mode are set to the defaults and the pen
size is set to 30 pixels wide and 20 pixels high.

The for loop is traversed four times, once for filling and erasing with colours, once
for filling and erasing with bit patterns, once for filling and erasing with a pixel
patterns, and once for inverting.  The first action, on the first three passes only, is
to fill the port rectangle with the colour white using the white pattern.

Preparation

The first time around the loop, RGBForeColor and RGBBackColor are called to set the
requested foreground and background colours to, respectively, blue and red.  In
addition, the calls to GetIndPattern and BackPat set the background pattern to black.

The second time around the loop, RGBForeColor and RGBBackColor are called to set the
requested foreground and background colours to, respectively, blue and yellow.  In
addition, GetIndPattern is called twice, once to assign a bit pattern to a Pattern
variable which will be passed as the second parameter in calls to FillRect, FillOval,
etc., and once, in conjunction with BackPat, to assign a bit pattern to the colour
graphics port's bkPixPat field.

The third time around the loop, GetPixPat is called twice, once to assign a pixel
pattern to a the variable which will be passed as the second parameter in calls to
FillCRect, FillCOval, etc., and once, in conjunction with BackPixPat, to assign a pixel
pattern to the colour graphics port's bkPixPat field.

The fourth time around the loop, and preparatory to calls to the erasing functions, the
call to BackPat sets the background pattern to white.  (The calls to SetRect and
EraseRect simply erase the existing text in the window.)

Filling, Erasing, and Inverting

In this section, SetRect is used to assign the coordinates of a rectangle to the fields
of a Rect structure, and OffsetRect is used to move the rectangle horizontally and
vertically between the calls to the various filling, erasing, and inverting functions.

Before doFillEraseInvert exits, DisposePixPat is called twice to free the memory
obtained by the two GetPixPat calls.

doPolygonAndRegion

doPolygonAndRegion demonstrates defining a polygon and a region and the use of some of
QuickDraw's polygon and region framing, painting, filling, and erasing functions.

Preparation

The calls to GetIndPattern and BackPat set the background pattern to one on the
system-supplied bit patterns.  The call to GetPixPat gets the pixel pattern to be used
by the filling functions.  The calls to RGBForeColor and RGBBackColor set the requested
foreground and background colours.  PenNormal sets the pen's size, pattern mode, and
pattern to the defaults.

The OpenPoly call initiates the recording of the polygon definition, the MoveTo and
LineTo calls define the polygon, and ClosePoly stops the recording.  Note that, in this
demonstration, the last vertex is not joined to the first vertex.

The NewRgn call allocates memory for a new region and a region pointer, initialises the
contents of the region and make it an empty rectangle.  OpenRgn initiates the recording
of a region shape.  The next seven lines create a region definition comprising two
rectangles and an overlapping oval.  CloseRgn terminates the recording.

Framing, Painting, Filling, And Erasing

In this section, OffsetPoly and OffsetRgn are used to move the polygon and region
horizontally between the calls to the framing, filling, and erasing functions. 
OffsetPoly modifies the polygon's definition.  OffsetRgn adjusts the coordinates of the
region.

Before doPolygonAndRegion exits, KillPoly is called to free all the memory obtained by
OpenPoly, DisposeRgn is called to free all the memory obtained by NewRgn, DisposePixPat
is called to free all the memory obtained by GetPixPat, and the background pattern is
set to white.
doText

doText draws text in various fonts, sizes and styles.  In addition, the last block
demonstrates drawing justified text within a specified rectangle using the TextEdit
function TETextBox.

Prior to the for loop, the variable windowCentre is assigned a value which represents a
location midway across the port rectangle, and the right half of the content area is
filled with blue.

Within the first section of the for loop, the text font is changed using GetFNum and
TextFont, the text style is changed using TextFace, and the foreground colour is
changed.  At the last two sections within the loop, the text size is changed using
TextSize, a string is retrieved from a 'STR#' resource, the width of the string in
pixels is determined, and the string is drawn centred laterally in the window.

After the loop exits, the text font, size and style are returned to Geneva 10pt plain.

At the final block, a small rectangle is defined at the bottom left of the content area. 
Because the current background colour is blue, the call to EraseRect erases the
rectangle in that colour.  The rectangle is then inset by five pixels all round.  A
string is then loaded from a 'STR#' resource and the foreground colour is set to white. 
Finally, TETextBox is called to draw the text within the specified rectangle with left
justification.  (Other available justification constants are teFlushRight and 
teCenter.)

doScrolling

doScrolling demonstrates scrolling pixels within a specified rectangle, with the
operation clipped to a region comprising two unconnected rectangular areas.

The first call to GetPixPat loads a 'ppat' resource.  The call to PenPixPat assigns that
pixel pattern to the pen, which is then made 50 pixels wide and zero pixels high.  A
framed rectangle is then drawn in the left half of the window.  (Note that, because the
pen height is set to zero, the two sides of the rectangle will be drawn but not the top
and bottom.)  A filled rectangle is then drawn in the right side of the window using the
same pixel pattern.

In the next block, another 'ppat' resource is retrieved.  The call to BackPixPat makes
this pixel pattern the background pixel pattern.

The next block creates a region comprising two separate rectangles, the first one
coincident with the "inside" of the framed rectangle and the second one coincident with
the whole of the filled rectangle).  The current clipping region is then saved and the
newly created region is established as the current clipping region.

The following call to SetRect defines a rectangle for the first parameter of the
ScrollRect function.  Laterally, this extends from the left inside of the framed
rectangle to the right hand side of the filled rectangle.  The call to NewRgn then
creates the empty region required by the ScrollRect calls.

In the first for loop, the pixels within the clipping region within the specified
rectangle are scrolled downwards, the top of the rectangle being incremented downwards
between calls to ScrollRect.  ScrollRect fills the "vacated" areas with the background
pattern .

Between the for loops, the rectangle used by ScrollRect is redefined and the background
pixel pattern is changed to the pixel pattern used to draw the original rectangles.  
The scrolling operation is then repeated, this time in an upwards direction.

Before doScrolling exits, the saved clipping region is restored and all the memory
obtained by the GetPixPat and NewRgn calls is freed.

doBooleanSourceModes

doBooleanSourceModes demonstrates the effects of the Boolean source modes in both
black-and-white and colour.

The first block fills the content area with green and then fills the top half of the
content area with white.  This block leaves the foreground colour black and the
background colour white.

The next block loads two 32 bit by 32 bit 'ICON' resources.  One icon contains the image
of a cross and the other contains the image of a square.

The first for loop calls PlotIcon four times, twice to draw the icons in the white area
at the top of the window, and twice to draw them in the green area at the bottom of the
window.  The rectangle passed in the first parameter of the PlotIcon calls expands the
icon to 64 pixels by 64 pixels.  The calls to RGBForeColor and RGBBackColor cause the
icons in the green area to be drawn using a foreground colour of yellow and a background
colour of red.  

The foreground and background colours are reset to black and white before the second for
loop is entered.

The second for loop draws the cross icon eight times across the bottom of the white half
of the window.  The foreground and background colours are then changed to yellow and red
before this process is repeated across the bottom of the green area of the window. 

The foreground and background colours are again reset to black and white.

As a preamble to what is to come, note that there is no special data type for an icon. 
It is simply 128 bytes of bit data arranged as 32 rows of 4 bytes per row.  All that is
available is a handle to that 128 bytes of data.  The intention is to cause the 128
bytes of data which constitutes the square icon to be regarded as bitmap data pointed to
by the baseAddr field of a BitMap record.  That way, the CopyBits routine can be used to
copy the bitmap into the colour graphics port.

Because CopyBits is one of those functions which can move memory around, the first
action is to lock the icon data in the heap.  The address of the square icon image data
is then assigned to the baseAddr field of a BitMap record, the rowBytes field is
assigned the value 4, and the bounds field is assigned a rectangle defining the normal
icon size.

The final for loop calls CopyBits to copy the bit image into the graphics port sixteen
times, overdrawing the previously drawn cross icons.  The call to SetRect within the
inner for loop defines the expanded destination rectangle which governs the size at
which the image will be drawn.  This rectangle is passed in the destRect parameter of
the CopyBits call.  Note that, in the CopyBits call, the value passed in the tMode
(transfer mode) parameter is incremented each time through the loop so that the square
image overdraws the cross image once in each of the eight available Boolean source
modes.  The three lines following the CopyBits call retrieve the appropriate string
containing the relevant source mode from the specified 'STR#' resource and draw this
string above each copied image.
The last line unlocks the icon image data.

doArithmeticSourceModes

doArithmeticSourceModes demonstrates the effects of the arithmetic source modes.

Since CopyBits will be called, the foreground and background colours are set to black
and white respectively.  The call to FillRect clears the window to white.

The first call to GetPicture loads a 'PICT' resource into a Picture structure.  (Since
the 'PICT' resource is purgeable, it is made non-purgeable immediately it is retrieved,
used immediately, and immediately made purgeable again.)  The call to DrawPicture draws
the picture in the top left of the window, where it is labelled as the source image.

The second call to GetPicture loads another 'PICT' resource which will be used as the
destination image.  The first for loop draws this picture in the window at eight
separate locations, these locations being determined by the rectangle passed in the
first parameter of the DrawPicture calls.

The last for loop is traversed once for each of the eight arithmetic source modes. 
CopyBits is called eight times to overdraw the destination images with the source image. 
Note that the value in the tMode (transfer mode) parameter of the CopyBits call is
incremented each time around the loop.  Note also that, each time around the loop, a new
string is retrieved from a 'STR#' resource and drawn above the destination image.

Before doArithmeticSourceModes exits, ReleaseResource is called twice to free the memory
obtained by the GetPicture calls.

doHighlighting

doHighlighting demonstrates highlighting, first with the colour set by the user in the
Colour pane of the Appearance control panel, and then with two colours set by the
program.

Firstly, the highlight colour set by the user is saved via a call to LMGetHiliteRGB.

The for loop is traversed three times.  On the second and third traverses, the highlight
colour is changed.

Within the for loop, a copy of the value at the low memory global HiliteMode is
retrieved using LMGetHiliteMode, BitClr is called to clear the highlight bit, and
LMSetHiliteMode is called to set to low memory global to this new value.  At the if/else
block, the highlight colour is changed if this is the second or third time around the
loop.  With the highlight bit cleared, InvertRect is called to invert a specified
rectangle.

Note that the call to InvertRect resets the highlight bit.  Accordingly, when the user
clicks the mouse button, the highlight bit is cleared once again before InvertRect is
called once again.  This second call restores the colour in the specified rectangle to
the background colour.

Before the doHighLighting function returns, it sets the highlight colour to the saved
highlight colour.

doDrawWithMouse

doDrawWithMouse demonstrates the use of the mouse to define bounding rectangles for
QuickDraw shape drawing functions.  It also demonstrates the implementation of the
"rubber band" rectangle commonly used to provide visual feedback to the user as he drags
the mouse during such operations.  (While the mouse button remains down, the
"rubber-band" rectangle is continually erased and redrawn as the mouse is moved.  It is
erased when the mouse button is released.)

doDrawWithMouse is called when a mouse-down occurs in the window while it is the front
window, provided that the global variable gDrawWithMouseActivated is set to true.

The call to GetPixPat loads a 'ppat' resource containing a small 8 pixel by 8 pixel
pattern.  This pixel pattern is assigned to the pen by the call to PenPixPat.  The call
to PenSize makes the pen size one pixel high by one pixel wide. The pen pattern mode is
then set to patXOr.  (Note: For a black-and-white "rubber band", replace the PenPixPat
call with PenPat(&qd.gray).)

The call to GetMouse saves the initial mouse location to a Point variable.  The contents
of the fields of this variable will remain unchanged.  Those coordinates are also used
to initialise the left and top fields of the Rect variable drawRect.

The next call to GetMouse assigns the initial location of the mouse to another Point
variable.  The contents of the fields of this variable will continually change as the
mouse is dragged.

The while loop continues to execute while the mouse button remains down.  Within the
loop, the current mouse location is retrieved and compared with the previous mouse
location (the first if statement).  If the mouse has moved:

*   FrameRect is called to draw the framed rectangle.

*   If the current mouse horizontal coordinate is greater than or equal to the initial
    horizontal mouse coordinate, the current mouse horizontal coordinate is assigned to
    the right field of the rectangle.

*   If the current mouse vertical coordinate is greater than or equal to the initial
    vertical mouse coordinate, the current mouse vertical coordinate is assigned to the
    bottom field of the rectangle.

*   If the current mouse horizontal coordinate is less than or equal to the initial
    horizontal mouse coordinate, the current mouse horizontal coordinate is assigned to
    the left field of the rectangle.

*   If the current mouse vertical coordinate is less than or equal to the initial
    vertical mouse coordinate, the current mouse vertical coordinate is assigned to the
    top field of the rectangle.

*   FrameRect is called again with the newly defined rectangle passed in.

Because the drawing mode is patXor, the first call to FrameRect erases the old
rectangle.  Because FrameRect is only called if the mouse has moved, the flicker which
would otherwise occur when the mouse is stationary is avoided.  

Below the if block, and preparatory to the next comparison of current and previous mouse
location, the current mouse location becomes the previous mouse position.

When the mouse button is released:

*   The final call to FrameRect erases the final "rubber-band" rectangle.

*   The foreground colour is set to a random colour, the pen pattern mode is set to
    patCopy, the pen pattern is set to black, and the background pixel pattern is set
    to that previously used to draw the "rubber band".

*   The rectangle as at mouse button release is used in calls to QuickDraw painting
    and erasing functions to draw rectangles, round rectangles, ovals, and arcs.  Just
    which function is called depends on the value returned by the call to 
    doRandomNumber.

*   The background pattern is set to white.

doDrawingState

doDrawingState is similar to the function doDrawListView in the demonstration 
program Appearance, the difference being that, in doDrawingState, the drawing state is 
saved at entry and restored at exit.

Note that the call to NormalizeThemeDrawingState or doNormalizeDrawingState is included 
in this function for demonstration purposes only.  Ordinarily, these would be called
(if required) at other points in an application.  If the target is the PowerPC target: 
If Mac OS 8.5 is present, NormalizeThemeDrawingState is called; otherwise the 
application-defined function doNormalizeDrawingState is called.  If the target is the 
68K target, the application-defined function doNormalizeDrawingState is called.

The call to GetThemeDrawingState or doGetDrawingState saves the drawing state prior to 
the calls to the Appearance Manager functions SetThemeBackground and SetThemePen, 
which, depending on the current appearance, will change either the colour or the 
pattern in the relevant fields of the colour graphics port. If the target is the 
PowerPC target: If Mac OS 8.5 is present, GetThemeDrawingState is called; otherwise 
the application-defined function doGetDrawingState is called.  If the target is the 
68K target, the application-defined function doGetDrawingState is called.

The call to SetThemeDrawingState or doSetDrawingState restores the saved drawing state.

The intervening code simply draws an Appearance-compliant list view in the left half 
of the window.

The calls to doDrawingStateProof are also for demonstration purposes only.  As will be 
seen, this function simply draws rectangles in the right half of the window in the pen 
and background colours and patterns as they were after the call to 
NormalizeThemeDrawingState/doNormalizeDrawingState, after the calls to the Appearance 
Manager functions, and after the call to SetThemeDrawingState/doSetDrawingState.

doGetDrawingState

doGetDrawingState saves the current drawing state to a variable of type 
drawingState.

The call to GetPort assigns a pointer to the current port to the variable currentPort.

GetPenState saves the current pen location, size, pattern mode, and pattern to the 
penLocSizeModePat field of the drawingState structure.  GetForeColor and GetBackColor 
save the current foreground and background colours.  The next line saves the text 
source mode.

At the next two lines, the fields of the drawingState structure relating to the pen 
and background pixel patterns are initialised to NULL.

The patType field of the PixPat structure whose handle resides in the pnPixPat field 
of the colour graphics port will contain 0 if the pattern is a bit pattern and 1 if it 
is a pixel pattern.  If it is a pixel pattern, the handle to the PixPat structure is 
saved.

If the patType field of the PixPat structure whose handle resides in the bkPixPat 
field of the colour graphics port indicates that the pattern is a pixel pattern, the 
handle to the PixPat structure is saved.  If the pattern is a bit pattern, a pointer 
to the pattern data is saved.

doSetDrawingState

doSetDrawingState restores the saved drawing state.

The first four calls restore the saved pen location, size, pattern mode, and bit 
pattern, the requested foreground and background colours, and the text source mode.

If the penPixelPattern field of the drawingState structure does not contain NULL, the 
pen pixel pattern is restored, overriding the effect of the pattern aspect of the 
previous call to SetPenState.

If the backPixelPattern field of the drawingState structure does not contain NULL, the 
background pixel pattern is restored, otherwise the background bit pattern is restored.

doNormalizeDrawingState

doNormalizeDrawingState shows how you might normalise the drawing state.  It sets 
the pen size to (1,1), the pen pattern mode to patCopy, and the pen pattern to black. 
 It also sets the foreground and background colours to black and white respectively, 
 the text source mode to srcOr and the background pattern to white.

doDrawingStateProof

ddoDrawingStateProof is called by doDrawingState to draw rectangles in the right 
half of the window in the pen and background colours and patterns as they were after 
the call to NormalizeThemeDrawingState/doNormalizeDrawingState, after the calls to 
the Appearance Manager functions, and after the call to 
SetThemeDrawingState/doSetDrawingState.  Note that the colour or pattern in which the 
second pair of rectangles is drawn will depend on the current appearance.

doGetDepthAndDevice and doRandomNumber

doGetDepthAndDevice and doRandomNumber are incidental to the demonstration. 

doGetDepthAndDevice gets the pixel depth of the main device, and whether the device is a
colour device or a monochrome device, for the Appearance Manager functions
SetThemeBackground and SetThemePen.  doRandomNumber returns a random number between the
specified minimum value and the specified maximum value minus one.

 

Community Search:
MacTech Search:

Software Updates via MacUpdate

Latest Forum Discussions

See All

Make the passage of time your plaything...
While some of us are still waiting for a chance to get our hands on Ash Prime - yes, don’t remind me I could currently buy him this month I’m barely hanging on - Digital Extremes has announced its next anticipated Prime Form for Warframe. Starting... | Read more »
If you can find it and fit through the d...
The holy trinity of amazing company names have come together, to release their equally amazing and adorable mobile game, Hamster Inn. Published by HyperBeard Games, and co-developed by Mum Not Proud and Little Sasquatch Studios, it's time to... | Read more »
Amikin Survival opens for pre-orders on...
Join me on the wonderful trip down the inspiration rabbit hole; much as Palworld seemingly “borrowed” many aspects from the hit Pokemon franchise, it is time for the heavily armed animal survival to also spawn some illegitimate children as Helio... | Read more »
PUBG Mobile teams up with global phenome...
Since launching in 2019, SpyxFamily has exploded to damn near catastrophic popularity, so it was only a matter of time before a mobile game snapped up a collaboration. Enter PUBG Mobile. Until May 12th, players will be able to collect a host of... | Read more »
Embark into the frozen tundra of certain...
Chucklefish, developers of hit action-adventure sandbox game Starbound and owner of one of the cutest logos in gaming, has released their roguelike deck-builder Wildfrost. Created alongside developers Gaziter and Deadpan Games, Wildfrost will... | Read more »
MoreFun Studios has announced Season 4,...
Tension has escalated in the ever-volatile world of Arena Breakout, as your old pal Randall Fisher and bosses Fred and Perrero continue to lob insults and explosives at each other, bringing us to a new phase of warfare. Season 4, Into The Fog of... | Read more »
Top Mobile Game Discounts
Every day, we pick out a curated list of the best mobile discounts on the App Store and post them here. This list won't be comprehensive, but it every game on it is recommended. Feel free to check out the coverage we did on them in the links below... | Read more »
Marvel Future Fight celebrates nine year...
Announced alongside an advertising image I can only assume was aimed squarely at myself with the prominent Deadpool and Odin featured on it, Netmarble has revealed their celebrations for the 9th anniversary of Marvel Future Fight. The Countdown... | Read more »
HoYoFair 2024 prepares to showcase over...
To say Genshin Impact took the world by storm when it was released would be an understatement. However, I think the most surprising part of the launch was just how much further it went than gaming. There have been concerts, art shows, massive... | Read more »
Explore some of BBCs' most iconic s...
Despite your personal opinion on the BBC at a managerial level, it is undeniable that it has overseen some fantastic British shows in the past, and now thanks to a partnership with Roblox, players will be able to interact with some of these... | Read more »

Price Scanner via MacPrices.net

You can save $300-$480 on a 14-inch M3 Pro/Ma...
Apple has 14″ M3 Pro and M3 Max MacBook Pros in stock today and available, Certified Refurbished, starting at $1699 and ranging up to $480 off MSRP. Each model features a new outer case, shipping is... Read more
24-inch M1 iMacs available at Apple starting...
Apple has clearance M1 iMacs available in their Certified Refurbished store starting at $1049 and ranging up to $300 off original MSRP. Each iMac is in like-new condition and comes with Apple’s... Read more
Walmart continues to offer $699 13-inch M1 Ma...
Walmart continues to offer new Apple 13″ M1 MacBook Airs (8GB RAM, 256GB SSD) online for $699, $300 off original MSRP, in Space Gray, Silver, and Gold colors. These are new MacBook for sale by... Read more
B&H has 13-inch M2 MacBook Airs with 16GB...
B&H Photo has 13″ MacBook Airs with M2 CPUs, 16GB of memory, and 256GB of storage in stock and on sale for $1099, $100 off Apple’s MSRP for this configuration. Free 1-2 day delivery is available... Read more
14-inch M3 MacBook Pro with 16GB of RAM avail...
Apple has the 14″ M3 MacBook Pro with 16GB of RAM and 1TB of storage, Certified Refurbished, available for $300 off MSRP. Each MacBook Pro features a new outer case, shipping is free, and an Apple 1-... Read more
Apple M2 Mac minis on sale for up to $150 off...
Amazon has Apple’s M2-powered Mac minis in stock and on sale for $100-$150 off MSRP, each including free delivery: – Mac mini M2/256GB SSD: $499, save $100 – Mac mini M2/512GB SSD: $699, save $100 –... Read more
Amazon is offering a $200 discount on 14-inch...
Amazon has 14-inch M3 MacBook Pros in stock and on sale for $200 off MSRP. Shipping is free. Note that Amazon’s stock tends to come and go: – 14″ M3 MacBook Pro (8GB RAM/512GB SSD): $1399.99, $200... Read more
Sunday Sale: 13-inch M3 MacBook Air for $999,...
Several Apple retailers have the new 13″ MacBook Air with an M3 CPU in stock and on sale today for only $999 in Midnight. These are the lowest prices currently available for new 13″ M3 MacBook Airs... Read more
Multiple Apple retailers are offering 13-inch...
Several Apple retailers have 13″ MacBook Airs with M2 CPUs in stock and on sale this weekend starting at only $849 in Space Gray, Silver, Starlight, and Midnight colors. These are the lowest prices... Read more
Roundup of Verizon’s April Apple iPhone Promo...
Verizon is offering a number of iPhone deals for the month of April. Switch, and open a new of service, and you can qualify for a free iPhone 15 or heavy monthly discounts on other models: – 128GB... Read more

Jobs Board

IN6728 Optometrist- *Apple* Valley, CA- Tar...
Date: Apr 9, 2024 Brand: Target Optical Location: Apple Valley, CA, US, 92308 **Requisition ID:** 824398 At Target Optical, we help people see and look great - and Read more
Medical Assistant - Orthopedics *Apple* Hil...
Medical Assistant - Orthopedics Apple Hill York Location: WellSpan Medical Group, York, PA Schedule: Full Time Sign-On Bonus Eligible Remote/Hybrid Regular Apply Now Read more
*Apple* Systems Administrator - JAMF - Activ...
…**Public Trust/Other Required:** None **Job Family:** Systems Administration **Skills:** Apple Platforms,Computer Servers,Jamf Pro **Experience:** 3 + years of Read more
Liquor Stock Clerk - S. *Apple* St. - Idaho...
Liquor Stock Clerk - S. Apple St. Boise Posting Begin Date: 2023/10/10 Posting End Date: 2024/10/14 Category: Retail Sub Category: Customer Service Work Type: Part Read more
Top Secret *Apple* System Admin - Insight G...
Job Description Day to Day: * Configure and maintain the client's Apple Device Management (ADM) solution. The current solution is JAMF supporting 250-500 end points, Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.