TweetFollow Us on Twitter

TextBoxer
Volume Number:8
Issue Number:3
Column Tag:Getting Started

Related Info: Quickdraw TextEdit Window Manager

TextBoxer

A vehicle for experimenting with QuickDraw's text and shape-drawing routines

By Dave Mark, MacTutor Regular Contributing Author

Note: Source code files accompanying article are located on MacTech CD-ROM or source code disks.

About the author

Dave Mark is an accomplished Macintosh author and an Apple Partner. He is the author of The Macintosh Programming Primer Series which includes: Macintosh C Programming Primer, Volumes 1 and 2; Macintosh Pascal Programming Primer, Volume 1, and his latest book, Learn C on the Macintosh. These books are available through the MacTutor Mail Order Store located in the back of the magazine. Dave is also the “professor” on the Learn Programming Forum on CompuServe. To get there, type GO MACDEV, then check out section 11.

In last months column, we covered the basics of programming using windows and QuickDraw. The Macintosh Toolbox was introduced, and a function was presented that properly initializes the Toolbox. This month, we’ll dig a little deeper into the relationship between windows and QuickDraw.

TextBoxer: Still Life With Text and QuickDraw

This months application, TextBoxer, gives you a vehicle to experiment with QuickDraw’s text and shape-drawing routines. In its initial incarnation, TextBoxer creates the window shown in Figure 1. Notice that the content region of the window contains two rectangle (one inside the other), as well as a text string.

Figure 1. TextBoxer in action.

Creating the TextBoxer Project

Launch THINK C, creating a new project called TextBoxer.Π (The Π character is created by typing option-p). THINK C will create a project window with the title TextBoxer.Π. Select New from the File menu to create a new source code window. Type the following source code into the window:

/* 1*/

#define kVisible false
#define kMoveToFront (WindowPtr)-1L
#define kNoGoAwayfalse
#define kNilRefCon 0L
#define kPascalString“\pAll applaud the strongly-jawed”
#define kFontSize12
#define kBottomOffset7
#define kLeftOffset7

void    ToolBoxInit( void );
WindowPtr WindowInit( void );

/****************** main ************/
main()
{
 Rect   shapeRect;
 WindowPtrwindow;
 
 ToolBoxInit();
 window = WindowInit();
 
 shapeRect = window->portRect;
 
 InsetRect( &shapeRect, 5, 5 );
 FrameRect( &shapeRect );
 
 InsetRect( &shapeRect, 2, 2 );
 FrameRect( &shapeRect );
 
 TextFont( monaco );
 TextSize( kFontSize );
 MoveTo( shapeRect.left + kLeftOffset,
 shapeRect.bottom - kBottomOffset );
 DrawString( kPascalString );
 
 while ( ! Button() ) ;
}

/****************** ToolBoxInit ***********/
void  ToolBoxInit( void )
{
 InitGraf( &thePort );
 InitFonts();
 InitWindows();
 InitMenus();
 TEInit();
 InitDialogs( nil );
 InitCursor();
}
/****************** WindowInit *************/
WindowPtr WindowInit( void )
{
 WindowPtrwindow;
 Rect   windowRect;
 
 SetRect( &windowRect, 20, 40, 260, 74 );

 window = NewWindow( nil, &windowRect, “\pBox o’ Text”,
 kVisible, documentProc, kMoveToFront,
 kNoGoAway, kNilRefCon );
 
 if ( window == nil )
 {
 SysBeep( 10 );  /*  Couldn’t create a window!!!  */
 ExitToShell();
 }
 
 ShowWindow( window );
 SetPort( window );
 
 return( window );
}

Select Save from the File menu and save the source code under the name TextBoxer.c. Next, select Add (not Add...) from the Source menu to add TextBoxer.c to the project. Finally, select Add... from the Source menu and add the MacTraps library to the project. You’ll find MacTraps inside your Development folder, inside the THINK C Folder, inside the Mac Libraries folder. As mentioned last month, MacTraps contains the interfaces to the routines that make up the Macintosh Toolbox.

Once MacTraps has been added to the project, the project window should look like the one shown in Figure 2.

Figure 2. The TextBoxer project window, before compilation.

Running TextBoxer.Π

Select Run from the Project menu, asking THINK C to compile and run your project. If you run into any compile or link errors, check the code over carefully. Once your project runs, you should see something similar to Figure 3. To exit TextBoxer, just click the mouse button.

