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