TweetFollow Us on Twitter

MACINTOSH C CARBON

Demonstration Program QuickDraw

Goto Contents

// *******************************************************************************************
// QuickDraw.c                                                             CLASSIC EVENT MODEL
// *******************************************************************************************
// 
// 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, copying, etc., operations are chosen from a Demonstration pull-down 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:
//
// o  A 'plst' resource.
//
// o  'WIND' resources for the main window, and a small window used for the CopyBits
//    demonstration (purgeable) (initially visible).
//
// o  An 'MBAR' resource and associated 'MENU' resources (preload, non-purgeable).
//
// o  Two 'ICON' resources (purgeable) used for the boolean source modes demonstration. 
//
// o  Two 'PICT' resources (purgeable) used in the arithmetic source modes demonstration.
//
// o  'STR#' resources (purgeable) containing strings used in the source modes and text
//    drawing demonstrations.
//
// o  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.
//
// o  A 'SIZE' resource with the acceptSuspendResumeEvents, canBackground, 
//    doesActivateOnFGSwitch, and isHighLevelEventAware flags set.
//
// *******************************************************************************************

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

#include <Carbon.h>

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

#define rMenubar                128
#define mAppleApplication       128
#define  iAbout                 1
#define mFile                   129
#define  iQuit                  12
#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 MAX_UINT32              0xFFFFFFFF

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

Boolean   gRunningOnX     = false;
Boolean   gDone;
WindowRef gWindowRef;
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    doPreliminaries         (void);
OSErr   quitAppEventHandler     (AppleEvent *,AppleEvent *,SInt32);
void    doEvents                (EventRecord *);
void    doDemonstrationMenu     (MenuItemIndex);
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    doDrawingStateProof     (SInt16);
void    doGetDepthAndDevice     (void);
UInt16  doRandomNumber          (UInt16,UInt16);

// ************************************************************************************** main

void  main(void)
{
  UInt32        seconds;
  MenuBarHandle menubarHdl;
  SInt32        response;
  MenuRef       menuRef;
  EventRecord   eventStructure;
  Boolean       gotEvent;    

  // ......................................................................... do prelimiaries

  doPreliminaries();

  // ............................................................ seed random number generator

  GetDateTime(&seconds);
  SetQDGlobalsRandomSeed(seconds);

  // ............................................................... set up menu bar and menus

  menubarHdl = GetNewMBar(rMenubar);
  if(menubarHdl == NULL)
    ExitToShell();
  SetMenuBar(menubarHdl);
  DrawMenuBar();

  Gestalt(gestaltMenuMgrAttr,&response);
  if(response & gestaltMenuMgrAquaLayoutMask)
  {
    menuRef = GetMenuRef(mFile);
    if(menuRef != NULL)
    {
      DeleteMenuItem(menuRef,iQuit);
      DeleteMenuItem(menuRef,iQuit - 1);
      DisableMenuItem(menuRef,0);
    }

    gRunningOnX = true;
  }

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

  if(!(gWindowRef = GetNewCWindow(rWindow,NULL,(WindowRef)-1)))
    ExitToShell();

  SetPortWindowPort(gWindowRef);
  UseThemeFont(kThemeSmallSystemFont,smSystemScript);

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

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

  gDone = false;

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

// *************************************************************************** doPreliminaries

void  doPreliminaries(void)
{
  OSErr osError;

  MoreMasterPointers(32);
  InitCursor();
  FlushEvents(everyEvent,0);

  osError = AEInstallEventHandler(kCoreEventClass,kAEQuitApplication,
                            NewAEEventHandlerUPP((AEEventHandlerProcPtr) quitAppEventHandler),
                            0L,false);
  if(osError != noErr)
    ExitToShell();  
}

// **************************************************************************** doQuitAppEvent

OSErr  quitAppEventHandler(AppleEvent *appEvent,AppleEvent *reply,SInt32 handlerRefcon)
{
  OSErr    osError;
  DescType returnedType;
  Size     actualSize;

  osError = AEGetAttributePtr(appEvent,keyMissedKeywordAttr,typeWildCard,&returnedType,NULL,0,
                              &actualSize);

  if(osError == errAEDescNotFound)
  {
    gDone = true;
    osError = noErr;
  } 
  else if(osError == noErr)
    osError = errAEParamMissed;

  return osError;
}

// ********************************************************************************** doEvents

void  doEvents(EventRecord *eventStrucPtr)
{
  SInt32          menuChoice;
  MenuID          menuID;
  MenuItemIndex   menuItem;
  WindowPartCode  partCode;
  WindowRef       windowRef;
  
  switch(eventStrucPtr->what)
  {
    case kHighLevelEvent:
      AEProcessAppleEvent(eventStrucPtr);
      break;

    case keyDown:
      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,&windowRef))
      {
        switch(partCode)
        {
          case inMenuBar:
            menuChoice = MenuSelect(eventStrucPtr->where);
            menuID = HiWord(menuChoice);
            menuItem = LoWord(menuChoice);

            if(menuID == 0)
              return;

            switch(menuID)
            {
              case mAppleApplication:
                if(menuItem == iAbout)
                  SysBeep(10);
                break;

              case mFile:
                if(menuItem == iQuit)
                  gDone = true;
                break;
                
              case mDemonstration:
                doDemonstrationMenu(menuItem);
                break;
            }
            break;

          case inDrag:
            DragWindow(windowRef,eventStrucPtr->where,NULL);
            break;

          case inContent:
            if(windowRef != FrontWindow())
              SelectWindow(windowRef);
            else
              if(gDrawWithMouseActivated)
                doDrawWithMouse();
            break;
        }
      }
      break;

    case updateEvt:
      windowRef = (WindowRef) eventStrucPtr->message;
      BeginUpdate(windowRef);
      EndUpdate(windowRef);
      break;
  }
}