Figure 3. Running TextBoxer.

Walking Through the Source Code

TextBoxer.c consists of three routines, main(), ToolBoxInit(), and WindowInit(). As usual, we start off by defining some useful constants. I’ll explain each of these as they occur in context.

/* 2 */

#define kVisible false
#define kMoveToFront (WindowPtr)-1L
#define kNoGoAwayfalse
#define kNilRefCon 0L

#define kPascalString“\pAll applaud the strongly-jawed”
#define kFontSize12
#define kBottomOffset7
#define kLeftOffset7

Next come the function prototypes. Be sure to prototype all your functions. This practice will go a long way towards catching compile errors.

/* 3 */

void    ToolBoxInit( void );
WindowPtr WindowInit( void );

main() starts off with a couple of local variable declarations. shapeRect is declared to be of type Rect. Rect is a widely used Toolbox type and is defined in Inside Macintosh. A Rect has four fields: left, top, right, and bottom. Typically, you’ll fill a Rect’s fields so they define the position and size of a rectangle.

You can set the fields of a Rect individually, like this:

/* 4 */

Rect  myRect;

myRect.left = 20;
myRect.top = 30;
myRect.right = 40;
myRect.bottom = 50;

or you can use a Toolbox routine like SetRect(). SetRect() is defined in IM(I:174):

/* 5 */

SetRect( Rect *myRect, int left, int top, int right, int bottom );

The second local variable in main() is window, used to store a pointer to the TextBoxer window.

/* 6 */

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

