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

Apple Keynote 7.3 - Apple's present...
Easily create gorgeous presentations with the all-new Keynote, featuring powerful yet easy-to-use tools and dazzling effects that will make you a very hard act to follow. The Theme Chooser lets you... Read more
Apple Numbers 4.3 - Apple's spreads...
With Apple Numbers, sophisticated spreadsheets are just the start. The whole sheet is your canvas. Just add dramatic interactive charts, tables, and images that paint a revealing picture of your data... Read more
Apple Pages 6.3 - Apple's word proc...
Apple Pages is a powerful word processor that gives you everything you need to create documents that look beautiful. And read beautifully. It lets you work seamlessly between Mac and iOS devices, and... Read more
Smultron 9.4.2 - Easy-to-use, powerful t...
Smultron 9 is an elegant and powerful text editor that is easy to use. Use it to create or edit any text document. Everything from a web page, a note or a script to any single piece of text or code.... Read more
Xcode 9.0 - Integrated development envir...
Xcode includes everything developers need to create great applications for Mac, iPhone, iPad, and Apple Watch. Xcode provides developers a unified workflow for user interface design, coding, testing... Read more
iShowU Instant 1.2.0 - Full-featured scr...
iShowU Instant gives you real-time screen recording like you've never seen before! It is the fastest, most feature-filled real-time screen capture tool from shinywhitebox yet. All of the features you... Read more
Apple Safari 11.0 - Apple's Web bro...
Note: The direct download link is currently unavailable. It is available in the OS X 10.12.6 release, as well as in the Apple Security Updates. Apple Safari is Apple's web browser that comes with... Read more
Typinator 7.3 - Speedy and reliable text...
Typinator turbo-charges your typing productivity. Type a little. Typinator does the rest. We've all faced projects that require repetitive typing tasks. With Typinator, you can store commonly used... Read more
ExpanDrive 6.0.16 - Access cloud storage...
ExpanDrive builds cloud storage in every application, acts just like a USB drive plugged into your Mac. With ExpanDrive, you can securely access any remote file server directly from the Finder or... Read more
coconutBattery 3.6.4 - Displays info abo...
With coconutBattery you're always aware of your current battery health. It shows you live information about your battery such as how often it was charged and how is the current maximum capacity in... Read more

The best games to play while you wait fo...
SteamWorld Dig 2 is out this week on PC and Switch, and people are understandably excited. This clever series by Image and Form combines our favorite metroidvania mechanics with an esquisite universe, excellent storytelling, and true wit. While... | Read more »
Drag'n'Boom beginner's gu...
Have you ever wanted to burn and pillage a village as a bloodthirsty dragon? If you answered yes to that question, Drag'n'Boom offers you the perfect chance to do so, casting you as an adorable little dragon that wants to set humankind aflame. It... | Read more »
Thimbleweed Park (Games)
Thimbleweed Park 1.0.0 Device: iOS Universal Category: Games Price: $9.99, Version: 1.0.0 (iTunes) Description: A brand new adventure game from Ron Gilbert and Gary Winnick, creators of the classics Monkey Island and Maniac Mansion!... | Read more »
The best simulation games on mobile
There's nothing like a good sim -- from the seemingly ridiculous to the incredibly mundane, you can be there's a simulation game out there for your every whim. [Read more] | Read more »
INKS guide - how to create works of pinb...
INKS puts a clever new spin on everyone's favorite classic arcade game, pinball. The core mechanics are the same -- keep a little ball pinging around the board for as long as possible without letting it fall into the precarious holes in the board.... | Read more »
Warbands: Bushido (Games)
Warbands: Bushido 1.0 Device: iOS Universal Category: Games Price: $3.99, Version: 1.0 (iTunes) Description: Warbands:Bushido is a miniatures board game with cards, miniatures, dice and beautiful terrains to fight on, with both... | Read more »
The best mobile games like Divinity: Ori...
Divinity: Original Sin 2 launched this week to the excitement of RPG fans everywhere. The game, which derives a lot of of its story and mechanics from old-school isometric RPGs and Dungeons & Dragons, has unseated PlayerUnknown's... | Read more »
Iron Marines guide - beginner tips and t...
Iron Marines is a brilliant RTS title that feels a bit like Starcraft. It's got a sci-fi setting and some of the most spectacular strategy mechanics we've seen in mobile games to date. With that said, the RTS genre can be a bit tricky to break... | Read more »
The best new games we played this week -...
The work week can be tough, but on the bright side, it's almost overandthere are bunches of brand new games to try out this weekend. This week definitely makes up for last week's sleepiness ten-fold. We've got one of the finest RTS game on mobile... | Read more »
Through the Ages (Games)
Through the Ages 1.0.60 Device: iOS Universal Category: Games Price: $9.99, Version: 1.0.60 (iTunes) Description: The offical adaptation of Vlaada Chvátil’s strategy classic, the second best board game ever by Board Game Geek website... | Read more »

