UNIT cs65; {******************************************************************************* Programmer:John Zelle Description: This is a Codewarrior unit that defines a set of routines to make Codewarrior on the Mac look similar to Turbo Pascal under DOS. Specifically, this unit implements procedures and functions for graphics-oriented programs of the type found in "Introductory Computer Science" by A. K. Dewdney. Intitial Version: Summer 1996. Updates: 9/22/96 Cleaned up code and added some comments. *******************************************************************************} INTERFACE FUNCTION Random:REAL; { Imitates RANDOM. Returns a value uniformly distributed between 0 and 1 } FUNCTION RandomInt(top : INTEGER):INTEGER; { Imitates RANDOM(SomeInt). Returns an integer uniformly distributed in range 0 to top-1. } PROCEDURE Randomize; { Imitates RANDOMIZE. Initializes the random number generator to produce differing sequences. } PROCEDURE SetGraph; { Imitates SetGraph. Initializes the graphics routines. IMPORTANT NOTE: SetGraph is incompatible with and program containing READLN orWRITELN. A graphics program may only use the graphical I/O routines described below. } FUNCTION ButtonPressed : BOOLEAN; { Is true anytime after the mouse button has been pressed during program execution. } FUNCTION Click:BOOLEAN; { Like ButtonPressed, but also clears the event so that the next call to Click returns false (unless the button has been pressed again). } PROCEDURE ClrScr; { Imitates Clrscr. Clears the graphics screen.} PROCEDURE OutTextXY(X, Y : INTEGER; Str:STRING); { Imitates OutTextXY. Writes the output string starting at location (X,Y). } PROCEDURE OutText(Str : STRING); { Same as OutTextXY, but writes wherever the current location is.} PROCEDURE SetColor(C : INTEGER); { Imitates SetColor. Subsequent drawing is donw in the indicated color. A table of color values is given on page 106. Unlike Turbo Pascal, SetColor should also be used to set the color of filled object, replacing SetFillStyle. } PROCEDURE Bar(left,top,right,bottom : INTEGER); { Imitates BAR. Draws a bar in the current color. } PROCEDURE Line(left,top,right,bottom : INTEGER); { Imitates LINE. Draws a line in the current color. } PROCEDURE PutPixel(Horiz, Vertical : INTEGER); { Imitates PutPixel. Unlike Turbo Pascal, it always draw the pixel in the current color. } PROCEDURE ReadStr(VAR Str : STRING); { Graphics input routine. Replaces READLN for inputting string values. } PROCEDURE ReadInt(VAR Value : INTEGER); { Graphics input routine. Replaces READLN for inputting INTEGER values. } PROCEDURE ReadReal(VAR Value : REAL); { Graphics input routine. Replaces READLN for inputting REAL values. } PROCEDURE Pause; { Pauses execution until a key is pressed, or the mouse button is pushed. Replaces a bare READLN for "holding" a graphics screen. } PROCEDURE Delay(Ticks : INTEGER); { Imitates Delay. Pauses execution for a specifified number of ticks.} IMPLEMENTATION USES Types, QuickDraw,OSUtils, SegLoad, Fonts, Windows, Menus, TextEdit, Dialogs, Processes, Events, QuickDrawText; {*******************************************************************************} FUNCTION rand:INTEGER; C; EXTERNAL; {Borrow randoms from C library} PROCEDURE srand(seed:INTEGER); C; EXTERNAL; FUNCTION random:REAL; BEGIN random := rand/32768; END; { random } PROCEDURE RANDOMIZE; VAR seed : longint; BEGIN GetDateTime(seed); srand(seed); END; { RANDOMIZE } FUNCTION RandomInt(limit : INTEGER):INTEGER; BEGIN RandomInt := rand MOD limit; END; { RandomInt } {*******************************************************************************} PROCEDURE SetGraph; { Standard Macintosh initializations except there is no error checking. Assumes the PowerMac environment at Drake. The screen is setup as one large graphics window (ala Turbo Pascal). All graphics commands write to this window. } VAR mainPtr : WindowPtr; windRect : Rect; BEGIN InitGraf(@qd.thePort); InitFonts; InitWindows; InitMenus; TEInit; InitDialogs(NIL); InitCursor; GetDateTime (qd.RandSeed); windRect := qd.screenBits.bounds; MainPtr := NewWindow(NIL, windRect, 'Graphics', TRUE, documentProc, Pointer(-1), FALSE, 0); SetPort(MainPtr); MoveTo(0,30); END; { Initialize } {******************************************************************************* Functions for detecting mouse clicks } FUNCTION ButtonPressed : BOOLEAN; { This one does not clear the event} BEGIN ButtonPressed := Button; END; { ButtonPressed } Function Click:BOOLEAN; VAR AnEvent : EventRecord; BEGIN Click := FALSE; IF GetNextEvent(EveryEvent,AnEvent) THEN IF AnEvent.What = MouseDown THEN Click := TRUE; END; { Click } {*******************************************************************************} PROCEDURE ClrScr; {Clear the screen by painting it white.} BEGIN ForeColor(Whitecolor); PaintRect(qd.screenBits.bounds); MoveTo(0,30); ForeColor(BlackColor); END; { ClrScr } {******************************************************************************} {Routines for outputting text in graphics mode} PROCEDURE OutTextXY(X, Y : INTEGER; Str:STRING); BEGIN MoveTo(X,Y); DrawString(Str); END; PROCEDURE OutText(Str:STRING); BEGIN DrawString(Str); END; { OutText } {***************************************************************************} {Routines for Drawing} PROCEDURE SetColor(C : INTEGER); BEGIN CASE C OF 0 : ForeColor(BlackColor); 1 : ForeColor(BlueColor); 2 : ForeColor(GreenColor); 3 : ForeColor(CyanColor); 4 : ForeColor(RedColor); 5 : ForeColor(MagentaColor); 14 : ForeColor(yellowColor); 15 : ForeColor(whiteColor); END; { case } END; { SetColor } PROCEDURE Bar(left,top,right,bottom:INTEGER); VAR Bar : Rect; BEGIN setRect(Bar,left,top,right,bottom); PaintRect(Bar); END; { Bar } PROCEDURE Line(left,top,right,bottom:INTEGER); BEGIN MoveTo(left,top); LineTo(right,bottom); END; PROCEDURE PutPixel(H,V : INTEGER); BEGIN MoveTo(H,V); LineTo(H,V); END; {******************************************************************************} { Routines for Graphics-mode inputs. } PROCEDURE ReadStr(VAR Str : STRING); VAR Done : BOOLEAN; AnEvent : EventRecord; Key : char; BEGIN Done := FALSE; Str := ''; REPEAT IF getNextEvent(EveryEvent,AnEvent) THEN IF (anEvent.what = keydown) or (anEvent.what = autoKey) THEN BEGIN Key := char(BAnd(anEvent.message, charCodeMask)); IF ord(Key) <> 13 THEN BEGIN Str[0] := char(ord(Str[0]) + 1); Str[length(Str)] := Key; DrawChar(Key); END ELSE Done := TRUE; END; UNTIL Done; END; { ReadStr } PROCEDURE ReadInt(VAR Value : INTEGER); VAR Done : BOOLEAN; AnEvent : EventRecord; Key : char; KeyValue : INTEGER; BEGIN Done := FALSE; Value := 0; REPEAT IF getNextEvent(EveryEvent,AnEvent) THEN IF (anEvent.what = keydown) or (anEvent.what = autoKey) THEN BEGIN Key := char(BAnd(anEvent.message, charCodeMask)); IF (ord(Key) <> 13) THEN BEGIN KeyValue := ord(Key) - ord('0'); IF (KeyValue >= 0) and (KeyValue <=9) THEN BEGIN Value := Value*10+KeyValue; DrawChar(Key); END END ELSE Done := TRUE; END; UNTIL Done; END; { ReadInt } PROCEDURE ReadReal(VAR Value : Real); VAR Done : BOOLEAN; AnEvent : EventRecord; Key : char; KeyValue : INTEGER; Fraction : REAL; BEGIN Done := FALSE; Value := 0.0; REPEAT IF getNextEvent(EveryEvent,AnEvent) THEN IF (anEvent.what = keydown) or (anEvent.what = autoKey) THEN BEGIN Key := char(BAnd(anEvent.message, charCodeMask)); IF (Key <> '.') AND (ord(key) <> 13) THEN BEGIN KeyValue := ord(Key) - ord('0'); IF (KeyValue >= 0) and (KeyValue <=9) THEN BEGIN Value := Value*10+KeyValue; DrawChar(Key); END END ELSE Done := TRUE; END; UNTIL Done; IF Key = '.' THEN BEGIN DrawChar('.'); Done := FALSE; fraction := 1; REPEAT IF getNextEvent(EveryEvent,AnEvent) THEN IF (anEvent.what = keydown) or (anEvent.what = autoKey) THEN BEGIN Key := char(BAnd(anEvent.message, charCodeMask)); IF ord(Key) <> 13 THEN BEGIN KeyValue := ord(Key) - ord('0'); IF (KeyValue >= 0) and (KeyValue <=9) THEN BEGIN fraction := fraction *10; Value := Value+KeyValue/fraction; DrawChar(Key); END END ELSE Done := TRUE; END; UNTIL Done; END; END; { ReadReal } PROCEDURE Pause; VAR e : EventRecord; Done : BOOLEAN; BEGIN Done := FALSE; REPEAT IF GetNextEvent(EveryEvent, e) THEN IF e.what IN [keydown,autokey,mousedown] THEN Done := True; UNTIL Done; END; { Pause } PROCEDURE DELAY( Ticks : INTEGER); VAR StopTime : LONGINT; BEGIN StopTime := TickCount + Ticks DIV 100; REPEAT UNTIL TickCount > StopTime; END; { DELAY } END. {UNIT cs65}