// *********************************************************************** doDemonstrationMenu

void  doDemonstrationMenu(MenuItemIndex menuItem)
{
  Rect    portRect;
  Pattern whitePattern;
  
  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(gWindowRef,"\pDrawing with the mouse");
      RGBBackColor(&gWhiteColour);
      GetWindowPortBounds(gWindowRef,&portRect);
      FillRect(&portRect,GetQDGlobalsWhite(&whitePattern));
      gDrawWithMouseActivated = true;
      break;

    case iDrawingState:
      doDrawingState();
      break;
  }

  HiliteMenu(0);
}

// *********************************************************************************** doLines

void  doLines(void)
{
  Rect         portRect, newClipRect;
  Pattern      whitePattern, systemPattern, blackPattern;
  RgnHandle    oldClipRgn;
  SInt16       a, b, c;
  RGBColor     theColour;
  UInt32       finalTicks;
  PixPatHandle pixpatHdl;  

  PenNormal();

  RGBBackColor(&gBlueColour);
  GetWindowPortBounds(gWindowRef,&portRect);
  FillRect(&portRect,GetQDGlobalsWhite(&whitePattern));

  newClipRect = portRect;
  InsetRect(&newClipRect,10,10);
  oldClipRgn = NewRgn();
  GetClip(oldClipRgn);
  ClipRect(&newClipRect);

  // ................................ lines drawn with foreground colour and black pen pattern

  SetWTitle(gWindowRef,"\pDrawing lines with colours");
  RGBBackColor(&gWhiteColour);
  FillRect(&portRect,&whitePattern);

  if(!gRunningOnX)
    SetThemeCursor(kThemeWatchCursor);

  for(a=1;a<60;a++)
  {
    b = doRandomNumber(0,portRect.right - portRect.left);
    c = doRandomNumber(0,portRect.right - 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,portRect.top);
    LineTo(c,portRect.bottom);

    QDFlushPortBuffer(GetWindowPort(FrontWindow()),NULL);
    Delay(2,&finalTicks);
  }

  if(!gRunningOnX)
    SetThemeCursor(kThemeArrowCursor);

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

  SetWTitle(gWindowRef,"\pClick mouse for more lines");
  QDFlushPortBuffer(GetWindowPort(FrontWindow()),NULL);
  while(!Button()) ;  
  SetWTitle(gWindowRef,"\pDrawing lines with system-supplied bit patterns");
  FillRect(&portRect,&whitePattern);

  if(!gRunningOnX)
    SetThemeCursor(kThemeWatchCursor);

  for(a=1;a<39;a++)
  {
    b = doRandomNumber(0,portRect.bottom - portRect.top);
    c = doRandomNumber(0,portRect.bottom - 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(portRect.left,b);
    LineTo(portRect.right,c);

    QDFlushPortBuffer(GetWindowPort(FrontWindow()),NULL);
    Delay(5,&finalTicks);
  }

  if(!gRunningOnX)
    SetThemeCursor(kThemeArrowCursor);

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

  SetWTitle(gWindowRef,"\pClick mouse for more lines");
  QDFlushPortBuffer(GetWindowPort(FrontWindow()),NULL);
  while(!Button()) ;  
  SetWTitle(gWindowRef,"\pDrawing lines with a pixel pattern");
  FillRect(&portRect,&whitePattern);

  if(!gRunningOnX)
    SetThemeCursor(kThemeWatchCursor);

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


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

    PenSize(a * 2,1);    

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

    QDFlushPortBuffer(GetWindowPort(FrontWindow()),NULL);
    Delay(5,&finalTicks);
  }

  DisposePixPat(pixpatHdl);

  SetClip(oldClipRgn);
  DisposeRgn(oldClipRgn);

  if(!gRunningOnX)
    SetThemeCursor(kThemeArrowCursor);

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

  SetWTitle(gWindowRef,"\pClick mouse for more lines");
  QDFlushPortBuffer(GetWindowPort(FrontWindow()),NULL);
  while(!Button()) ;
  SetWTitle(gWindowRef,"\pDrawing lines using pattern mode patXor");

  if(!gRunningOnX)
    SetThemeCursor(kThemeWatchCursor);

  RGBBackColor(&gRedColour);
  FillRect(&portRect,&whitePattern);

  PenSize(1,1);    
  PenPat(GetQDGlobalsBlack(&blackPattern));
  PenMode(patXor);

  InsetRect(&portRect,10,10);

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

    QDFlushPortBuffer(GetWindowPort(FrontWindow()),NULL);
  }

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

    QDFlushPortBuffer(GetWindowPort(FrontWindow()),NULL);
  }

  if(!gRunningOnX)
    SetThemeCursor(kThemeArrowCursor);
}

