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

Adobe After Effects CC 2018 16.1.3 - Cre...
After Effects CC 2018 is available as part of Adobe Creative Cloud for $52.99/month (or $20.99/month for a single app license). The new, more connected After Effects CC 2018 can make the impossible... Read more
Adobe Audition CC 2019 12.1.4 - Professi...
Audition CC 2019 is available as part of Adobe Creative Cloud for as little as $20.99/month (or $9.99/month if you're a previous Audition customer). Adobe Audition CC 2019 empowers you to create and... Read more
Adobe Premiere Pro CC 2019 13.1.5 - Digi...
Premiere Pro CC 2019 is available as part of Adobe Creative Cloud for as little as $52.99/month. The price on display is a price for annual by-monthly plan for Adobe Premiere Pro only Adobe Premiere... Read more
Navicat Premium Essentials 12.1.25 - Pro...
Navicat Premium Essentials is a compact version of Navicat which provides basic and necessary features you will need to perform simple administration on a database. It supports the latest features... Read more
Sketch 58 - Design app for UX/UI for iOS...
Sketch is an innovative and fresh look at vector drawing. Its intentionally minimalist design is based upon a drawing space of unlimited size and layers, free of palettes, panels, menus, windows, and... Read more
ClipGrab 3.8.5 - Download videos from Yo...
ClipGrab is a free downloader and converter for YouTube, Vimeo, Facebook and many other online video sites. It converts downloaded videos to MPEG4, MP3 or other formats in just one easy step Version... Read more
Dash 4.6.6 - Instant search and offline...
Dash is an API documentation browser and code snippet manager. Dash helps you store snippets of code, as well as instantly search and browse documentation for almost any API you might use (for a full... Read more
FotoMagico 5.6.8 - Powerful slideshow cr...
FotoMagico lets you create professional slideshows from your photos and music with just a few, simple mouse clicks. It sports a very clean and intuitive yet powerful user interface. High image... Read more
Civilization VI 1.2.4 - Next iteration o...
Sid Meier’s Civilization VI is the next entry in the popular Civilization franchise. Originally created by legendary game designer Sid Meier, Civilization is a strategy game in which you attempt to... Read more
Skype 8.52.0.138 - Voice-over-internet p...
Skype allows you to talk to friends, family and co-workers across the Internet without the inconvenience of long distance telephone charges. Using peer-to-peer data transmission technology, Skype... Read more

Latest Forum Discussions

See All

Lots of premium games are going free (so...
You may have seen over the past couple weeks a that a bunch of premium games have suddenly become free. This isn’t a mistake, nor is it some last hurrah before Apple Arcade hits, and it’s important to know that these games aren’t actually becoming... | Read more »
Yoozoo Games launches Saint Seiya Awaken...
If you’re into your anime, you’ve probably seen or heard of Saint Seiya. Based on a shonen manga by Masami Kurumada, the series was massively popular in the 1980s – especially in its native Japan. Since then, it’s grown into a franchise of all... | Read more »
Five Nights at Freddy's AR: Special...
Five Nights at Freddy's AR: Special Delivery is a terrifying new nightmare from developer Illumix. Last week, FNAF fans were sent into a frenzy by a short teaser for what we now know to be Special Delivery. Those in the comments were quick to... | Read more »
Rush Rally 3's new live events are...
Last week, Rush Rally 3 got updated with live events, and it’s one of the best things to happen to racing games on mobile. Prior to this update, the game already had multiplayer, but live events are more convenient in the sense that it’s somewhat... | Read more »
Why your free-to-play racer sucks
It’s been this way for a while now, but playing Hot Wheels Infinite Loop really highlights a big issue with free-to-play mobile racing games: They suck. It doesn’t matter if you’re trying going for realism, cart racing, or arcade nonsense, they’re... | Read more »
Steam Link Spotlight - The Banner Saga 3
Steam Link Spotlight is a new feature where we take a look at PC games that play exceptionally well using the Steam Link app. Our last entry talked about Terry Cavanaugh’s incredible Dicey Dungeons. Read about how it’s a great mobile experience... | Read more »
Combo Quest (Games)
Combo Quest 1.0 Device: iOS Universal Category: Games Price: $.99, Version: 1.0 (iTunes) Description: Combo Quest is an epic, time tap role-playing adventure. In this unique masterpiece, you are a knight on a heroic quest to retrieve... | Read more »
Hero Emblems (Games)
Hero Emblems 1.0 Device: iOS Universal Category: Games Price: $2.99, Version: 1.0 (iTunes) Description: ** 25% OFF for a limited time to celebrate the release ** ** Note for iPhone 6 user: If it doesn't run fullscreen on your device... | Read more »
Puzzle Blitz (Games)
Puzzle Blitz 1.0 Device: iOS Universal Category: Games Price: $1.99, Version: 1.0 (iTunes) Description: Puzzle Blitz is a frantic puzzle solving race against the clock! Solve as many puzzles as you can, before time runs out! You have... | Read more »
Sky Patrol (Games)
Sky Patrol 1.0.1 Device: iOS Universal Category: Games Price: $1.99, Version: 1.0.1 (iTunes) Description: 'Strategic Twist On The Classic Shooter Genre' - Indie Game Mag... | Read more »

Price Scanner via MacPrices.net

$250 prepaid Visa card with any Apple iPhone,...
Xfinity Mobile will include a free $250 prepaid Visa card with the purchase of any new iPhone, new line activation, and transfer of phone number to Xfinity Mobile. Offer is valid through October 27,... Read more
Sprint is offering the 64GB Apple iPhone 11 P...
Sprint has the new 64GB iPhone 11 Pro available for $12.50 per month for new customers with an eligible trade-in in of iPhone 7 or newer. That’s down from their standard monthly lease of $41.67. The... Read more
Final week: Apple’s 2019 Back to School Promo...
Purchase a new Mac using Apple’s Education discount, and take up to $400 off MSRP. All teachers, students, and staff of any educational institution with a .edu email address qualify for the discount... Read more
Save $30 on Apple’s AirPods at these reseller...
Amazon is offering discounts on new 2019 Apple AirPods ranging up to $30 off MSRP as part of their Labor Day sale. Shipping is free: – AirPods with Charging Case: $144.95 $15 off MSRP – AirPods with... Read more
Preorder your Apple Watch Series 5 today at A...
Amazon has Apple Watch Series 5 GPS models available for preorder and on sale today for $15 off Apple’s MSRP. Shipping is free and starts on September 20th: – 40mm Apple Watch Series 5 GPS: $384.99 $... Read more
21″ iMacs on sale for $100 off Apple’s MSRP,...
B&H Photo has new 21″ Apple iMacs on sale for $100 off MSRP with models available starting at $999. These are the same iMacs offered by Apple in their retail and online stores. Overnight shipping... Read more
2018 4 and 6-Core Mac minis on sale today for...
Apple resellers are offering new 2018 4-Core and 6-Core Mac minis for $100-$150 off MSRP for a limited time. B&H Photo has the new 2018 4-Core and 6-Core Mac minis on sale for up to $150 off... Read more
Save $150-$250 on 10.2″ WiFi + Cellular iPads...
Verizon is offering $150-$250 discounts on Apple’s new 10.2″ WiFi + Cellular iPad with service. Buy the iPad itself and save $150. Save $250 on the purchase of an iPad along with an iPhone. The fine... Read more
Apple continues to offer 13″ 2.3GHz Dual-Core...
Apple has Certified Refurbished 2017 13″ 2.3GHz Dual-Core non-Touch Bar MacBook Pros available starting at $1019. An standard Apple one-year warranty is included with each model, outer cases are new... Read more
Apple restocks 2018 MacBook Airs, Certified R...
Apple has restocked Certified Refurbished 2018 13″ MacBook Airs starting at only $849. Each MacBook features a new outer case, comes with a standard Apple one-year warranty, and is shipped free. The... Read more

Jobs Board

Student Employment (Blue *Apple* Cafe) Spri...
Student Employment (Blue Apple Cafe) Spring 2019 Penn State University Campus/Location: Penn State Brandywine Campus City: Media, PA Date Announced: 12/20/2018 Date Read more
Geek Squad *Apple* Master Consultation Agen...
**732907BR** **Job Title:** Geek Squad Apple Master Consultation Agent **Job Category:** Services/Installation/Repair **Location Number:** 000360-Williston-Store Read more
*Apple* Mobile Master - Best Buy (United Sta...
**728519BR** **Job Title:** Apple Mobile Master **Job Category:** Store Associates **Location Number:** 000853-Jackson-Store **Job Description:** **What does a Best Read more
*Apple* Mobility Pro - Best Buy (United Stat...
**733006BR** **Job Title:** Apple Mobility Pro **Job Category:** Store Associates **Location Number:** 000865-Conroe-Store **Job Description:** At Best Buy, our Read more
*Apple* Mobility Pro-Store 149 - Best Buy (U...
**731985BR** **Job Title:** Apple Mobility Pro-Store 149 **Job Category:** Store Associates **Location Number:** 000149-Towson-Store **Job Description:** At Best Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.