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


Customizing TextEdit

This section describes how to customize TextEdit using the TECustomHook routine to replace the end-of-line, drawing, width-measuring, and hit test default hook routines.

It also describes the multi-purpose low-memory global variable TEDoText hook routine that displays, highlights, and hit-tests characters, and positions the pen to draw a caret. Finally, this section discusses how to customize word selection, automatic scrolling, and how to determine the length of a line of text in order to justify it. (For a brief discussion of hook fields and hook routines, see "Related Data Structures" on page 2-16.)

The next four sections describe how to customize TextEdit using the TECustomHook procedure. Information about the use of TECustomHook that is common to all four sections is provided here.

You can customize TextEdit's behavior by replacing any of the default hook
routines with those of your own. You use the TECustomHook procedure to replace
a routine installed in a hook field of the dispatch record (TEDispatchRec). Initially, each hook field of the dispatch record contains the address of the default hook routine that TextEdit uses.

The TECustomHook procedure returns the address of the default routine that it replaces so that your application-supplied routine can call the default routine, daisy-chaining it, if you want it to. For example, your routine can add additional functionality, then call the default routine instead of replicating all of its behavior. If you replace the address of a default hook routine with that of your own customized version, the next time you call TECustomHook for that hook field, TECustomHook will return the address of your routine. (For more information, see "TECustomHook" on page 2-105.) To ensure future compatibility, use the TextEdit customization routines to modify hooks rather than write directly to these fields.

If you replace a default hook routine with a customized version that you write in a high-level language, such as Pascal or C, you need to provide assembly-language glue code that utilizes the registers for your high-level language routine. Refer to "TECustomHook" on page 2-105 for a description of the register contents on entry and return for each of the hook routines.

If you replace a default routine, take the following precautions:

Replacing the End-of-Line Routine

You can replace the address of the default end-of-line hook routine with the address of your own routine that determines an end-of-line character if you want the end-of-line to be defined by a character other than the carriage return.

The default routine compares a given character with $0D (a carriage return) to determine whether it is an end-of-line character, and returns with the appropriate status flags (either TRUE or FALSE) in the status register.

Replacing the Drawing Routine

TextEdit calls the draw hook routine any time the various components of a line are drawn. The appropriate font, face, and size characteristics have already been set into the current graphics port by the time this routine is called.

If your application uses an outline font, the default behavior of the Font Manager ensure's that glyphs fit within the font's ascent and descent. Glyphs that extend beyond the ascent or descent, such as certain accented fonts, are scaled down to fit.

If your application has set the preserveGlyph parameter of the Font Manager's SetPreserveGlyph procedure to TRUE to preserve the original unscaled shape of the glyph, note that TextEdit sets it to FALSE before it calls the draw hook to perform any drawing. This is to guarantee that the glyphs whose bounding boxes exceed the font's ascent or descent are scaled down to prevent them from colliding with other glyphs on the lines above or below. TextEdit then restores the preserveGlyph parameter to its previous value before proceeding.

Replacing the Width-Measuring Routines

A width measurement hook routine measures portions of a line of text, and TextEdit calls one each time the width of various components of a line is calculated. There are three width measurement hooks: the width measurement hook, the new width measurement hook, and the text width measurement hook. Default hook routines of the same name as the hook field are installed in each of these hooks.

The width measurement hook, which TextEdit used in the past, now exists to provide backward compatibility for applications that have replaced the default routine with a customized one. TextEdit uses the routine whose address is installed in this field only when both of the following conditions exist: when only the Roman script system is installed and the field contains the address of a customized routine.

In all other cases--when more than one script system is installed or when the width measurement hook has not been customized--TextEdit calls the routine whose address is installed in the new width measurement hook field to measure text.

Figure 2-14 shows a flow chart illustrating when the width measurement hook and the new width measurement hook routines are used.

Figure 2-14 Determining when to use WIDTHHook and nWIDTHHook