// *************************************************************************** doFrameAndPaint

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

  PenNormal();
  PenSize(30,20);
  
  for(a=0;a<3;a++)
  {
    RGBBackColor(&gWhiteColour);
    GetWindowPortBounds(gWindowRef,&portRect);
    FillRect(&portRect,GetQDGlobalsWhite(&whitePattern));

    if(!gRunningOnX)
      SetThemeCursor(kThemeWatchCursor);

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

    if(a == 0)
    {
      SetWTitle(gWindowRef,"\pFraming and painting with a colour");
      RGBForeColor(&gRedColour);                               // set foreground colour to red
    }
    else if(a == 1)
    {
      SetWTitle(gWindowRef,"\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(gWindowRef,"\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");  
    QDFlushPortBuffer(GetWindowPort(FrontWindow()),NULL);
    Delay(30,&finalTicks);

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

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

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

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

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

    OffsetRect(&theRect,140,0);
    PaintArc(&theRect,330,300);                                                    // PaintArc
    MoveTo(450,214);
    DrawString("\pPaintArc");  
    QDFlushPortBuffer(GetWindowPort(FrontWindow()),NULL);
    Delay(30,&finalTicks);
  
    if(!gRunningOnX)
      SetThemeCursor(kThemeArrowCursor);

    if(a < 2)
    {
      SetWTitle(gWindowRef,"\pClick mouse for more");
      QDFlushPortBuffer(GetWindowPort(FrontWindow()),NULL);
      while(!Button()) ;
    }  
  }

  DisposePixPat(pixpatHdl);
}

// ************************************************************************* doFillEraseInvert

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

  PenNormal();
  PenSize(30,20);

  for(a=0;a<4;a++)
  {
    if(a < 3)
    {
      RGBBackColor(&gWhiteColour);
      GetWindowPortBounds(gWindowRef,&portRect);
      FillRect(&portRect,GetQDGlobalsWhite(&whitePattern));
    }

    if(!gRunningOnX)
      SetThemeCursor(kThemeWatchCursor);

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

    if(a == 0)
    {
      SetWTitle(gWindowRef,"\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(&whitePattern);                          // set white bit pattern for background
    }
    else if(a == 1)
    {
      SetWTitle(gWindowRef,"\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(gWindowRef,"\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(gWindowRef,"\pInverting");

      BackPat(&whitePattern);
      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");  
    }    
    QDFlushPortBuffer(GetWindowPort(FrontWindow()),NULL);
    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");  
    }    
    QDFlushPortBuffer(GetWindowPort(FrontWindow()),NULL);
    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");  
    }    
    QDFlushPortBuffer(GetWindowPort(FrontWindow()),NULL);
    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");  
    }    
    QDFlushPortBuffer(GetWindowPort(FrontWindow()),NULL);
    Delay(30,&finalTicks);
  
    OffsetRect(&theRect,-420,186);
    MoveTo(30,214);
    if(a < 3)
    {
      EraseRect(&theRect);                                                        // EraseRect
      DrawString("\pEraseRect");  
    }
    else
    {
      InvertRect(&theRect);                                                      // InvertRect
      DrawString("\pInvertRect");  
    }
    QDFlushPortBuffer(GetWindowPort(FrontWindow()),NULL);
    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");  
    }
    QDFlushPortBuffer(GetWindowPort(FrontWindow()),NULL);
    Delay(30,&finalTicks);

    OffsetRect(&theRect,140,0);
    MoveTo(310,214);
    if(a < 3)
    {  
      EraseOval(&theRect);                                                        // EraseOval
      DrawString("\pEraseOval");  
    }
    else
    {
      InvertOval(&theRect);                                                      // InvertOval
      DrawString("\pInvertOval");  
    }
    QDFlushPortBuffer(GetWindowPort(FrontWindow()),NULL);
    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");  
    }
    QDFlushPortBuffer(GetWindowPort(FrontWindow()),NULL);
    Delay(30,&finalTicks);

    if(!gRunningOnX)
      SetThemeCursor(kThemeArrowCursor);

    if(a < 3)
    {
      SetWTitle(gWindowRef,"\pClick mouse for more");
      QDFlushPortBuffer(GetWindowPort(FrontWindow()),NULL);
      while(!Button()) ;
    }  
  }

  DisposePixPat(fillPixpatHdl);
  DisposePixPat(backPixpatHdl);
}