main()
{
 Rect   shapeRect;
 WindowPtrwindow;

Next, main() calls ToolBoxInit() to initialize the Macintosh Toolbox. As mentioned last month, with few exceptions, every Mac program you write will start off this way. Once the Toolbox is initialized, you can call the Toolbox as much as you like.

/* 7 */

 ToolBoxInit();

Once the Toolbox is initialized, we’ll call WindowInit() to create our window. WindowInit() returns a WindowPtr, an extremely important Toolbox data type. A WindowPtr is a pointer to a GrafPort, QuickDraw’s basic data structure:

/* 8 */

struct GrafPort {
    short device;
    BitMap portBits;
    Rect portRect;
    RgnHandle visRgn;
    RgnHandle clipRgn;
    Pattern bkPat;
    Pattern fillPat;
    Point pnLoc;
    Point pnSize;
    short pnMode;
    Pattern pnPat;
    short pnVis;
    short txFont;
    Style txFace;
    char filler;
    short txMode;
    short txSize;
    Fixed spExtra;
    long fgColor;
    long bkColor;
    short colrBit;
    short patStretch;
    Handle picSave;
    Handle rgnSave;
    Handle polySave;
    QDProcsPtr grafProcs;
};
typedef GrafPort *GrafPtr;
typedef GrafPtr WindowPtr;

Typically, you’ll create a GrafPort, customize it, draw in it, and eventually dispose of it. When you create a new window, a GrafPort is automatically created for you. For example, the Toolbox function NewWindow() creates a WindowRecord:

/* 9 */

struct WindowRecord {
    GrafPort port;
    short windowKind;
    Boolean visible;
    Boolean hilited;
    Boolean goAwayFlag;
    Boolean spareFlag;
    RgnHandle strucRgn;
    RgnHandle contRgn;
    RgnHandle updateRgn;
    Handle windowDefProc;
    Handle dataHandle;
    StringHandle titleHandle;
    short titleWidth;
    ControlHandle controlList;
    struct WindowRecord *nextWindow;
    PicHandle windowPic;
    long refCon;
};

typedef struct WindowRecord WindowRecord;
typedef WindowRecord *WindowPeek;

Notice that the first field in the WindowRecord is a GrafPort. The WindowPtr returned by NewWindow() is actually a pointer to this GrafPort. You can cast the WindowPtr to the type WindowPeek when you want to access the rest of the fields in the WindowRecord.

Though this may seem confusing, it’s actually quite easy, once you get used to it. As we go over more and more examples, you’ll learn how to create and manage your own windows and GrafPorts. Let’s get back to the TextBoxer code.

As we said earlier, WindowInit() creates a new WindowRecord (and, therefore, a GrafPort as well). The WindowPtr returned by WindowInit() is a pointer to the GrafPort embedded in the WindowRecord.

/* 10 */

 window = WindowInit();

The window’s portRect field is a Rect that defines the boundary of the window in screen pixels. On a typical Macintosh, the upper left corner of the screen corresponds to the (x,y) coordinate 0, 0. As you move to the right, the x coordinate increases. As you move down the screen, the y coordinate increases. The coordinates of the main screen serve as a reference point to all the GrafPorts on the screen and are known as global coordinates. Each GrafPort you create has its own coordinate system, known as local coordinates.

Figure 4 shows the point (0,0) in global coordinates. It also shows the point (0,0) in a window’s local coordinate system. Typically, a window’s local coordinates start in the upper left corner of the window’s content region. The content region starts just below the window’s title bar, if it has one.

The window’s portRect field is copied into a local variable, shapeRect. We’ll inset the Rect (make it uniformally smaller) by 5 pixels in each direction, then call the drawing routine FrameRect() to draw a one pixel rectangle using this inset Rect as a guide. This rectangle will appear 5 pixels inside the border of the window’s content region.

/* 11 */

 shapeRect = window->portRect;
 
 InsetRect( &shapeRect, 5, 5 );
 FrameRect( &shapeRect );

Figure 4. The point (0,0) in both global and local coordinates.

Next, we’ll inset the Rect 2 more pixels and frame another rectangle inside the first. InsetRect() is described in IM(I:175). FrameRect() is described in IM(I:176). Later in the column, we’ll discuss some of the other functions that relate to drawing.

/* 12 */

 InsetRect( &shapeRect, 2, 2 );
 FrameRect( &shapeRect );

Once the rectangles are drawn, we’re ready to tackle the text. First, we’ll set the current font to monaco, then we’ll set the font size to kFontSize. It’s important to note that we’ve only made this change to the current port. If we had two windows set up, we could set one window to use 18 point Geneva, and the other to 24 point Times. You’ll see how to set the current port when we discuss WindowInit()

/* 13 */

 TextFont( monaco );
 TextSize( kFontSize );

Every GrafPort has a pen associated with it. The location of the pen determines where the next drawing operation will take place. Several of the QuickDraw drawing routines produce results based strictly on the location of this pen. One of these routines is DrawString(), a routine that draws a pascal string in the current port, at the current pen location. The function MoveTo() sets the pen location using the local coordinates of the current GrafPort.

/* 14 */

 MoveTo( shapeRect.left + kLeftOffset, shapeRect.bottom - kBottomOffset 
);

DrawString() draws the text using the current pen location as the left side of the baseline of the first character in the specified string. Remember, pascal strings start with a length byte, followed by that number of characters (up to 255). In THINK C, you can specify a pascal string by starting your string with the characters \p (look at the #define for kPascalString above).

/* 15 */

 DrawString( kPascalString );

Finally, leave the window up there till the mouse button is clicked.

/* 16 */

 while ( ! Button() ) ;
}

ToolBoxInit() is the same as it was in last month’s column.

/* 17 */


/****************** ToolBoxInit ***********/

void  ToolBoxInit( void )
{
 InitGraf( &thePort );
 InitFonts();
 InitWindows();
 InitMenus();
 TEInit();
 InitDialogs( nil );
 InitCursor();
}

WindowInit() will create a new window and return a pointer to it.

/* 18 */

/****************** WindowInit *************/

WindowPtr WindowInit( void )
{
 WindowPtrwindow;
 Rect   windowRect;

For starters, SetRect() is used to set windowRect to the global coordinates we’d like our window to appear at.

/* 19 */

 SetRect( &windowRect, 20, 40, 260, 74 );

Next, NewWindow() is called to create the new window. Check out last months column for more info on NewWindow() and its parameters.

/* 20 */

 window = NewWindow( nil, &windowRect, "\pBox o’ Text",
 kVisible, documentProc, kMoveToFront,
 kNoGoAway, kNilRefCon );

If the window could not be created, NewWindow() will return nil. In that case, we beep once and exit.

/* 21 */

 if ( window == nil )
 {
 SysBeep( 10 );  /*  Couldn't create a window!!!  */
 ExitToShell();
 }

Since the constant kVisible (passed as a parameter to NewWindow()) was set to false, the window is not visible upon creation. That’s ShowWindow()’s job! ShowWindow() makes the specified window visible and HideWindow() makes the window invisible.

Try commenting out the call to ShowWindow() to find out what an invisible window looks like.

/* 22 */

 ShowWindow( window );

SetPort() makes the specified window the current port. Use SetPort() to switch between multiple GrafPorts.

/* 23 */

 SetPort( window );

Finally, we return the pointer to our newly created window.

/* 24 */

 return( window );
}

More Routines to Play With

QuickDraw allows you to do a lot more than frame rectangles. On one hand, you can use routines such as FrameOval(), FrameRoundRect(), and FrameArc() to frame each of the different QuickDraw shapes. On the other hand, for each shape you can perform paint, erase, invert, and fill operations in addition to the framing already discussed. For example, check out the QuickDraw routines PaintRect(), EraseRect(), InvertRect(), and FillRect().

These routines are completely described in Inside Macintosh, Volume I, Chapter 6. Be sure to check the parameters for each routine. Different shapes require different parameters.

I would strongly recommend that you read the aforementioned QuickDraw chapter from cover to cover. Play around with TextBoxer. Try different fonts and font sizes. Take a look at the file Quickdraw.h found in the THINK C Folder, in the Mac #includes folder, inside the Apple #includes folder. You’ll find constants for the basic Mac fonts and a list of the different QuickDraw Toolbox routines.

Next Month...

In next month’s column, we’ll poke around some of QuickDraw’s nooks and crannies. We’ll also learn about resources, the Mac’s mechanism for separating data from code. For those of you on baby-watch, there are only eight more weeks to go!!! Got any suggestions for the best type of car seat, crib, swing, diapers, bottles, etc. to buy? Let me know. I could sure use the help!

As always, you can reach me on CompuServe in MACDEV, Section 11 (Learn Programming).

 

Community Search:
MacTech Search:

Software Updates via MacUpdate

Latest Forum Discussions

See All

Fresh From the Land Down Under – The Tou...
After a two week hiatus, we are back with another episode of The TouchArcade Show. Eli is fresh off his trip to Australia, which according to him is very similar to America but more upside down. Also kangaroos all over. Other topics this week... | Read more »
TouchArcade Game of the Week: ‘Dungeon T...
I’m a little conflicted on this week’s pick. Pretty much everyone knows the legend of Dungeon Raid, the match-3 RPG hybrid that took the world by storm way back in 2011. Everyone at the time was obsessed with it, but for whatever reason the... | Read more »
SwitchArcade Round-Up: Reviews Featuring...
Hello gentle readers, and welcome to the SwitchArcade Round-Up for July 19th, 2024. In today’s article, we finish up the week with the unusual appearance of a review. I’ve spent my time with Hot Lap Racing, and I’m ready to give my verdict. After... | Read more »
Draknek Interview: Alan Hazelden on Thin...
Ever since I played my first release from Draknek & Friends years ago, I knew I wanted to sit down with Alan Hazelden and chat about the team, puzzle games, and much more. | Read more »
The Latest ‘Marvel Snap’ OTA Update Buff...
I don’t know about all of you, my fellow Marvel Snap (Free) players, but these days when I see a balance update I find myself clenching my… teeth and bracing for the impact to my decks. They’ve been pretty spicy of late, after all. How will the... | Read more »
‘Honkai Star Rail’ Version 2.4 “Finest D...
HoYoverse just announced the Honkai Star Rail (Free) version 2.4 “Finest Duel Under the Pristine Blue" update alongside a surprising collaboration. Honkai Star Rail 2.4 follows the 2.3 “Farewell, Penacony" update. Read about that here. | Read more »
‘Vampire Survivors+’ on Apple Arcade Wil...
Earlier this month, Apple revealed that poncle’s excellent Vampire Survivors+ () would be heading to Apple Arcade as a new App Store Great. I reached out to poncle to check in on the DLC for Vampire Survivors+ because only the first two DLCs were... | Read more »
Homerun Clash 2: Legends Derby opens for...
Since launching in 2018, Homerun Clash has performed admirably for HAEGIN, racking up 12 million players all eager to prove they could be the next baseball champions. Well, the title will soon be up for grabs again, as Homerun Clash 2: Legends... | Read more »
‘Neverness to Everness’ Is a Free To Pla...
Perfect World Games and Hotta Studio (Tower of Fantasy) announced a new free to play open world RPG in the form of Neverness to Everness a few days ago (via Gematsu). Neverness to Everness has an urban setting, and the two reveal trailers for it... | Read more »
Meditative Puzzler ‘Ouros’ Coming to iOS...
Ouros is a mediative puzzle game from developer Michael Kamm that launched on PC just a couple of months back, and today it has been revealed that the title is now heading to iOS and Android devices next month. Which is good news I say because this... | Read more »

Price Scanner via MacPrices.net

Amazon is still selling 16-inch MacBook Pros...
Prime Day in July is over, but Amazon is still selling 16-inch Apple MacBook Pros for $500-$600 off MSRP. Shipping is free. These are the lowest prices available this weekend for new 16″ Apple... Read more
Walmart continues to sell clearance 13-inch M...
Walmart continues to offer clearance, but new, Apple 13″ M1 MacBook Airs (8GB RAM, 256GB SSD) online for $699, $300 off original MSRP, in Space Gray, Silver, and Gold colors. These are new MacBooks... Read more
Apple is offering steep discounts, up to $600...
Apple has standard-configuration 16″ M3 Max MacBook Pros available, Certified Refurbished, starting at $2969 and ranging up to $600 off MSRP. Each model features a new outer case, shipping is free,... Read more
Save up to $480 with these 14-inch M3 Pro/M3...
Apple has 14″ M3 Pro and M3 Max MacBook Pros in stock today and available, Certified Refurbished, starting at $1699 and ranging up to $480 off MSRP. Each model features a new outer case, shipping is... Read more
Amazon has clearance 9th-generation WiFi iPad...
Amazon has Apple’s 9th generation 10.2″ WiFi iPads on sale for $80-$100 off MSRP, starting only $249. Their prices are the lowest available for new iPads anywhere: – 10″ 64GB WiFi iPad (Space Gray or... Read more
Apple is offering a $50 discount on 2nd-gener...
Apple has Certified Refurbished White and Midnight HomePods available for $249, Certified Refurbished. That’s $50 off MSRP and the lowest price currently available for a full-size Apple HomePod today... Read more
The latest MacBook Pro sale at Amazon: 16-inc...
Amazon is offering instant discounts on 16″ M3 Pro and 16″ M3 Max MacBook Pros ranging up to $400 off MSRP as part of their early July 4th sale. Shipping is free. These are the lowest prices... Read more
14-inch M3 Pro MacBook Pros with 36GB of RAM...
B&H Photo has 14″ M3 Pro MacBook Pros with 36GB of RAM and 512GB or 1TB SSDs in stock today and on sale for $200 off Apple’s MSRP, each including free 1-2 day shipping: – 14″ M3 Pro MacBook Pro (... Read more
14-inch M3 MacBook Pros with 16GB of RAM on s...
B&H Photo has 14″ M3 MacBook Pros with 16GB of RAM and 512GB or 1TB SSDs in stock today and on sale for $150-$200 off Apple’s MSRP, each including free 1-2 day shipping: – 14″ M3 MacBook Pro (... Read more
Amazon is offering $170-$200 discounts on new...
Amazon is offering a $170-$200 discount on every configuration and color of Apple’s M3-powered 15″ MacBook Airs. Prices start at $1129 for models with 8GB of RAM and 256GB of storage: – 15″ M3... Read more

Jobs Board

*Apple* Systems Engineer - Chenega Corporati...
…LLC,** a **Chenega Professional Services** ' company, is looking for a ** Apple Systems Engineer** to support the Information Technology Operations and Maintenance Read more
Solutions Engineer - *Apple* - SHI (United...
**Job Summary** An Apple Solution Engineer's primary role is tosupport SHI customers in their efforts to select, deploy, and manage Apple operating systems and Read more
*Apple* / Mac Administrator - JAMF Pro - Ame...
Amentum is seeking an ** Apple / Mac Administrator - JAMF Pro** to provide support with the Apple Ecosystem to include hardware and software to join our team and Read more
Operations Associate - *Apple* Blossom Mall...
Operations Associate - Apple Blossom Mall Location:Winchester, VA, United States (https://jobs.jcp.com/jobs/location/191170/winchester-va-united-states) - Apple Read more
Cashier - *Apple* Blossom Mall - JCPenney (...
Cashier - Apple Blossom Mall Location:Winchester, VA, United States (https://jobs.jcp.com/jobs/location/191170/winchester-va-united-states) - Apple Blossom Mall Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.