The new width measurement hook routine is called to measure text for both Roman and non-Roman script systems. If you replace this routine, make sure that your customized routine is script-aware.

The default action for the new width measurement hook routine is to call the QuickDraw Manager's CharToPixel function or TextWidth procedure to measure for non-Roman scripts. By default, the TextWidthHook field contains the address of the QuickDraw TextWidth function. You can use this hook to replace TextEdit's use of the
QuickDraw TextWidth function with your own measuring routine. If you replace
this hook routine with a customized version, when the routine whose address is installed in the new width measurement hook field makes a call to TextWidth, your customized routine is invoked.

To test for the availability of the width-measuring hooks, you can call the Gestalt function with the gestaltTextEditVersion selector. A result of gestaltTE2 or greater returned in the response parameter indicates that the new width measurement hook is available, and a result of gestaltTE5 or greater indicates that TextWidthHook is available.

Replacing the Hit Test Routine

TextEdit calls the hit test hook routine to determine the glyph position in a line, given the pixel width from the left edge of the view rectangle. For versions of software earlier than 7.0, the default action is to call the TextWidth function to determine if the pixel width of the measured text is greater than the input width. If it is, then the hit test hook routine calls the QuickDraw PixelToChar function and returns. For system software version 7 and later, the default action is to call the QuickDraw PixelToChar function. In addition to the values defined by the register contents on entry, when TextEdit calls the PixelToChar function, it passes a value of OnlyStyleRun for the styleRunPosition parameter and scaling factors of 1/1 for the numer and demon parameters. See "Hit Test Hook Registers" on page 2-108.

Customizing Word Selection

A word-selection break routine determines which word is highlighted when the user double-clicks in the text. It also determines where TextEdit breaks the text at the end of a line. You can use TESetWordBreak to replace the default routine, installed in the edit record's wordBreak field, that is used for word selection and line breaking under certain circumstances. Whether or not TextEdit uses the word break hook routine installed in this field is determined by the algorithm implemented in the default TEFindWord routine, which is described below.

When you replace the wordBreak field hook routine, your customized word-selection break routine is used instead of the default one. The default routine breaks words at
any character with an ASCII value of $20 or less (the space character or nonprinting control characters).

Before non-Roman script systems were supported, TextEdit used the word-selection break routine referenced by the wordBreak field for all word selection and line breaking. However, in order to support both Roman and non-Roman script systems, TextEdit now uses the routine referenced by the low-memory global variable TEFindWord. The default TEFindWord hook routine determines which hook TextEdit should use for word selection and line breaking--the wordBreak hook or the Text Utilities FindWordBreaks procedure--based on what script systems are installed
and some other factors. You can replace the TEFindWord hook routine with a customized version.

The TEFindWord hook routine is a higher level routine than wordBreak. Because of this, when you customize the TEFindWord hook you are completely changing how TextEdit handles word selection and line breaking. However, when you replace wordBreak, you are only impacting those aspects of word selection and line breaking that are normally handled by the wordBreak routine.

The TEFindWord hook routine gives your application more control over the breaking process and allows you to write more efficient routines. However, unless you include explicit tests for scripts in your customized routine, the algorithms you provide may be incorrect for non-Roman scripts. If you replace TEFindWord, you should understand the behavior of the default routine.

Here's how the default TEFindWord routine works:

When TextEdit calls the Text Utilities FindWordBreaks procedure, it uses information in the edit record to provide the necessary parameters. TextEdit determines the current script boundaries from the Text Utilities FindWordBreaks procedure by using the font run information in the style record (of type TEStyleRec). TextEdit also determines the length of the script run and the offset within the script run from which to begin searching for a word boundary. TextEdit uses the value in the clikStuff field of the edit record to determine the leading edge flag for the FindWordBreaks procedure. You must use similar information to replace TEFindWord correctly for non-Roman scripts.