// ************************************************************************ doPolygonAndRegion

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

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

  RGBBackColor(&gWhiteColour);
  GetWindowPortBounds(gWindowRef,&portRect);
  FillRect(&portRect,GetQDGlobalsWhite(&whitePattern));

  if(!gRunningOnX)
    SetThemeCursor(kThemeWatchCursor);

  // ............................................................................. 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)");  
  QDFlushPortBuffer(GetWindowPort(FrontWindow()),NULL);
  Delay(30,&finalTicks);

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

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

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

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

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

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

  KillPoly(polygonHdl);
  DisposeRgn(regionHdl);
  DisposePixPat(fillPixpatHdl);
  BackPat(&whitePattern);  

  if(!gRunningOnX)
    SetThemeCursor(kThemeArrowCursor);
}

// ************************************************************************************ doText

void  doText(void)
{
  Rect    portRect, theRect;
  Pattern whitePattern;
  SInt16  windowCentre, a, fontNum, stringWidth;
  Str255  textString;
  UInt32  finalTicks;
    
  RGBBackColor(&gWhiteColour);
  GetWindowPortBounds(gWindowRef,&portRect);
  FillRect(&portRect,GetQDGlobalsWhite(&whitePattern));               

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

  if(!gRunningOnX)
    SetThemeCursor(kThemeWatchCursor);

  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(normal);
      RGBForeColor(&gGreenColour);
    }
    else if(a == 6)
      TextFace(bold + italic);
    else if(a == 7)
    {
      GetFNum("\pCharcoal",&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);

    QDFlushPortBuffer(GetWindowPort(FrontWindow()),NULL);
    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,portRect.left + 5,portRect.bottom - 55,portRect.left + 118,
          portRect.bottom - 5);
  EraseRect(&theRect);
  InsetRect(&theRect,5,5);
  GetIndString(textString,rFontsStringList,9);
  RGBForeColor(&gWhiteColour);
  TETextBox(&textString[1],textString[0],&theRect,teFlushLeft);

  if(!gRunningOnX)
    SetThemeCursor(kThemeArrowCursor);
}

