Legacy Documentclose button

Important: The information in this document is obsolete and should not be used for new development.

Previous Book Contents Book Index Next

Inside Macintosh: Text /
Chapter 2 - TextEdit / Using TextEdit


Getting Started With TextEdit

You can use TextEdit to display static text, for example, in a dialog box; the TextEdit procedure that you use to do this creates its own edit record. You can use TextEdit to display and manipulate modifiable text, for which purpose you must first create an edit record. This section discusses these two uses of TextEdit. It describes how you create an edit record and bring existing text into its text buffer, then set the text selection range or insertion point, scroll the text, and, finally, release the memory allocated for the edit record when you are finished with it. The topics are described in the following order:

Preparing to Use TextEdit

This section describes two basic tasks that your application needs to perform before using TextEdit. It must

To determine the installed version of TextEdit, you use the Gestalt Manager, which is fully documented in the chapter "The Gestalt Manager" in Inside Macintosh: Operating System Utilities.

You can get information about the current version of TextEdit using the Gestalt function with the Gestalt selector gestaltTextEditVersion, which returns one of the values listed and described below. In this list, a new feature is shown only when it is first introduced in the software, although it is part of TextEdit in succeeding versions. For system software version 6.0.4, different patches were made to TextEdit for different hardware platforms. In these cases, unique values are returned that also identify
the hardware.
Returned valueNew featuresSystem software/hardware
gestaltUndefSelectorErrMultistyled TextEditSystems before 6.0.4/all hardware
gestaltTE1 System 6.0.4 Roman script system/IIci-family hardware
gestaltTE2New width measurement hook

Script Manager compatible
System 6.0.4 non-Roman script system/IIci-family hardware
gestaltTE3 System 6.0.4 non-Roman script system/all non-IIci family hardware
gestaltTE4TEFeatureFlagSystem 6.0.5/all hardware
gestaltTE5Text width measurement hookSystem 7.0/all hardware

You need to initialize other managers and TextEdit before your application calls any TextEdit routines, including TEInit. First, you initialize QuickDraw, the Font Manager, and the Window Manager, and then TextEdit, in that order. To do this, call the following routines from an initialization procedure that is called from your application's
main routine.

BEGIN
   InitGraf(@thePort);
   InitFonts;
   InitWindows;
   InitMenus;
   TEInit;
   ....
In addition to initializing miscellaneous global variables, such as TEDoText and TERecal, the TEInit procedure sets up the private scrap and allocates a handle to it.

Note
You should call TEInit even if your application doesn't use TextEdit so that desk accessories and dialog and alert boxes, which use TextEdit routines, work correctly.

Displaying Static Text

TextEdit provides an easy way for your application to display static text whether or
not it uses other TextEdit features to implement editing services. The TETextBox procedure displays unchanging text that you cannot edit. You don't create an edit record because the TETextBox procedure creates its own edit record, which it deletes when it's finished with it.

The TETextBox procedure draws the text in a rectangle whose size you specify in the local coordinates of the current graphics port. You can also specify how text is aligned in the box. Text can be right aligned, left aligned, or centered.

You can use any of the following constants to specify how text is aligned in the box that TETextBox creates.
ConstantDescription
teFlushDefaultDefault alignment according to the primary line direction
teCenterCenter for all scripts
teFlushRightRight for all scripts
teFlushLeftLeft for all scripts

Listing 2-1 shows how to use TETextBox. The first parameter is a pointer to the text to be drawn, which is a Pascal string. Because Pascal strings start with a length byte, you need to advance the pointer one position past the beginning of the string to point to the start of the text.

Listing 2-1 Using TETextBox to draw static text

str   := 'String in a box'; 
SetRect(r,100,100,200,200); 
TETextBox(POINTER(ORD(@str)+1),LENGTH(str),r,teCenter); 
FrameRect(r);

Creating an Edit Record

To use all other TextEdit routines in your application except the TETextBox procedure, first you need to create an edit record. This section discusses how to create an edit record. It also describes

The TEStyleNew function allocates a multistyled edit record which contains text with character attribute information that can vary from character to character. The TENew function allocates a monostyled edit record which contains text in a single font, face, and size. (Before your application calls either of these functions, the window must be the current graphics port.)