Price Scanner via MacPrices.net

Apple Refurbished 3TB Time Capsule for $279,...
Apple has Certified Refurbished 3TB Time Capsules available for $279 including free shipping plus Apple’s standard one-year warranty. Their price is $120 off MSRP. Read more
19% off Smart Battery Cases for iPhone 7
Amazon has both Black and White Smart Battery Cases for iPhone 7s available for $80.41 including free shipping. Their price is $18.59, or 19%, off MSRP. Read more
Back on sale: 10.5-inch 64GB iPad Pros for $5...
MacMall has 10.5″ 64GB Apple iPad Pros on sale again for $599 including free shipping. That’s $50 off MSRP and the lowest price available for this model from any reseller. Read more
Verizon offers Certified Preowned 16GB iPhone...
Verizon has the 16GB iPhone 6, Certified Preowned, available for $259.99 or $10.83 per month for 24 months. Service plan required. According to Verizon, “All CPO devices have been reconditioned to... Read more
Preorder new iPhone 8 at US Cellular, and tak...
Preorder the new iPhone 8 or iPhone 8 Plus at US Cellular, and take $50 off the prepaid price: – 64GB iPhone 8: $649.99 – 128GB iPhone 8: $799.99 – 64GB iPhone 8 Plus: $749.99 – 128GB iPhone 8 Plus... Read more
12-inch and 9-inch Apple iPad Pros, Certified...
Apple has Certified Refurbished 2016 12″ WiFi iPad Pros available starting at $589. An Apple one-year warranty is included with each model, and shipping is free: – 32GB 12″ iPad Pro WiFi: $589... Read more
QuickerTek Announces Solar PV Chargers for US...
Wichita, Kansas based QuickerTek has announced its new 30 Watt and 60 Watt USB Type-C Solar Juicz Chargers. These solar panels are the only products of their kind, featuring the USB 3.1 adapter cable... Read more
Apple refurbished 128GB iPhone 6s and 6s Plus...
Apple has Certified Refurbished 128GB iPhone 6s and 6s Plus’ available for up to $100 off the price of new models. Space Gray, Silver, Gold, and Rose Gold models are available. Each phone comes... Read more
13-inch 2.3GHz Silver MacBook Pros on sale fo...
B&H Photo has 2017 13″ 2.3GHz Silver MacBook Pros in stock today and on sale for $100 off MSRP, each including free shipping plus NY & NJ sales tax only: – 13-inch 2.3GHz/128GB Silver... Read more
12-inch 64GB iPad Pros available for $749, $5...
MacMall has 12″ 64GB iPad Pros on sale for $749 including free shipping. Their price is $50 off MSRP. Read more

Jobs Board

Development Operations and Site Reliability E...
Development Operations and Site Reliability Engineer, Apple Payment Gateway Job Number: 57572631 Santa Clara Valley, California, United States Posted: Jul. 27, 2017 Read more
*Apple* Solutions Consultant - Apple Inc. (U...
…about helping others on a team while also delighting customers? As an Apple Solutions Consultant (ASC), you will discover customers needs and help connect them Read more
Software/Data Engineer, *Apple* Media Produ...
Job Summary Apple Media Products is the team behind the App Store, Apple Music, iTunes, and many other high profile products on iPhone, Mac and AppleTV. Our Data Read more
SW Engineer , *Apple* Media - Apple Inc. (U...
Job Summary Our team is responsible for exposing Apple Media content and services to the world, and building the infrastructure for next generation internal and Read more
*Apple* Data Center Site Selection and Strat...
Job Summary As Apple 's products and services scale the globe, the Data Center Affairs team works behind the scenes to secure infrastructure for Apple 's data Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.