// ******************************************************************************* doScrolling

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

  SetWTitle(gWindowRef,"\pScrolling pixels");

  RGBBackColor(&gWhiteColour);
  GetWindowPortBounds(gWindowRef,&portRect);
  FillRect(&portRect,GetQDGlobalsWhite(&whitePattern));

  if(!gRunningOnX)
    SetThemeCursor(kThemeWatchCursor);

  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);
    QDFlushPortBuffer(GetWindowPort(FrontWindow()),NULL);
    theRect.top ++;
    Delay(1,&finalTicks);
  }

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

  for(a=0;a<371;a++)
  {
    ScrollRect(&theRect,0,-1,scrollRegionHdl);
    QDFlushPortBuffer(GetWindowPort(FrontWindow()),NULL);
    theRect.bottom --;
    Delay(1,&finalTicks);
  }

  SetClip(oldClipHdl);

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

  if(!gRunningOnX)
    SetThemeCursor(kThemeArrowCursor);
}

// ********************************************************************** doBooleanSourceModes

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

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

  RGBForeColor(&gBlackColour);
  RGBBackColor(&gGreenColour);
  GetWindowPortBounds(gWindowRef,&portRect);
  FillRect(&portRect,GetQDGlobalsWhite(&whitePattern));
  SetRect(&theRect,portRect.left,portRect.top,portRect.right,
          (portRect.bottom - portRect.top) / 2);
  RGBBackColor(&gWhiteColour);
  FillRect(&theRect,&whitePattern);
  
  if(!gRunningOnX)
    SetThemeCursor(kThemeWatchCursor);

  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);
    }
  }

  QDFlushPortBuffer(GetWindowPort(FrontWindow()),NULL);

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

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

  destinationPixMapHdl = GetPortPixMap(GetQDGlobalsThePort());

  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,
               (BitMap *) *destinationPixMapHdl,
               &sourceIconMap.bounds,
               &theRect,
               b,NULL);
      GetIndString(sourceString,rBooleanStringList,b + 1);
      MoveTo(b * 69 + 28,a * 191 + 118);
      DrawString(sourceString);

      QDFlushPortBuffer(GetWindowPort(FrontWindow()),NULL);
    }
  }

  HUnlock(sourceIconHdl);

  if(!gRunningOnX)
    SetThemeCursor(kThemeArrowCursor);
}