If your application supports only monostyled text, use TENew to avoid the unnecessary allocation of additional data structures used to store character attribute information for multistyled edit records. You can use TEStyleNew in this case also, although it is not recommended.

Both TENew and TEStyleNew return a handle to the newly created record. Most TextEdit routines require you to pass this handle as a parameter, so your application needs to store it using any of the following methods:

Listing 2-2 shows a sample document record declaration for an application that handles text files. The document record is an application-specific data structure that contains the handle to the edit record, and any controls for scroll bars.

Listing 2-2 A sample document record

TYPE
   MyDocRecHnd =  ^MyDocRecPtr;
   MyDocRecPtr =  ^MyDocRec;
   MyDocRec    =
   RECORD
      editRec:       TEHandle;      {handle to TextEdit record}
      vScrollBar:    ControlHandle; {vertical scroll bar}
      hScrollBar:    ControlHandle; {horizontal scroll bar}
   END;
To associate an application-defined document record with a particular window, you can set a handle to that record as the reference constant of the window by using the Window Manager procedure SetWRefCon. This technique is described further in the chapter "Introduction to File Management" in Inside Macintosh: Files.

When you create an edit record, you specify the area in which the text is drawn as the destination rectangle, and the portion of the window in which the text is actually displayed as the view rectangle.

To ensure that the first and last characters in each line are legible in a document window, you can inset the destination rectangle at least four pixels from the left and right edges of the graphics port (20 pixels from the right edge if the window contains a scroll bar
or size box).

The destination rectangle must always be at least as wide as the first character drawn. The view rectangle must not be empty; for example, if you do not want any text visible, specify a rectangle off the screen--don't make its trailing edge less than its leading edge.

Editing operations may lengthen or shorten the text. The bottom of the destination rectangle can extend to accommodate the end of the text. In other words, you can think of the destination rectangle as bottomless. The sides of the destination rectangle determine the beginning and the end of each line of text, and its top determines the position of the first line.

Your program should not have a destination rectangle that is wider than the view rectangle if you are displaying mixed-directional text. For example, the Dialog Manager makes the destination rectangle extend twice as far on the right as the view rectangle, so that horizontal scrolling can be used in normal dialog boxes. When the Arabic script system is installed, this extension is disabled, because the text may be right aligned, and therefore out of view. Your application can include the following code to check that the destination and view rectangles have the same width.

IF scriptsInstalled > 1 THEN
   IF GetEnvirons (smBidirect)<>0 THEN
      BEGIN
      {make the rectangles the same width}
      END;
When you create an edit record, TextEdit initializes the record's fields, based on values in the current graphics port record and the kind of edit record you create. Although most edit record fields are initialized similarly for both monostyled and multistyled edit records, there are some fields that are used differently, and their initial values depend on how they are used.

For a monostyled edit record that you create by calling TENew, the txSize, lineHeight, and fontAscent fields of the edit record hold actual values reflecting the text size, the line height, and the font ascent. Because the text is monostyled, these values apply to all of the text of the edit record.

Note
To adjust the spacing for a monostyled edit record, you can alter the values in the fontAscent and lineHeight fields of the edit record.
For more information, see the discussion of font measurements in the chapter "Font Manager" in this book.

For a multistyled edit record, TEStyleNew initializes the txSize, lineHeight, and fontAscent fields of the edit record to -1. A value of -1 in each of these fields means:

For both multistyled and monostyled records, the following fields are initially set to the same values:

Listing 2-3 shows the MyAddTE function, which is a sample application-defined function that creates a new multistyled edit record for an existing window. The TEStyleNew function call returns a handle to the edit record that it creates. The code stores the handle in the docTE variable. The TEAutoView procedure call turns on automatic scrolling for the newly created edit record. For a complete discussion of scrolling, see the chapter "Control Manager" in Inside Macintosh: Macintosh Toolbox Essentials.

Listing 2-3 Creating a multistyled edit record

FUNCTION MyAddTE (myWindow: WindowPtr): TEHandle;
VAR
   destRect, viewRect:  Rect;
   docTE:               TEHandle;
   CONST
   kMaxDocWidth = 576;
