Important: The information in this document is obsolete and should not be used for new development.
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
- displaying static text
- creating an edit record
- setting the text of an edit record
- setting the selection range or the insertion point
- scrolling text
- disposing of an edit record
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.
- determine the installed version of TextEdit
- initialize other managers and TextEdit
You can get information about the current version of TextEdit using the
Gestalt
function with theGestalt
selectorgestaltTextEditVersion
, 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.
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 asTEDoText
andTERecal
, theTEInit
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. TheTETextBox
procedure displays unchanging text that you cannot edit. You don't create an edit record because theTETextBox
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.
Constant Description teFlushDefault Default alignment according to the primary line direction teCenter Center for all scripts teFlushRight Right for all scripts teFlushLeft Left 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 theTETextBox
procedure, first you need to create an edit record. This section discusses how to create an edit record. It also describes
The
- which type of edit record to use, monostyled or multistyled, and why
- some ways to store the edit record handle that the function returns when you create an edit record
- what to consider when you specify values for the destination and view rectangles when you create an edit record
- how TextEdit initializes those edit record fields that are used differently for monostyled and multistyled edit records, and those that are used the same
TEStyleNew
function allocates a multistyled edit record which contains text with character attribute information that can vary from character to character. TheTENew
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 useTEStyleNew
in this case also, although it is not recommended.Both
TENew
andTEStyleNew
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.
- You can store the edit record handle in a private data structure whose handle is stored in your application window's
refcon
field.- You can create a record in which to store information about the window, and include a field to store the edit record handle. Listing 2-2 provides an example of this method.
- You can define a variable in your application for each edit record handle, and then use the variable to store the handle.
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 procedureSetWRefCon
. 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
, thetxSize
,lineHeight
, andfontAscent
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.
- The
txSize
field is set to the value of the current graphics port's text size (txSize
) field, which indicates that all text is set in a single font, size, and face.- The value of the
lineHeight
field specifies the fixed vertical distance from the ascent line of one line of text down to the ascent line of the next. The line height corresponds to the ascent plus descent for the font and leading to create single-spacing for the lines in the new edit record.- The value of the
fontAscent
field specifies how far above the base line the pen is positioned to draw the caret or to highlight the text. For single-spaced text, this is the ascent of the text in pixels (the height of the tallest characters in the font from the base line). The font ascent corresponds to the ascent of the font indicated by thetxFont
andtxSize
fields of the current graphics port.
For more information, see the discussion of font measurements in the chapter "Font Manager" in this book.
- Note
- To adjust the spacing for a monostyled edit record, you can alter the values in the
fontAscent
andlineHeight
fields of the edit record.For a multistyled edit record,
TEStyleNew
initializes thetxSize
,lineHeight
, andfontAscent
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:
txSize
The edit record contains associated character attribute information and the
txFont
andtxFace
fields combine to contain the text style record handle for the character attribute information.lineHeight
The vertical distance from the ascent line of one line of text down to the ascent line of the next is calculated independently for each line, based on the maximum value for any individual character attribute on that line. These values are stored in the line height table (
LHTable
).fontAscent
The font ascent is calculated independently for each line, based on the maximum value for any individual character attribute on that line. These values are stored in the line height table (
LHTable
).
Listing 2-3 shows the
- The record initially contains no text. The text handle (
hText
) points to a zero-length block in the heap, and the text length field (teLength
) of the edit record is set to 0. To furnish text to be edited, you use theTESetText
procedure if you are incorporating existing text and theTEKey
procedure if the user is entering text.- The value of the
just
field determines the alignment of text in the edit record. The default value isteFlushDefault
, indicating that the alignment is to follow the primary line direction. For languages that are read from left to right, the default value is left; for languages that are read from right to left, the default value is right. To change the alignment of text in the record, you use theTESetAlignment
procedure.- The
selStart
andselEnd
fields are initially set to 0; this places the insertion point at the beginning of the text.- The edit record uses the drawing environment of the graphics port specified by the
destRect
andviewRect
parameters. These parameters contain the local coordinates of rectangles within the current graphics port, which becomes the graphics port for the new edit record. The text in the new edit record is to have the characteristics of the current graphics port.
MyAddTE
function, which is a sample application-defined function that creates a new multistyled edit record for an existing window. TheTEStyleNew
function call returns a handle to the edit record that it creates. The code stores the handle in thedocTE
variable. TheTEAutoView
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'shText
field. One of the parameters that you pass toTESetText
specifies the length of the text. TheTESetText
procedure resets theteLength
field of the edit record with this value and uses it to determine the end of the text; it sets theselStart
andselEnd
fields to the last byte offset of the text so that the insertion point is positioned at the end of the displayed text. TheTESetText
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 theteLength
field to specify the length of the new text, and then callTECalText
to recalculate thelineStarts
array andnLines
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
- Before changing the edit record's
hText
field, reduce the style run table to one entry.
Do this by setting the edit record'sselStart
field to 0 and itsselEnd
field to 32767, then callTESetStyle
.- Before calling
TECalText
, set the start character (startChar
) field of the style run table to the length of the new text plus one, that is:
TEStyleRec.runs[1] to length(hText)+1
The
- 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 thehText
field, first you need to save the text before you callTESetText
, becauseTESetText
uses the same handle, resizing it for the new text, if necessary.TESetText
procedure doesn't affect the text drawn in the destination rectangle, so call the Window Manager'sInvalRect
procedure afterward, if necessary. For more information about theInvalRect
procedure, see the chapter "Window Manager" in Inside Macintosh: Macintosh Toolbox Essentials.Setting the Selection Range or the Insertion Point
You can use theTESetSelect
procedure to specify the selection range or the position of the insertion point as determined by the application. For example, you can useTESetSelect
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. TheTESetSelect
procedure modifies theselStart
andselEnd
fields of the edit record.To display a caret at an insertion point, specify the same value for both the
selStart
andselEnd
parameters. To encompass the edit record's entire text block as the selection range, specify 0 as the value ofselStart
and 32767 as the value ofselEnd
. 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 theteLength
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 thelineHeight
field and by the number of lines displayed in the view rectangle. For multistyled text, you need to use the value of thelhHeight
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
orTEPinScroll
specifying the number of pixels to scroll. The only difference betweenTEScroll
andTEPinScroll
is thatTEPinScroll
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 theTEAutoView
procedure or theteFAutoScroll
feature of theTEFeatureFlag
function. However, neither of these routines actually scrolls the text. To ensure that the selection range is always visible, your application should callTESelView
. 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 usingTEPinScroll
. 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 thelhHeight
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 callingTEDispose
. To continue to refer to the text once you've destroyed the edit record, use the Operating System UtilitiesHandToHand
function before you callTEDispose
. It copies the text (whose handle is stored in the edit record'shText
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 thehText
field after you callTEDispose
, the handle becomes invalid because the text is removed--the memory used for it is deallocated.