home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Carousel Volume 2 #1
/
carousel.iso
/
mactosh
/
fonts
/
fontshow.sit
/
Windows.Pas
< prev
next >
Wrap
Pascal/Delphi Source File
|
1988-09-14
|
24KB
|
465 lines
UNIT Windows(2);
(* This unit contains the window handling routines for the FontShow program *)
(* Version 1.0 by Richard Clark, September 1988 *)
(* Version 1.1, September 13, 1988. Added the CreateFontPict routine so that the Menus unit *)
(* doesn't have to scrounge up the WindowPict when the user chooses Copy. Apparently, *)
(* the system modifies the WindowPict's boundaries before drawing it, and this causes *)
(* great problems if you try to paste this into the clipboard. *)
(* *)
(* Also changed the DisposHandle() calls to get rid of the WindowPic to KillPicture() *)
{$U-}
{$D+}
INTERFACE
{$U globals}
USES
MemTypes, QuickDraw, OSIntf, ToolIntf, PackIntf,
Globals;
CONST
wFont = 128; (* Resource ID of the Font display window *)
wAbout = 129; (* Resource ID of the ╥About╙ window *)
FUNCTION CreateFontPict(fNum, fSize: INTEGER): PicHandle;
(* Added in 1.1: Create a font grid picture with the given font and font size *)
PROCEDURE OpenAWindow; (* Create a new Font Display window *)
PROCEDURE AttachWindowPict(whichWindow : WindowPeek); (* Connect a font grid to a font window *)
PROCEDURE CloseAWindow (whichWindow : WindowPtr); (* Close the specified window *)
PROCEDURE CloseAllWindows; (* Close all visible windows, allowing each *)
(* window to be updated just before closure *)
PROCEDURE DoAbout; (* Open the ╥About╙ window *)
PROCEDURE UpdateAboutWindow; (* Cause the memory statistic in the ╥About╙ *)
(* window to be updated. *)
PROCEDURE UpdateWindow (whichWindow : WindowPtr); (* Redraw the given window *)
PROCEDURE ActivateWindow (whichWindow : WindowPeek; (* Set the global font information if it's a Font window *)
makeActive : Boolean);
IMPLEMENTATION
CONST
pAbout = 128; (* Resource ID of the ╥About╙ picture *)
VAR
MemSizeRect : Rect; (* The bounding box for the memory size number *)
(* in the about window *)
MemSizeLeft, (* The starting coordinates of the memory size *)
MemSizeBottom : INTEGER; (* message in the about window *)
PROCEDURE OpenAWindow;
(* This procedure creates a new font display window. The new window is located 16 pixels down *)
(* and to the right of the frontmost Font window. A QuickDraw picture containing the displayed *)
(* font grid is attached so that the window will be updated automatically by the system. *)
VAR
myWindow : WindowPeek; (* Our new window *)
done : Boolean; (* Flag used when searching for the frontmost *)
(* font window *)
currWindow : WindowPeek; (* The window being examined (to determine if it is *)
(* a font window *)
top, left : INTEGER; (* The upper, left coordinates of this window *)
BEGIN
(* Get the new window using the storage pre-allocated in the main loop *)
myWindow := WindowPeek(GetNewWindow(wFont, WindowReserve, WindowPtr(-1)));
WindowReserve := NIL; (* We've used this block, so get another *)
myWindow^.refCon := wFont; (* Mark this as being a font display window *)
(* Find the frontmost font window and position this window 16 pixels left and down from it *)
currWindow := WindowPeek(FrontWindow);
REPEAT
done := false;
IF (currWindow <> NIL) THEN
BEGIN
IF (currWindow^.windowKind < 0) OR (currWindow^.refCon <> wFont) THEN
(* This is a desk accessory, or not a font window, so skip it *)
currWindow := currWindow^.nextWindow
ELSE (* It's a font window *)
BEGIN (* Calculate the new coordinates and exit the loop *)
top := 16 - currWindow^.port.portBits.bounds.top;
left := 16 - currWindow^.port.portBits.bounds.left;
done := TRUE;
END;
END
ELSE (* No more windows are left, so no Font window *)
BEGIN (* was found. Place this window in the upper *)
top := 40; (* left corner of the screen, and exit the loop *)
left := 20;
done := TRUE;
END;
UNTIL done;
MoveWindow(WindowPtr(myWindow), left, top, true);(* Set the window's new position *)
ShowWindow(WindowPtr(myWindow)); (* Open it so our ╥Attach Picture╙ procedure *)
(* has something to work with. *)
AttachWindowPict(myWindow); (* Connect a picture of the font grid to this window *)
END; (* OpenAWindow *)
PROCEDURE CalcPictBounds(VAR PictBounds: Rect);
(* Calculate the boundaries of our Font Grid. We do this before drawing the picture so the *)
(* window's picture can be sized appropriately. (This isn't normally a problem when drawing*)
(* the window, as we could use an extremely large rectangle when creating picture and only *)
(* the top, left part would appear in the window. But, having too large of a rectangle *)
(* would cause a problem if the user Copies this picture to the Clipboard.) *)
(* *)
(* This routine assumes that a Font window has been selected (using SetPort) and will take *)
(* its font and size information from the current GrafPort. *)
CONST
Margin = 4; (* Start the picture at (4,4) *)
VAR
topMargin, (* How much space should we allocate for *)
leftMargin : INTEGER; (* the labels on the side of the grid? *)
cellSize,
gridSize : INTEGER;
BEGIN
cellSize := thePort^.txSize + 4; (* How large is each square? *)
gridSize := cellSize * 16; (* The grid is 16 squares on a side *)
topMargin := Margin + 3 * thePort^.txSize + 1; (* Calculate the depth of the top label area *)
leftMargin := Margin + StringWidth('$0X') + 1; (* Calculate the width of the side label area *)
SetRect(PictBounds, 0, 0, (* Set the picture's bounds, with a few (4) *)
leftMargin+gridSize+Margin, (* extra pixels on the sides. *)
topMargin+gridSize+Margin);
END; (* CalcPictBounds *)
PROCEDURE DrawFontGrid(fNum, fSize: INTEGER);
(* Draw a font grid in the current window using its current font and font size. *)
CONST
Margin = 4;
VAR
topMargin, (* This first part is a duplicate of the *)
leftMargin : INTEGER; (* procedure above. *)
rowCount,
colCount : INTEGER;
rowEnd,
colEnd : INTEGER;
rowV,
colH : INTEGER;
cellSize,
gridSize : INTEGER;
hexString : STRING[16];
oldFont,
oldSize : INTEGER;
BEGIN
hexString := '0123456789ABCDEF'; (* 0..15 in Hexadecimal *)
oldFont := thePort^.txFont;
oldSize := thePort^.txSize;
TextFont(fNum);
TextSize(fSize);
cellSize := fSize + 4; (* Calculate the spacing and placement of *)
gridSize := cellSize * 16; (* the grid lines *)
topMargin := Margin + 3 * fSize + 1;
leftMargin := Margin + StringWidth('$0X') + 1;
rowEnd := LeftMargin + gridSize; (* Set up to draw the Row lines *)
rowV := TopMargin;
FOR rowCount := 0 TO 15 DO (* Draw the horizontal lines *)
BEGIN
MoveTo(rowEnd, rowV); (* Draw one line *)
LineTo(Margin, rowV);
Move(0, cellSize - 1); (* Drop down to the next row *)
DrawChar('$'); (* Add the label for this row *)
DrawChar(hexString[rowCount + 1]);
DrawChar('X');
rowV := rowV + cellSize; (* Set up for the next row *)
END;
MoveTo(rowEnd, rowV); (* Draw a final line to close off the grid *)
LineTo(Margin, rowV);
colEnd := topMargin + gridSize; (* Set up to draw the column lines *)
colH := leftMargin;
FOR colCount := 0 TO 15 DO (* Draw each vertical line *)
BEGIN
MoveTo(colH, colEnd); (* Draw the line *)
LineTo(colH, Margin);
colH := colH + cellSize;
(* Draw one label at the top *)
MoveTo(colH - cellSize + 3, Margin + fSize);
DrawChar('$');
MoveTo(colH - cellSize + 3, Margin + 2 * fSize);
DrawChar('X');
MoveTo(colH - cellSize + 3, Margin + 3 * fSize);
DrawChar(hexString[colCount + 1]);
rowV := TopMargin + cellSize - 2;
FOR rowCount := 0 TO 15 DO (* Draw the characters inside of the grid *)
BEGIN
MoveTo(colH - cellSize + 2, rowV);
DrawChar(chr(rowCount * 16 + colCount));
rowV := rowV + cellSize;
END;
END;
MoveTo(colH, colEnd); (* Draw one final line to complete the grid *)
LineTo(colH, Margin);
END; (* DrawFontGrid *)
FUNCTION CreateFontPict;
VAR
picBounds : Rect; (* The bounds of the font grid *)
myPic : PicHandle; (* The new picture we are creating *)
BEGIN
CalcPictBounds(picBounds); (* Get the boundaries of our new picture *)
myPic := OpenPicture(picBounds); (* and begin recording the drawing commands *)
IF (myPic <> nil) THEN
BEGIN
DrawFontGrid(fNum, fSize); (* Draw the font grid into our picture *)
(* (nothing will appear on the screen) *)
ClosePicture; (* Complete the picture's definition, *)
END;
CreateFontPict := myPic;
END; (* CreateFontPict *)
PROCEDURE AttachWindowPict;
(* Given a font window, attach a picture to it containing a new font grid. (We use this method *)
(* so that QuickDraw will update the window for us.) *)
VAR
oldPort : GrafPtr; (* The currently selected GrafPort *)
wName, (* The new name of this window (eg. ╥Geneva 12╙) *)
scratch : Str255; (* String used in building the window name *)
BEGIN
IF (whichWindow <> NIL) THEN (* Make sure we have a window *)
IF (whichWindow^.refCon = wFont) THEN (* And make sure it's a font window *)
BEGIN
GetPort(oldPort); (* Preserve the current port *)
SetPort(WindowPtr(whichWindow)); (* And set the port to our target window *)
TextFace([]); (* Set the text face to plain, and the *)
TextSize(currSize); (* Font and Size to those indicated in the *)
TextFont(currFont); (* Font and Size menus *)
TextMode(srcOr); (* Set up the pen mode to overlay any lines *)
IF (whichWindow^.windowPic <> NIL) THEN (* If we already have a picture attached to *)
BEGIN (* this window, then get rid of it *)
KillPicture(whichWindow^.windowPic);
whichWindow^.windowPic := NIL;
END;
whichWindow^.windowPic := CreateFontPict(whichWindow^.port.txFont,
whichWindow^.port.txSize);
(* and attach the picture to this window *)
(* Assemble the window's title, ex: "Geneva 12" *)
GetFontName(currFont, wName); (* Get the current font's name *)
Insert(' ', wName, length(wName) + 1); (* Append a space (this is safer than CONCAT) *)
NumToString(currSize, scratch); (* Convert the font's size into a string *)
Insert(scratch, wName, length(wName) + 1); (* Append it to the title string *)
SetWTitle(WindowPtr(whichWindow), wName); (* And change the window's title (this redraws *)
(* the window's bounds *)
InvalRect(whichWindow^.port.portRect); (* Mark the contents of this window as having been changed *)
EraseRect(whichWindow^.port.portRect); (* And erase the old picture *)
SetPort(oldPort); (* Restore the saved GrafPort *)
END;
END; (* AttachWindowPict *)
PROCEDURE ForceUpdate;
(* This procedure is used by CloseAllWindows to activate and update a window just after it has *)
(* been uncovered. *)
VAR
theEvent: EventRecord;
BEGIN
IF (GetNextEvent(activMask, theEvent)) THEN (* The window has been activated *)
; (* Throw away the event! *)
IF (GetNextEvent(updateMask, theEvent)) THEN (* If FALSE, then the window is self-updating *)
(* by virtue of having an attached picture *)
UpdateWindow(WindowPtr(theEvent.message)); (* If TRUE, we will need to draw the window *)
END; (* ForceUpdate *)
PROCEDURE CloseAWindow;
(* Given a window, look at its type and perform the actions necesary to close it and dispose *)
(* of any private storage. *)
VAR
currWindow : WindowPeek; (* Used to access the window's kind and RefCon *)
aboutPict : Handle; (* Used to purge the "About" picture from memory *)
BEGIN
currWindow := WindowPeek(whichWindow); (* Convert our WindowPtr into a WindowPeek *)
IF (currWindow^.windowKind < 0) THEN (* This is a desk accessory *)
CloseDeskAcc(currWindow^.windowKind)
ELSE IF (currWindow^.refCon = wAbout) THEN (* This is the "About" window *)
BEGIN
DisposeWindow(whichWindow); (* Close the window and release its storage *)
AboutWindow := NIL; (* Mark it as being closed *)
IF (WindowReserve <> NIL) THEN (* Let our Pre-Allocation routine reclaim the memory *)
BEGIN (* (instead of leaving a hole below the current WindowReserve) *)
DisposPtr(WindowReserve);
WindowReserve := NIL;
END;
aboutPict := GetResource('PICT', pAbout); (* Get the "About" picture, then purge it from memory *)
ReleaseResource(aboutPict);
END
ELSE IF (currWindow^.refCon = wFont) THEN (* This is one of the font display windows *)
BEGIN
IF (currWindow^.windowPic <> NIL) THEN (* Get rid of the window's picture *)
KillPicture(currWindow^.windowPic);
DisposeWindow(whichWindow); (* Close the window and release its storage *)
IF (WindowReserve <> NIL) THEN (* Let our Pre-Allocation routine reclaim the memory *)
BEGIN
DisposPtr(WindowReserve);
WindowReserve := NIL;
END;
END;
END; (* CloseAWindow *)
PROCEDURE CloseAllWindows;
(* This procedure goes through all of the windows from front to back and closes each one. It *)
(* then gives the newly uncovered window a chance to get updated *)
VAR
inFront : WindowPtr;
BEGIN
REPEAT
inFront := FrontWindow;
IF (inFront <> NIL) THEN
BEGIN
CloseAWindow(inFront); (* Close the frontmost window *)
ForceUpdate; (* Now that the second window is exposed, update it *)
END;
UNTIL (inFront = NIL);
END; (* CloseAllWindows *)
PROCEDURE DoAbout;
(* Open our "About" window and calculate the location of the "Available Memory" prompt string *)
(* at the bottom of the window. *)
VAR
aboutPict : PicHandle;
promptWidth, (* The width of the "Available Memory" string *)
numWidth, (* The width of the following integer *)
combinedWidth : INTEGER;
promptString : StringHandle;
BEGIN
IF (AboutWindow = NIL) THEN
BEGIN
AboutWindow := GetNewWindow(wAbout, WindowReserve, WindowPtr(-1)); (* Create the new window *)
WindowReserve := NIL; (* Ask for a replacement pre-allocation *)
SetPort(AboutWindow); (* Set the font to Chicago, 12 point *)
TextFace([]);
TextFont(0);
TextSize(12);
aboutPict := PicHandle(GetResource('PICT', pAbout)); (* Pull the picture into memory so we can get its size *)
promptString := GetString(128); (* get the prompt that reads "Available memory:" *)
(* Put the baseline of our memory size message 16 pixels below the picture *)
MemSizeBottom := aboutPict^^.picFrame.bottom + 16;
HLock(Handle(promptString)); (* Lock the handle (so it doesn't move) *)
promptWidth := StringWidth(promptString^^); (* and calculate the display width of the string *)
HUnlock(Handle(promptString));
numWidth := 10 * CharWidth('0'); (* Assume that our free memory count will never be *)
(* longer than 10 digits *)
combinedWidth := promptWidth + numWidth;
(* Calculate the starting coordinates of the prompt string (the whole thing should be centered *)
(* in the dialog window *)
MemSizeLeft := ((AboutWindow^.portRect.right - AboutWindow^.portRect.left)
- combinedWidth) DIV 2;
(* Set up a rectangle which encloses just the displayed number. When the number changes, we *)
(* can invalidate this rectangle to force the About window to be redrawn. *)
SetRect(MemSizeRect, MemSizeLeft + promptWidth,
MemSizeBottom - 12,
MemSizeLeft + combinedWidth,
MemSizeBottom);
END
ELSE (* If the window already exists, then bring *)
SelectWindow(AboutWindow); (* it to the front *)
END; (* DoAbout *)
PROCEDURE UpdateAboutWindow;
(* This procedure forces the system to redraw the memory size info in the "About" window *)
VAR
oldPort : GrafPtr;
BEGIN
IF (AboutWindow <> NIL) THEN
BEGIN
GetPort(oldPort); (* Save the current port *)
SetPort(AboutWindow); (* Switch to the About window *)
InvalRect(MemSizeRect); (* Invalidate the memory size area *)
SetPort(oldPort); (* Switch back to the old port *)
END;
END; (* UpdateAboutWindow *)
PROCEDURE DrawAboutWindow;
(* This procedure is used to update the "About" window. Since we have both a picture and some *)
(* text to draw in the window (and the text is subject to change), we can't just attach a picture *)
(* to the window. *)
VAR
aboutPict : PicHandle; (* The main picture *)
promptString : StringHandle; (* The "Available Memory" prompt *)
memSizeString : Str255; (* Our free memory number converted into a string *)
BEGIN
aboutPict := PicHandle(GetResource('PICT', pAbout)); (* Load the picture into memory, and draw it *)
DrawPicture(aboutPict, aboutPict^^.picFrame);
MoveTo(MemSizeLeft, MemSizeBottom); (* Now, get ready to draw the memory information *)
promptString := GetString(128);
HLock(Handle(promptString)); (* Lock the string, as DrawString might cause Handles to be moved *)
DrawString(promptString^^);
HUnlock(Handle(promptString)); (* unlock it to prevent memory fragmentation *)
NumToString(CurrFreeMem, memSizeString); (* Now convert our free memory figure into a string *)
DrawString(memSizeString); (* and draw it at the current pen position *)
(* (right after the prompt) *)
END; (* DrawAboutWindow *)
PROCEDURE UpdateWindow;
(* This only gets called if the window doesn't have a picture attached to it and we need to *)
(* redraw the window's contents *)
VAR
currWindow : WindowPeek;
BEGIN
BeginUpdate(whichWindow); (* Set the visRgn to this window's update region *)
SetPort(whichWindow); (* Switch to our destination window *)
EraseRect(whichWindow^.portRect); (* Erase any old information that may be there *)
currWindow := WindowPeek(whichWindow);
IF (currWindow^.refCon = wAbout) THEN (* Dispatch to the appropriate drawing routine *)
DrawAboutWindow
ELSE
DrawFontGrid(whichWindow^.txFont, whichWindow^.txSize);
EndUpdate(whichWindow); (* And remove this update region from the one maintained *)
(* by the Event Manager *)
END; (* UpdateWindow *)
PROCEDURE ActivateWindow;
(* This procedure sets the internal Font and Size indiocators to reflect the settings of the *)
(* frontmost window. Since this unit can't access the Menus unit, we'll have to adjust the *)
(* menus from within the main loop. *)
BEGIN
IF (MakeActive) AND (whichWindow^.refCon = wFont) THEN
BEGIN (* A Font window just came to the front *)
currFont := whichWindow^.port.txFont;
currSize := whichWindow^.port.txSize;
END;
END; (* ActivateWindow *)
END.