BEGIN
   MyGetTERect(myWindow, viewRect); {get TextEdit rectangle}
   destRect := viewRect;
   destRect.right := destRect.left + kMaxDocWidth;
   docTE := TEStyleNew(destRect, viewRect);
   IF docTE <> NIL THEN 
      BEGIN
         TEAutoView(TRUE, docTE);
         docTE^^.clikLoop := @AsmClikLoop;
      END;
   MyAddTE := docTE; 
END;

Specifying the Destination and View Rectangles

When you create an edit record, whether monostyled or multistyled, you specify the area in which the text is drawn as the destination rectangle, and the portion of the window in which the text is actually displayed as the view rectangle.

To ensure that the first and last glyphs in each line are legible in a document window, you can inset the destination rectangle at least four pixels from the left and right edges of the graphics port (20 pixels from the right edge if the window contains a scroll bar
or size box).

The destination rectangle must always be at least as wide as the first glyph drawn. The view rectangle must not be empty; for example, if you do not want any text visible, specify a rectangle off the screen--don't make its trailing edge less than its leading edge.

Editing operations may lengthen or shorten the text. The bottom of the destination rectangle can extend to accommodate the end of the text. In other words, you can think of the destination rectangle as bottomless. The sides of the destination rectangle determine the beginning and the end of each line of text, and its top determines the position of the first line.

Your program should not have a destination rectangle that is wider than the view rectangle if you are displaying mixed-directional text. For example, the Dialog Manager makes the destination rectangle extend twice as far on the right as the view rectangle, so that horizontal scrolling can be used in normal dialog boxes. When the Arabic script system is installed, this extension is disabled, because the text may be right aligned, and therefore out of view. Your application can include the following code to check that the destination and view rectangles have the same width.

IF scriptsInstalled > 1 THEN
   IF GetEnvirons (smBidirect)<>0 THEN
      BEGIN
      {make the rectangles the same width}
      END;

Setting the Text of an Edit Record

When you create an edit record, it doesn't contain any text until either the user enters text through the keyboard or opens an existing document. This section describes how to specify existing text to be edited. "Accepting Text Input Through Key-Down Events" on page 2-33 discusses how to insert text that the user enters through the keyboard.

When a user opens a document, your application can bring the document's text into the text buffer of an edit record by calling TESetText. If the text has associated character attribute information, your application also needs to manage it.

There are two ways to specify existing text to be edited. The easier method is to use TESetText, which creates a copy of the text and stores the copy in the existing handle of the edit record's hText field. One of the parameters that you pass to TESetText specifies the length of the text. The TESetText procedure resets the teLength field of the edit record with this value and uses it to determine the end of the text; it sets the selStart and selEnd fields to the last byte offset of the text so that the insertion point is positioned at the end of the displayed text. The TESetText procedure calculates line breaks, eliminating the need for your application to do this.

You can use the second method to save space if you have a lot of text. Using this method, you can bring text into an edit record by directly changing the hText field of the edit record, replacing the existing handle with the handle of the new text. When you do this for a monostyled edit record, you need to modify the teLength field to specify the length of the new text, and then call TECalText to recalculate the lineStarts array and nLines values to match the new text.

Using the second method is somewhat more complicated for multistyled text because TECalText does not update the style run table (StyleRun) properly. To compensate for this, your application needs to perform the following tasks:

Using the same edit record for different pieces of text

Rather than allocate a new edit record for each piece of text you want to edit, you can use the same record to edit different pieces of text. For example, you can create an edit record and either accept user input or call TESetText to incorporate existing text. If you know that you'll want to edit the text again whose handle is currently stored in the hText field, first you need to save the text before you call TESetText, because TESetText uses the same handle, resizing it for the new text, if necessary.
The TESetText procedure doesn't affect the text drawn in the destination rectangle, so call the Window Manager's InvalRect procedure afterward, if necessary. For more information about the InvalRect procedure, see the chapter "Window Manager" in Inside Macintosh: Macintosh Toolbox Essentials.

Setting the Selection Range or the Insertion Point

You can use the TESetSelect procedure to specify the selection range or the position of the insertion point as determined by the application. For example, you can use TESetSelect to highlight an initial default value in an application such as an online data-entry form, or to position the caret at the start of the field where you want the user to enter a value. You can also use it to implement a Select All menu command.

