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

Gordon Ramsay DASH: Guide to upgrading a...
If we've learned anything about celebrity chef Gordon Ramsay over the years, it's that you don't want him angry and breathing down your neck. He's not above calling you out on TV, making a mockery of your efforts in the kitchen in front of... | Read more »
Galaxy of Trian (Games)
Galaxy of Trian 1.1.0 Device: iOS Universal Category: Games Price: $6.99, Version: 1.1.0 (iTunes) Description: Galaxy of Trian is an exciting, fast paced digital board game based on the highly acclaimed tabletop title. | Read more »
Dead In Bermuda (Games)
Dead In Bermuda 1.0 Device: iOS Universal Category: Games Price: $4.99, Version: 1.0 (iTunes) Description: | Read more »
The Little Fox (Games)
The Little Fox 1.0.1 Device: iOS Universal Category: Games Price: $2.99, Version: 1.0.1 (iTunes) Description: The Little Fox is an alternative perspective on the world-renowned ‘fairy tale for adults', The Little Prince by Antoine de... | Read more »
5 popular free fertility apps
There was a good article this week in The Independent about how more women are using fertility appsas a de facto form of contraception. It's apparently not working too well, leading to numerous unwanted pregnancies. [Read more] | Read more »
How to get more cars in CSR Racing 2
NaturalMotion and Zynga brought a lot of real life cars to the table for CSR Racing 2. From souped up everyday rides made by Nissan and Hyundai to supercars produced by the likes of McLaren and Pagani, there really is something for everyone. [... | Read more »
Crypt of the NecroDancer Pocket Edition...
Crypt of the NecroDancer Pocket Edition 1.0 Device: iOS Universal Category: Games Price: $4.99, Version: 1.0 (iTunes) Description: Crypt of the NecroDancer is an award winning hardcore roguelike rhythm game. Move to the music and... | Read more »
Gear-grinding puzzle title Inner Circle...
If you saw our post earlier this month announcing the imminent release of ZPlay’s new creation, Inner Circle, you’ll be happy to know that it’s now available on the App Store. Established in 2010, developer and publisher ZPlay have taken the... | Read more »
CSR Racing 2: Your guide to what's...
CSR Racing 2, or CSR2, as it likes to call itself, has finally arrived. The follow-up to the immensely popular drag racing game CSR Racing is the first release from NaturalMotion since the studio's acquisition by Zynga in early 2014. [Read more] | Read more »
Nanuleu (Games)
Nanuleu 1.1 Device: iOS Universal Category: Games Price: $2.99, Version: 1.1 (iTunes) Description: Nanuleu is a strategy game where you take control of ancient magical trees that protect the land from an invading dark force. A... | Read more »

Price Scanner via MacPrices.net

July 4th sale: $100 off 13-inch MacBook Airs
Amazon has 13″ MacBook Airs on sale for $100 off MSRP for a limited time. Shipping is free: - 13″ 1.6GHz/128GB MacBook Air (sku MMGF2LL/A): $899.99 $100 off MSRP - 13″ 1.6GHz/256GB MacBook Air (sku... Read more
Swiftpoint Launches Advanced Pivot, Tilt And...
Christchurch, New Zealand based Swiftpoint has announced the launch of its new generation computer mouse, The Z, on the crowdfunding website kickstarter.com. The company’s previous device, the... Read more
Clearance 12-inch Retina MacBooks, Apple refu...
Apple has Certified Refurbished 2015 12″ Retina MacBooks available starting at $929. Apple will include a standard one-year warranty with each MacBook, and shipping is free. The following... Read more
12-inch MacBooks available with free bundles...
Adorama has 12″ Retina MacBooks available including free shipping plus NY & NJ sales tax only. For a limited time, Adorama will include a free Apple USB-C to USB Adapter, free 4-Port USB Hub, and... Read more
Das Keyboard Unveils First Cloud-Connected Ke...
Austin, Texas based Das Keyboard has unveiled the newest addition to its family of high-performance mechanical keyboards with the introduction of the Das Keyboard 5Q on Kickstarter. Built with... Read more
13-inch 2.7GHz Retina MacBook Pros on sale fo...
Adorama has 13″ 2.7GHz Retina MacBook Pros on sale for up to $130 off MSRP. Shipping is free, and Adorama charges NY & NJ sales tax only: - 13″ 2.7GHz/128GB Retina MacBook Pro: $1169 $130 off -... Read more
New App Reminds Us to Put Down Our Phones and...
Mode, a new smartphone app that makes us more mindful of how we use our devices, debuts in the app stores today. The Mode app tracks time spent in different modes of day-to-day life without... Read more
ZuumSpeed Personalized Speedometer + HUD For...
RMKapps has announced the release and immediate availability of ZuumSpeed 1.0, its personalized speedometer plus heads up display for iOS devices. ZuumSpeed gives users over 18 custom fonts available... Read more
Apple refurbished clearance 15-inch Retina Ma...
Apple has Certified Refurbished 2014 15″ 2.2GHz Retina MacBook Pros available for $1609, $390 off original MSRP. Apple’s one-year warranty is included, and shipping is free. They have refurbished 15... Read more
9-inch 128GB Silver iPad Pro on sale for $50...
B&H Photo has the 9.7″ 128GB Silver Apple iPad Pro on sale for $699 including free shipping plus NY tax only. Their price is $50 off MSRP. Read more

Jobs Board

*Apple* Retail - Multiple Positions - Apple,...
Job Description: Sales Specialist - Retail Customer Service and Sales Transform Apple Store visitors into loyal Apple customers. When customers enter the store, Read more
*Apple* iPhone 6s and New Products Tester Ne...
…we therefore look forward to put out products to quality test for durability. Apple leads the digital music revolution with its iPods and iTunes online store, Read more
*Apple* Retail - Multiple Positions, Fort Wo...
Sales Specialist - Retail Customer Service and Sales Transform Apple Store visitors into loyal Apple customers. When customers enter the store, you're also the Read more
*Apple* Retail - Multiple Positions - Apple,...
Job Description: Sales Specialist - Retail Customer Service and Sales Transform Apple Store visitors into loyal Apple customers. When customers enter the store, Read more
*Apple* iPhone 6s and New Products Tester Ne...
…we therefore look forward to put out products to quality test for durability. Apple leads the digital music revolution with its iPods and iTunes online store, Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.