// ******************************************************************* doArithmeticSourceModes

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

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

  RGBForeColor(&gBlackColour);
  RGBBackColor(&gWhiteColour);
  GetWindowPortBounds(gWindowRef,&portRect);
  FillRect(&portRect,GetQDGlobalsWhite(&whitePattern));

  if(!gRunningOnX)
    SetThemeCursor(kThemeWatchCursor);

  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);

  QDFlushPortBuffer(GetWindowPort(FrontWindow()),NULL);

  currentPixMapHdl = GetPortPixMap(GetWindowPort(gWindowRef));

  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((BitMap *) *currentPixMapHdl,
               (BitMap *) *currentPixMapHdl,
               &sourceRect,&destRect,
               arithmeticMode + ditherCopy,NULL);

      arithmeticMode ++;

      QDFlushPortBuffer(GetWindowPort(FrontWindow()),NULL);
    }

  }

  ReleaseResource((Handle) sourceHdl);
  ReleaseResource((Handle) destinationHdl);  

  if(!gRunningOnX)
    SetThemeCursor(kThemeArrowCursor);
}

// **************************************************************************** doHighlighting

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

  SetWTitle(gWindowRef,"\pHighlighting");

  RGBForeColor(&gBlackColour);
  RGBBackColor(&gWhiteColour);
  GetWindowPortBounds(gWindowRef,&portRect);
  FillRect(&portRect,GetQDGlobalsWhite(&whitePattern));

  LMGetHiliteRGB(&oldHighlightColour);

  for(a=0;a<3;a++)
  {
    MoveTo(50,a * 100 + 60);
    DrawString("\pClearing the highlight bit and calling InvertRect.");
    QDFlushPortBuffer(GetWindowPort(FrontWindow()),NULL);
    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);
    QDFlushPortBuffer(GetWindowPort(FrontWindow()),NULL);

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

    while(!Button()) ;

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

    LMSetHiliteMode(hiliteVal);

    InvertRect(&theRect);  
    QDFlushPortBuffer(GetWindowPort(FrontWindow()),NULL);
  }

  HiliteColor(&oldHighlightColour);

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

  QDFlushPortBuffer(GetWindowPort(FrontWindow()),NULL);
}

// *************************************************************************** doDrawWithMouse

void  doDrawWithMouse(void)
{
  Rect         portRect, drawRect;
  Pattern      whitePattern, blackPattern;
  PixPatHandle pixpatHdl;
  Point        initialMouse, previousMouse, currentMouse;
  UInt16       randomNumber;
  RGBColor     theColour;

  RGBBackColor(&gWhiteColour);
  GetWindowPortBounds(gWindowRef,&portRect);
  FillRect(&portRect,GetQDGlobalsWhite(&whitePattern));

  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(GetQDGlobalsBlack(&blackPattern));
  BackPixPat(pixpatHdl);

  randomNumber = doRandomNumber(0,3);

  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(&whitePattern);
}      

// *************************************************************************** doDrawingState

void  doDrawingState(void)
{
  Rect              portRect, theRect;
  Pattern           whitePattern;
  ThemeDrawingState themeDrawingState;
  SInt16            a;
  UInt32            finalTicks;
  
  RGBBackColor(&gBlueColour);
  GetWindowPortBounds(gWindowRef,&portRect);
  FillRect(&portRect,GetQDGlobalsWhite(&whitePattern));
  SetWTitle(gWindowRef,"\pSaving and restoring the graphics port drawing state");

  if(!gRunningOnX)
    SetThemeCursor(kThemeWatchCursor);

  NormalizeThemeDrawingState();

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

  GetThemeDrawingState(&themeDrawingState);

  theRect = 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);  

  SetThemeDrawingState(themeDrawingState,true);

  doDrawingStateProof(2);

  if(!gRunningOnX)
    SetThemeCursor(kThemeArrowCursor);
}

// ********************************************************************** 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);  

  QDFlushPortBuffer(GetWindowPort(FrontWindow()),NULL);
}

// *********************************************************************** doGetDepthAndDevice

void doGetDepthAndDevice(void)
{
  GDHandle deviceHdl;

  deviceHdl = GetMainDevice();
  gPixelDepth = (*(*deviceHdl)->gdPMap)->pixelSize;
  if(((1 << gdDevType) & (*deviceHdl)->gdFlags) != 0)
    gIsColourDevice = true;
}