You can set the selection range (or insertion point) to any character positions within the text of the edit record corresponding to byte offsets 0 through 32767. To select a range of text, you pass TESetSelect the handle to the edit record along with the byte offsets corresponding to the beginning and the ending characters of the text to be highlighted. The TESetSelect procedure modifies the selStart and selEnd fields of the edit record.

To display a caret at an insertion point, specify the same value for both the selStart and selEnd parameters. To encompass the edit record's entire text block as the selection range, specify 0 as the value of selStart and 32767 as the value of selEnd. You can implement a Select All menu command by specifying the edit record's entire range of text, as shown in the following code fragment, by using the teLength field.

iSelectAll:
   TESetSelect(0, myTERec^^.teLength, myTERec);

Scrolling Text

Using TextEdit routines, your application can allow the user to control text scrolling through the scroll bars; in this case, you scroll the text by calling a TextEdit procedure. It can also automatically scroll the text of an edit record into view when the user clicks in the view rectangle, and then drags the mouse outside of it, if you enable automatic scrolling through another TextEdit procedure.

To scroll the text when a mouse-down event occurs in a scroll bar, your application needs to determine how far to scroll the text. For example, to vertically scroll the text of a monostyled edit record, you can use the lineHeight field of the edit record to calculate the number of pixels to scroll; you multiply every click in the scroll bar by the number of pixels in the lineHeight field and by the number of lines displayed in the view rectangle. For multistyled text, you need to use the value of the lhHeight field of the line height table for each line in the view rectangle because line height can vary from line to line.

To scroll the text, you call either TEScroll or TEPinScroll specifying the number of pixels to scroll. The only difference between TEScroll and TEPinScroll is that TEPinScroll stops scrolling when the last line is scrolled into the view rectangle.

When the user clicks in the scroll arrow pointing down, you scroll the text up. When the user clicks in the scroll arrow pointing up, you scroll the text down. Passing a positive value to either routine moves the text right and down, passing a negative value moves the text left and up. The destination rectangle is offset by the amount you scroll. For example, the following call scrolls the text of a monostyled edit record up one line.

TEScroll(0, -hTE^^.lineHeight, hTE)
There are two ways to enable or disable automatic scrolling for an edit record. You can use the TEAutoView procedure or the teFAutoScroll feature of the TEFeatureFlag function. However, neither of these routines actually scrolls the text. To ensure that the selection range is always visible, your application should call TESelView. When automatic scrolling is turned on, TESelView scrolls the selection range into view, if necessary.

Listing 2-3 on page 2-25 creates a multistyled edit record and turns on automatic scrolling for it. It saves the address of the default click loop procedure installed in the edit record's clikLoop field, then replaces it with the address of its own customized click loop routine.

The clikLoop field of the edit record contains the address of a click loop procedure that is called continuously as long as the mouse button is held down. When automatic scrolling is turned on, the default click loop routine determines if the mouse has been dragged out of the view rectangle; if it has, the default click routine scrolls the text using TEPinScroll. For example, if the user clicks in the text and drags the mouse outside of it to the right, the text is automatically scrolled left.

How much the text is scrolled vertically is determined by the lineHeight field of the edit record for a monostyled edit record and by the lhHeight field of the line height table for a multistyled edit record.

Scroll bars are not scrolled automatically with the text if the default click loop routine is used. However, you can replace the default click loop routine with a routine that updates scroll bars. For more information about customizing scrolling, see "Customizing Automatic Scrolling" on page 2-57. For a complete discussion of scrolling, see the chapter "Control Manager" in Inside Macintosh: Macintosh Toolbox Essentials.

Disposing of an Edit Record

When your application is completely finished with an edit record, you should release any memory allocated for it by calling TEDispose. To continue to refer to the text once you've destroyed the edit record, use the Operating System Utilities HandToHand function before you call TEDispose. It copies the text (whose handle is stored in the edit record's hText field), and returns a new handle to it. (See Inside Macintosh: Operating System Utilities for more information.) For a multistyled edit record, you also need to save the character attribute information. If your program retains the original handle to the text stored in the hText field after you call TEDispose, the handle becomes invalid because the text is removed--the memory used for it is deallocated.


Previous Book Contents Book Index Next

© Apple Computer, Inc.
6 JUL 1996