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

Tokkun Studio unveils alpha trailer for...
We are back on the MMORPG news train, and this time it comes from the sort of international developers Tokkun Studio. They are based in France and Japan, so it counts. Anyway, semantics aside, they have released an alpha trailer for the upcoming... | Read more »
Win a host of exclusive in-game Honor of...
To celebrate its latest Jujutsu Kaisen crossover event, Honor of Kings is offering a bounty of login and achievement rewards kicking off the holiday season early. [Read more] | Read more »
Miraibo GO comes out swinging hard as it...
Having just launched what feels like yesterday, Dreamcube Studio is wasting no time adding events to their open-world survival Miraibo GO. Abyssal Souls arrives relatively in time for the spooky season and brings with it horrifying new partners to... | Read more »
Ditch the heavy binders and high price t...
As fun as the real-world equivalent and the very old Game Boy version are, the Pokemon Trading Card games have historically been received poorly on mobile. It is a very strange and confusing trend, but one that The Pokemon Company is determined to... | Read more »
Peace amongst mobile gamers is now shatt...
Some of the crazy folk tales from gaming have undoubtedly come from the EVE universe. Stories of spying, betrayal, and epic battles have entered history, and now the franchise expands as CCP Games launches EVE Galaxy Conquest, a free-to-play 4x... | Read more »
Lord of Nazarick, the turn-based RPG bas...
Crunchyroll and A PLUS JAPAN have just confirmed that Lord of Nazarick, their turn-based RPG based on the popular OVERLORD anime, is now available for iOS and Android. Starting today at 2PM CET, fans can download the game from Google Play and the... | Read more »
Digital Extremes' recent Devstream...
If you are anything like me you are impatiently waiting for Warframe: 1999 whilst simultaneously cursing the fact Excalibur Prime is permanently Vault locked. To keep us fed during our wait, Digital Extremes hosted a Double Devstream to dish out a... | Read more »
The Frozen Canvas adds a splash of colou...
It is time to grab your gloves and layer up, as Torchlight: Infinite is diving into the frozen tundra in its sixth season. The Frozen Canvas is a colourful new update that brings a stylish flair to the Netherrealm and puts creativity in the... | Read more »
Back When AOL WAS the Internet – The Tou...
In Episode 606 of The TouchArcade Show we kick things off talking about my plans for this weekend, which has resulted in this week’s show being a bit shorter than normal. We also go over some more updates on our Patreon situation, which has been... | Read more »
Creative Assembly's latest mobile p...
The Total War series has been slowly trickling onto mobile, which is a fantastic thing because most, if not all, of them are incredibly great fun. Creative Assembly's latest to get the Feral Interactive treatment into portable form is Total War:... | Read more »

Price Scanner via MacPrices.net

Early Black Friday Deal: Apple’s newly upgrad...
Amazon has Apple 13″ MacBook Airs with M2 CPUs and 16GB of RAM on early Black Friday sale for $200 off MSRP, only $799. Their prices are the lowest currently available for these newly upgraded 13″ M2... Read more
13-inch 8GB M2 MacBook Airs for $749, $250 of...
Best Buy has Apple 13″ MacBook Airs with M2 CPUs and 8GB of RAM in stock and on sale on their online store for $250 off MSRP. Prices start at $749. Their prices are the lowest currently available for... Read more
Amazon is offering an early Black Friday $100...
Amazon is offering early Black Friday discounts on Apple’s new 2024 WiFi iPad minis ranging up to $100 off MSRP, each with free shipping. These are the lowest prices available for new minis anywhere... Read more
Price Drop! Clearance 14-inch M3 MacBook Pros...
Best Buy is offering a $500 discount on clearance 14″ M3 MacBook Pros on their online store this week with prices available starting at only $1099. Prices valid for online orders only, in-store... Read more
Apple AirPods Pro with USB-C on early Black F...
A couple of Apple retailers are offering $70 (28%) discounts on Apple’s AirPods Pro with USB-C (and hearing aid capabilities) this weekend. These are early AirPods Black Friday discounts if you’re... Read more
Price drop! 13-inch M3 MacBook Airs now avail...
With yesterday’s across-the-board MacBook Air upgrade to 16GB of RAM standard, Apple has dropped prices on clearance 13″ 8GB M3 MacBook Airs, Certified Refurbished, to a new low starting at only $829... Read more
Price drop! Apple 15-inch M3 MacBook Airs now...
With yesterday’s release of 15-inch M3 MacBook Airs with 16GB of RAM standard, Apple has dropped prices on clearance Certified Refurbished 15″ 8GB M3 MacBook Airs to a new low starting at only $999.... Read more
Apple has clearance 15-inch M2 MacBook Airs a...
Apple has clearance, Certified Refurbished, 15″ M2 MacBook Airs now available starting at $929 and ranging up to $410 off original MSRP. These are the cheapest 15″ MacBook Airs for sale today at... Read more
Apple drops prices on 13-inch M2 MacBook Airs...
Apple has dropped prices on 13″ M2 MacBook Airs to a new low of only $749 in their Certified Refurbished store. These are the cheapest M2-powered MacBooks for sale at Apple. Apple’s one-year warranty... Read more
Clearance 13-inch M1 MacBook Airs available a...
Apple has clearance 13″ M1 MacBook Airs, Certified Refurbished, now available for $679 for 8-Core CPU/7-Core GPU/256GB models. Apple’s one-year warranty is included, shipping is free, and each... Read more

Jobs Board

Seasonal Cashier - *Apple* Blossom Mall - J...
Seasonal Cashier - Apple Blossom Mall Location:Winchester, VA, United States (https://jobs.jcp.com/jobs/location/191170/winchester-va-united-states) - Apple Read more
Seasonal Fine Jewelry Commission Associate -...
…Fine Jewelry Commission Associate - Apple Blossom Mall Location:Winchester, VA, United States (https://jobs.jcp.com/jobs/location/191170/winchester-va-united-states) Read more
Seasonal Operations Associate - *Apple* Blo...
Seasonal Operations Associate - Apple Blossom Mall Location:Winchester, VA, United States (https://jobs.jcp.com/jobs/location/191170/winchester-va-united-states) - Read more
Hair Stylist - *Apple* Blossom Mall - JCPen...
Hair Stylist - Apple Blossom Mall Location:Winchester, VA, United States (https://jobs.jcp.com/jobs/location/191170/winchester-va-united-states) - Apple Blossom 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.