// **************************************************************************** doRandomNumber

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

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

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

Demonstration Program QuickDraw 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.

defines

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.

Global Variables

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 functions in the demonstration.  The call to
SetQDGlobalsRandomSeed 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.  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 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 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 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 three 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 by setting it in the graphics port object.
Lines Drawn With Foreground Colour And Black Pen Pattern
After the window title is set, FillRect is called with the white pattern with 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 allocated by the
GetPixPat call.

At this point, the clipping region saved at the start of the function is restored, and all of
the memory allocated 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 allocated 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 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 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 allocated 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 allocated by
OpenPoly, DisposeRgn is called to free all the memory allocated by NewRgn, DisposePixPat is
called to free all the memory allocated 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 allocated 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 structure.  That way, the CopyBits routine can be used to copy the bitmap into the
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 structure, 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
allocated by the GetPicture calls.

doHighlighting

doHighlighting demonstrates highlighting, first with the colour set by the user in the
Appearance pane of the Appearance control panel (Mac OS 8/9) or in System Preferences (Mac OS
X), 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(GetQDGlobalsGray(&grayPattern));

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:

o FrameRect is called to draw the framed rectangle.

o 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.

o 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.

o 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.

o 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.

o 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 location.

When the mouse button is released:

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

o 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".

o 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.

o 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 is included in this function for
demonstration purposes only.  Ordinarily, this function would be called (if required) at other
points in an application.

The call to GetThemeDrawingState saves the drawing state prior to the calls to the Appearance
Manager functions SetThemeBackground and SetThemePen, which will change either the colour or
the pattern settings in the graphics port. 

The call to SetThemeDrawingState restores the saved drawing state.

The intervening code simply draws a Mac OS 8/9-type 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, after the calls
to the Appearance Manager functions, and after the call to SetThemeDrawingState.

doDrawingStateProof

doDrawingStateProof 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, after the calls to the Appearance Manager functions, and after the
call to SetThemeDrawingState.

doRandomNumber

doRandomNumber are incidental to the demonstration. 