Customizing Automatic Scrolling

Scroll bars associated with the text are not automatically scrolled with the text unless you replace the address of the default click loop routine with that of a customized routine that updates the scroll bars. You can write your own click loop routine that includes code to update the scroll bars along with the text and install its address in the clikLoop field. To replace the default click loop routine with your customized version, you call the TESetClickLoop procedure.

You can write a routine that manages the scroll bars, then calls the default click loop routine, rather than replicating its behavior in your routine. However, if your routine scrolls the text and updates scroll bars, you should consider what the default click loop routine does. It adjusts the value in the clickTime field of the edit record to allow for slower scrolling.

When TEClick is called, the clickTime field contains the time when TEClick was last called. TextEdit sets the clickTime field with the current tick count on exit from the TEClick procedure and uses the new value at reentry the next time TEClick is called.

If you code a click loop routine in Pascal, it should have no parameters and it should return a Boolean value. You can declare a click loop routine named MyClickLoop
like this:

FUNCTION MyClickLoop: Boolean;
The function should return TRUE. Returning FALSE from your click loop routine tells the TEClick procedure that the mouse button has been released, which aborts TEClick.

Installing a customized default click loop routine
If you code a click loop routine in Pascal, then call the TESetClickLoop procedure to install the Pascal routine in the clikLoop field, TESetClickLoop installs a glue code routine in the clikLoop field because clikLoop expects a routine that uses assembly-language conventions. Because of this, you must always use TESetClickLoop to install a Pascal routine, while you must always directly install an assembly routine in the clikLoop field.
If you code a click loop routine in assembly, it should set register D0 to 1 and preserve register D2. Returning 0 in register D0 aborts TEClick.

You can write a routine that manages the scroll bars, then calls the default click loop routine, rather than replicating its behavior in your routine. If your customized routine calls the default click loop routine, it must use assembly-language calling convention.

Determining the Line Length

This section describes how to determine the length of a line. You can use this information, for example, to justify a line of text; although TextEdit aligns text with the right or left margins, or centers it, it does not justify it.

To determine the length of a line, you use the information contained in the edit record's line starts array and nLines field. The line starts array is a variable-length field in the edit record that contains the byte offset for the first character of each line. This array has the following boundary conditions:

For example, if you want to determine the length of the line n (where n = 0 for the first line), subtract its start location (contained in the array entry with index n) from its end location (contained in the array with index n + 1):

lengthOfLineN := myTE^^.lineStarts[n+1] - myTE^^.lineStarts[n];
The terminating condition for this measurement is when n is equal to nLines plus 1.

IMPORTANT
Do not change the information contained in the lineStarts array.

Advanced Customization

The low-memory global variable TEDoText is a hook which contains the address of a multi-purpose text editing routine that advanced programmers may find useful. It lets you display, highlight, and hit-test characters, and position the pen to draw the caret. Hit-testing is the process of determining where to place the insertion point when the user clicks the mouse button; the point selected with the mouse is in the SelPoint field. The registers contain the following values.
Registers on entry    
A3Pointer to the locked edit record 
D3Position of the first character (word) 
D4Position of the last character; used as defined below (word)
D7Selectors for TEDoText (word) 
 teFindEQU0to hit-test the character specified in D3
 teHighlightEQU1to highlight the text range specified in D3
and D4
 teDrawEQU-1to display the range of text specified in D3 and D4
 teCaretEQU-2to draw the caret at the position specified
in D3
 teFindEQU0to hit-test the character specified in D3
Registers on exit  
A0Pointer to current graphics port
D0If hit-testing, byte offset where hit, or -1 for none (word)

Note
You need to use the value stored in the edit record selPoint field
for hit-testing if you replace the routine pointed to by the global
variable TEDoText. (The assembly-language offset for this field
is named teSelPoint.)

Previous Book Contents Book Index Next

© Apple Computer, Inc.
6 JUL 1996