The use of the QuickDraw random number generator is quite adequate for the purposes of this
demonstration.  However, a professional programmer would not regard it as measuring up to the
minimal standards of a "serious" random number generator.  (See the article on random number
generators at http://www.mactech.com/articles/mactech/Vol.08/08.03/RandomNumbers/index.html.)
 

Community Search:
MacTech Search:

Software Updates via MacUpdate

Latest Forum Discussions

See All

Go from lowly lizard to wicked Wyvern in...
Do you like questing, and do you like dragons? If not then boy is this not the announcement for you, as Loongcheer Game has unveiled Quest Dragon: Idle Mobile Game. Yes, it is amazing Square Enix hasn’t sued them for copyright infringement, but... | Read more »
Aether Gazer unveils Chapter 16 of its m...
After a bit of maintenance, Aether Gazer has released Chapter 16 of its main storyline, titled Night Parade of the Beasts. This big update brings a new character, a special outfit, some special limited-time events, and, of course, an engaging... | Read more »
Challenge those pesky wyverns to a dance...
After recently having you do battle against your foes by wildly flailing Hello Kitty and friends at them, GungHo Online has whipped out another surprising collaboration for Puzzle & Dragons. It is now time to beat your opponents by cha-cha... | Read more »
Pack a magnifying glass and practice you...
Somehow it has already been a year since Torchlight: Infinite launched, and XD Games is celebrating by blending in what sounds like a truly fantastic new update. Fans of Cthulhu rejoice, as Whispering Mist brings some horror elements, and tests... | Read more »
Summon your guild and prepare for war in...
Netmarble is making some pretty big moves with their latest update for Seven Knights Idle Adventure, with a bunch of interesting additions. Two new heroes enter the battle, there are events and bosses abound, and perhaps most interesting, a huge... | Read more »
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 »

Price Scanner via MacPrices.net

Limited-time sale: 13-inch M3 MacBook Airs fo...
Amazon has the base 13″ M3 MacBook Air (8GB/256GB) in stock and on sale for a limited time for $989 shipped. That’s $110 off MSRP, and it’s the lowest price we’ve seen so far for an M3-powered... Read more
13-inch M2 MacBook Airs in stock today at App...
Apple has 13″ M2 MacBook Airs available for only $849 today in their Certified Refurbished store. These are the cheapest M2-powered MacBooks for sale at Apple. Apple’s one-year warranty is included,... Read more
New today at Apple: Series 9 Watches availabl...
Apple is now offering Certified Refurbished Apple Watch Series 9 models on their online store for up to $80 off MSRP, starting at $339. Each Watch includes Apple’s standard one-year warranty, a new... Read more
The latest Apple iPhone deals from wireless c...
We’ve updated our iPhone Price Tracker with the latest carrier deals on Apple’s iPhone 15 family of smartphones as well as previous models including the iPhone 14, 13, 12, 11, and SE. Use our price... Read more
Boost Mobile will sell you an iPhone 11 for $...
Boost Mobile, an MVNO using AT&T and T-Mobile’s networks, is offering an iPhone 11 for $149.99 when purchased with their $40 Unlimited service plan (12GB of premium data). No trade-in is required... Read more
Free iPhone 15 plus Unlimited service for $60...
Boost Infinite, part of MVNO Boost Mobile using AT&T and T-Mobile’s networks, is offering a free 128GB iPhone 15 for $60 per month including their Unlimited service plan (30GB of premium data).... Read more
$300 off any new iPhone with service at Red P...
Red Pocket Mobile has new Apple iPhones on sale for $300 off MSRP when you switch and open up a new line of service. Red Pocket Mobile is a nationwide MVNO using all the major wireless carrier... Read more
Clearance 13-inch M1 MacBook Airs available a...
Apple has clearance 13″ M1 MacBook Airs, Certified Refurbished, available for $759 for 8-Core CPU/7-Core GPU/256GB models and $929 for 8-Core CPU/8-Core GPU/512GB models. Apple’s one-year warranty is... Read more
Updated Apple MacBook Price Trackers
Our Apple award-winning MacBook Price Trackers are continually updated with the latest information on prices, bundles, and availability for 16″ and 14″ MacBook Pros along with 13″ and 15″ MacBook... Read more
Every model of Apple’s 13-inch M3 MacBook Air...
Best Buy has Apple 13″ MacBook Airs with M3 CPUs in stock and on sale today for $100 off MSRP. Prices start at $999. Their prices are the lowest currently available for new 13″ M3 MacBook Airs among... Read more

Jobs Board

Solutions Engineer - *Apple* - SHI (United...
**Job Summary** An Apple Solution Engineer's primary role is tosupport SHI customers in their efforts to select, deploy, and manage Apple operating systems and Read more
DMR Technician - *Apple* /iOS Systems - Haml...
…relevant point-of-need technology self-help aids are available as appropriate. ** Apple Systems Administration** **:** Develops solutions for supporting, deploying, Read more
Omnichannel Associate - *Apple* Blossom Mal...
Omnichannel Associate - Apple Blossom Mall Location:Winchester, VA, United States (https://jobs.jcp.com/jobs/location/191170/winchester-va-united-states) - Apple Read more
Operations Associate - *Apple* Blossom Mall...
Operations Associate - Apple Blossom Mall Location:Winchester, VA, United States (https://jobs.jcp.com/jobs/location/191170/winchester-va-united-states) - Apple Read more
Cashier - *Apple* Blossom Mall - JCPenney (...
Cashier - Apple Blossom Mall Location:Winchester, VA, United States (https://jobs.jcp.com/jobs/location/191170/winchester-va-united-states) - Apple Blossom Mall Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.