TweetFollow Us on Twitter

MACINTOSH C
MACINTOSH C: A Hobbyist's Guide To Programming the Mac OS in C
Version 2.3

© 2000 K. J. Bricknell

Go to Contents

(Chapter 19)

TEXT AND TEXTEDIT

A link to the associated demonstration program listings is at the bottom of this page



Introduction

The subject of text on the Macintosh is quite a complex matter, involving as it does QuickDraw, TextEdit, the Font Manager, the Text Utilities, the Script Manager, the Text Services Manager, the Resource Manager, keyboard resources, and international resources. Part of that complexity arises from the fact that the system software supports many different writing systems, including Roman, Chinese, Japanese, Hebrew, and Arabic.

Some of the information in this chapter is valid only in the case of the Roman writing system.

Text on the Macintosh was touched on briefly at Chapter 12 - Drawing With QuickDraw, which included descriptions of QuickDraw functions used for drawing text and for setting the font, style, size, and transfer mode. In addition, Chapter 15 - Printing contained a brief treatment of considerations applying to the printing of text.

This chapter addresses:

  • TextEdit, which is a collection of functions and data structures you can use to provide your application with basic text editing and formatting capabilities.

  • The formatting and display of dates, times, and numbers.
Before addressing those particular subjects, however, a brief overview of various closely related matters is appropriate.

More on Text

Characters, Character Sets and Codes, Glyphs, Typefaces, Styles, Fonts and Font Families

Characters and Character Sets and Codes

A character is a symbol which represents the concept of, for example, a lowercase "b", the number "2" or the arithmetic operator "+". A collection of characters is called a character set. Individual characters within a character set are identified by a character code.

The Apple Standard Roman character set is the fundamental character set for the Macintosh computer. It uses all character codes from 0x00 to 0xFF, and includes the uppercase versions of all of the lowercase accented Roman characters, a number of symbols, and other forms (see Fig 1). The Standard Roman character set is an extended version of the ASCII character set, which uses character codes from 0x00 to 0x7F only, and which is highlighted at Fig 1.

(Standard Roman charcater set)

Glyphs

You never see a character on a display device. What you see on a display device is a glyph, which is the visual representation of a character. In other words, a glyph is the exact shape by which a character is represented. A specific character can be represented by many different shapes (that is, glyphs).

The Font Manager uses two types of glyphs: bitmapped glyphs and glyphs from outline fonts. A bitmapped glyph is a bitmap designed at a fixed size for a particular display device. A glyph from an outline font is a model of how the glyph should look. The "outline" is a mathematical description of the glyph in terms of lines and curves, and is used by the Font Manager to create bitmaps at any size for any display device.

Typefaces

If all glyphs for a particular character set share certain design characteristics, they form a typeface, which is a distinctively designed collection of glyphs. Each typeface has its own name, such as New York, Geneva, or Times. The same typeface can be used with different hardware, such as typesetting machines, monitors, and laser printers.

Styles

A style is a specific variation in the appearance of a glyph which can be applied consistently to all glyphs in a typeface. Styles available on the Macintosh include plain, bold, italic, underline, outline, shadow, condensed, and extended. QuickDraw can add styles to bitmaps, or a font designer can design a font in a specific style (for example, Courier Bold).

Fonts and Font Families

A font refers to a complete set of glyphs in a specific typeface and style - and, in the case of bitmapped fonts, a specific size. All fonts have a font name, which is stored in a string such as "Geneva" or "New York". The font name is usually the same name as the typeface from which it was derived. If a font is not in the plain style, its style becomes part of the font name, for example "Palatino Bold". Fonts on the Macintosh are resources. The resource types are as follows:

  • Bitmapped fonts are fonts of the 'FONT' resource type (the original resource type for fonts) and the bitmapped font ('NFNT') resource type. These resources provide a separate bitmap for each glyph in each size and style.

  • Outline fonts are fonts of the outline font ('sfnt') resource type which consist of glyphs in a particular typeface and style with no size restriction. The outline font resource type emerged at the time of the addition of TrueType outline font support with System 7.
When multiple fonts of the same typeface are present in the system software, the Font Manager groups them into font families of the font family ('FOND') resource type. A font family ID is the resource ID for a font family. Because there are so many font families available for the Macintosh, many families have the same ID.

This is the reason why your application should refer to fonts by name and not by number when it stores font references in a document.

As an aside, most (though not all) fonts assign glyphs to character codes 0x20 to 0x7F which visually define the characters associated with those codes.3 However, there are differences in the glyphs assigned to the high-ASCII range. Indeed, some fonts do not actually include glyphs for all, or part, of the high-ASCII range.

Fonts such as Zapf Dingbats assign glyphs of pictorial symbols to this range. as well as the low-ASCII range.

Font Measurements

Monospaced and Proportional Fonts. Fonts are either monospaced or proportional. All glyphs in a monospaced font are the same width. The glyphs in a proportional font have different widths, "m" being wider than "i", for example.

Base Line, Ascent Line and Descent Line. Most glyphs in a font sit on an imaginary line called the base line. The ascent line is an imaginary horizontal line chosen by the font's designer which corresponds approximately with the tops of the uppercase letters of the font. The descent line is an imaginary line which usually corresponds to the bottom of the descenders (the tails of glyphs like "p" and "g").

Glyph Origin and Advance Width. QuickDraw begins drawing a glyph at the glyph origin. There is some white space between the glyph origin and the beginning of the glyph called the left side bearing. The advance width is the full horizontal measurement of a glyph as measured from its glyph origin to the glyph origin of the next glyph.

(Font measurement terms)

Font Size. Font size indicates the size of the font's glyphs as measured from the base line of one line of the text to the base line of the next line. Font size is measured in points (1/72 of an inch). The size of a font is often, but not always, the sum of the ascent, descent and leading (pronounced "ledding") values for a font. (The leading value is the amount of blank vertical space between the descent line of one line and the ascent line of the next line.)

The base line, ascent line, descent line, and glyph origin are illustrated at Fig 2.

System Font and Application Font

Macintosh system software recognises the following two special fonts, which should always be present:

  • The system font, which is used for menus, dialog boxes, and other messages to the user from the Finder and the Operating System. The system font is either 12 point Charcoal or 12-point Chicago, depending on the user's setting in the Appearance control panel.

  • The application font, which is the suggested default font for use by monostyled TextEdit and by applications which do not support user selection of fonts. The application font is 12-point Geneva.
The system font and application font have special font designators. The system font designator is 0 and the application font designator is 1. These special designators are not actual font family resource ID numbers and cannot be used as such in Resource Manager calls; however, they can be used in place of the font family ID in the txFont field of the colour graphics port and in text-related calls that take a font family ID. The system maps the special designators to the actual font family IDs.

The Font Manager and QuickDraw

The Font Manager keeps track of all fonts available to an application and supports QuickDraw by providing the character bitmaps that QuickDraw needs. If QuickDraw requests a typeface that is not represented in the available fonts, the Font Manager substitutes one that is. Where necessary, QuickDraw scales the font to the requested size and applies the specified style.

Aspects of Text Editing - Caret Position, Text Offsets, Selection Range, Insertion Point, and Highlighting

Caret Position and Text Offset

In the world of text editing, the caret is defined as the blinking bar which marks the insertion point of text and the cursor is the arrow, I-beam or other icon that moves with the mouse.

A caret position is a location on the screen which corresponds to an insertion point in memory. A caret position is always between glyphs on the screen. The caret is always positioned on the leading edge of the glyph corresponding to the character at the insertion point in memory. When a new character is inserted, it displaces the character at the insertion point, shifting it and all subsequent characters in the buffer forward by one position.

The relationship between caret position, insertion point and offset is illustrated at Fig 3.

(Caret position and inserion point)

Converting Screen Position to Text Offset

A mouse-down event can occur anywhere within the area of a glyph, but the caret position which is derived from that event must be an infinitesimally thin line falling between the two glyphs.

As shown at Fig 4, a line of displayed glyphs is divided into a series of mouse-down regions. A mouse-down region is a screen area within which any mouse click will yield the same caret position. It extends from the centre of one glyph to the centre of the next glyph (except at the ends of lines).

(Interpreting caret position)

Selection Range and Insertion Points

The selection range is the sequence of zero or more characters, contiguous in memory, where the next editing operation is to occur. A selection range of zero characters is called an insertion point.

Highlighting

A selection range is typically marked by highlighting, that is, by drawing the glyphs with a coloured background. The limits of highlighting rectangles are measured in terms of caret position. For example, if the characters B, C, and D at Fig 3 were highlighted, the highlighting would extend from the leading edge of B (offset = 1) to the leading edge of E (offset = 4). Outline Highlighting. Outline highlighting is the "framing" of text in the selection range in an inactive window. If there is no selection range, a grey, unblinking caret is displayed. By default, outline highlighting is disabled.

Keyboards and Text

Each keypress on a particular keyboard generates a value called a raw key code. The keyboard driver which handles the keypress uses the key-map ('KMAP') resource to map the raw key code to a keyboard-independent virtual key code. It then uses the Event Manager and the keyboard layout ('KCHR') resource to convert a virtual keycode into a character code. The character code is passed to your application in the event structure generated by the keypress.

Introduction to TextEdit

TextEdit is a collection of functions and data structures which give your application basic text formatting and editing capabilities. Its functions can be used in applications such as spreadsheets, on-line (data entry) forms, simple text editors, and drawing and painting programs with simple text-editing features. TextEdit relies on Script Manager, QuickDraw, and Text Utilities functions to handle text correctly, eliminating the need for your application to call these functions directly.

TextEdit was originally designed to handle editable text items in dialog boxes and other parts of the system software. It was subsequently enhanced to support some of the cumbersome tasks that a text processor needs to perform. That said, it was never intended to manipulate lengthy text documents in excess of 32 KB. Indeed, the limit for documents created by TextEdit is 32,767 characters.

Editing Tasks Performed by TextEdit

The fundamental editing tasks which TextEdit can perform for your application are as follows:

  • Selection of text by clicking and dragging the mouse.

  • Double-clicking to select words.

  • Extending or shortening selection ranges by Shift-clicking.

  • Highlighting the current text selection, or displaying a blinking vertical bar (the caret) at the insertion point.

  • Line breaking, that is, preventing a word from being split inappropriately between lines when text is drawn.

  • Cutting, copying, and pasting within and between applications.

  • Managing the use of more than one font, size, colour and stylistic variation from character to character.
Thus, if you do not need to manipulate large files and do not need extensive formatting capabilities, TextEdit is a convenient alternative to writing your own specialised text processing functions.

TextEdit Options

You can use TextEdit at different levels of complexity.

Using TextEdit Indirectly

For the simplest level of text handling (that is, in dialog boxes), you need not even call TextEdit directly but rather use the Dialog Manager. The Dialog Manager, in turn, calls TextEdit to edit and display text.

Displaying Static Text

If you simply want to display one or more lines of static (non-editable) text, you can call TETextBox, which draws your text in the location you specify. TETextBox may be used to display text that you cannot edit. You do not need to create an edit structure (see below) because TETextBox creates its own edit structure. TETextBox draws the text in a rectangle whose size you specify in the coordinates of the current graphics port. Using the following constants, you can specify how text is aligned in the box:

Constant Description
teFlushDefault Default alignment according to primary line direction of the script system. (Left for Roman script system.)
teCenter Centre alignment.
teFlushRight Right alignment.
teFlushLeft Left alignment.

Text Handling - Monostyled Text

If your application requires very basic text handling in a single typeface, style, and size, you probably only need monostyled TextEdit. You can use monostyled TextEdit with the application font (if you do not allow the user to select the font) or with any single available font (if you do allow user selection).

Text Handling - Multistyled Text

If your application requires a somewhat higher level of text handling (allowing the user to change typeface, style, and size within the document, for example), you must use multistyled TextEdit.

Caret Position and Movement in TextEdit

TextEdit marks the position in the displayed text where the next editing operation will occur with the caret. When TextEdit pastes text into a structure, it positions the caret after the newly pasted text. When the user presses the Up Arrow key or the Down Arrow key, the caret moves up or down one line respectively. When the caret is on the first line of an edit structure, and the user presses the Up Arrow key, TextEdit moves the caret to the beginning of text on that line. When the caret is on the last line of an edit structure, and the user presses the Down Arrow key, TextEdit moves the caret to the end of the text on that line.

TextEdit does not support the use of modifier keys, such as the Shift key, in conjunction with the arrow keys.

If spaces at the end of a text line extend beyond the view rectangle (see below), TextEdit draws the caret at the edge of the view rectangle, not beyond it. Whether TextEdit displays a caret at the beginning or end of a line when a mouse-down event occurs at a line's end depends on the current caret position and the value in the clikStuff field of the edit structure. TextEdit sets this field to reflect whether the most recent mouse-down event occurred on the leading or trailing edge of a glyph. For example, if the mouse-down event occurs on the leading edge of a glyph, TextEdit displays the caret at the caret position corresponding to the leading edge of the glyph. If the mouse-down event is on the trailing edge of a glyph, TextEdit displays the caret at the beginning of the next line.

Automatic Scrolling

One way for the user is to select large blocks of text is to click in the text and, holding the mouse button down, drag the cursor above, below, left of, or right of TextEdit's view rectangle. While the mouse button remains down, and provided that your application has enabled automatic scrolling, TextEdit continually calls its click loop function to automatically scroll the text.

Although TextEdit's default click loop function automatically scrolls the text, it cannot adjust the scroll box position in an application's scrollbars to follow up the scrolling. The default click loop function can, however, be replaced with an application-defined click loop function which accommodates scroll bars.

TextEdit Private, Null, and Style Scraps

Internally, TextEdit uses three scrap areas, namely, the private scrap, the null scrap, and the style scrap. The null scrap and the style scrap apply only to multistyled TextEdit.

Private Scrap

The private scrap, which belongs to your application, is used for all cut, copy, and paste activity. When the text is multistyled, TextEdit also copies the text to the Scrap Manager's desk scrap.

Null Scrap

The null scrap is used to store character attribute information associated with a null selection (that is, an insertion point) or text that is deleted when the user backspaces over it.

The font, style, size, and colour aspects of text are collectively referred to as character attributes.

Character attribute information is retained in the null scrap until it is used, that is, when it is applied to newly inserted text, or until some other editing action renders it unnecessary, such as when TextEdit sets a new selection range. A number of functions which deal with multistyled text check the null scrap for character attribute information and, if there is any, apply it to the newly inserted text when character attributes for that text are not available.

TextEdit creates and initialises a null scrap for a multistyled edit structure when an application creates the edit structure. The null scrap remains throughout the life of the edit structure, being disposed of when the application disposes of the edit structure and release the memory associated with it.

Style Scrap

When you cut or copy multistyled text, memory is allocated dynamically for the style scrap and the character attribute information is copied to it. Your application can also use the style scrap as follows:

  • To save and restore multistyled text, both the text and the associated character attribute information must be preserved. You can save character attributes associated with a range of text in the style scrap.

  • You can create a style scrap structure and store character attribute information in it to be applied to inserted text.

Text Alignment

The term alignment means the horizontal alignment of lines of text with respect to the left and right edges of the text area. Alignment can be left-aligned, right-aligned, centred, or justified (that is, aligned with both the left and right edges of the text area). Justification is achieved by spreading or compressing text to fit a given line width. TextEdit supports left-aligned, right-aligned and centred alignments.

Customising TextEdit

TextEdit may be customised by replacing the end-of-line, drawing, width-measuring, and hit test default hook functions using TECustomHook. You can also customise word selection, automatic scrolling, and how to determine the length of a line in order to justify it.

Primary TextEdit Data Structures

The primary data structures used by TextEdit are the edit structure and the dispatch structure. Additional data structures are associated with multistyled TextEdit. This section describes the primary data structures only.

The Edit Structure

The edit structure is the principal data structure used by TextEdit. The structure of the edit structure is the same regardless of whether the text is monostyled or multistyled, although some fields are used differently for multistyled edit structures. The edit structure is as follows:

     struct TERec
     {
       Rect       destRect;   // Destination rectangle.
       Rect       viewRect;   // View rectangle.
       Rect       selRect;    // Selection rectangle.
       short      lineHeight; // Vert spacing of lines. -1 in multistyled edit struct.
       short      fontAscent; // Font ascent. -1 in multistyled edit structure.
       Point      selPoint;   // Point selected with the mouse.
       short      selStart;   // Start of selection range.
       short      selEnd;     // End of selection range.
       short      active;     // Set when structure is activated or deactivated.
       WordBreakUPP   wordBreak;  // Word break function.
       TEClickLoopUPP clickLoop;  // Click loop function.
       long       clickTime;    // (Used internally.)
       short      clickLoc;     // (Used internally.)
       long       caretTime;    // (Used internally.)
       short      caretState;   // (Used internally.)
       short      just;         // Text alignment.
       short      teLength;     // Length of text.
       Handle     hText;        // Handle to text to be edited.
       long       hDispatchRec; // Handle to TextEdit dispatch structure.
       short      clikStuff;    // (Used internally)
       short      crOnly;       // If <0, new line at Return only.
       short      txFont; // Text font.   // If multistyled edit struct (txSize = -1),
       StyleField txFace; // Chara style. // these bytes are used as a handle
       SInt8      filler;                 // to a style structure (TEStyleHandle).
       short      txMode;       // Pen mode.
       short      txSize;       // Font size. -1 in multistyled edit structure.
       GrafPtr    inPort;       // Pointer to grafPort for this edit structure.
       HighHookUPP   highHook;  // Used for text highlighting, caret appearance.
       CaretHookUPP  caretHook; // Used from assembly language.
       short  nLines;           // Number of lines.
       short  lineStarts[16001];  // Positions of line starts.
     };
     typedef struct TERec TERec;
     typedef TERec *TEPtr;
     typedef TEPtr *TEHandle;


Field Descriptions

destRect Destination rectangle, in local coordinates.
viewRect View rectangle, in local coordinates.

When you allocate an edit structure, you specify where the text is to be drawn and where it is to be made visible. The destination rectangle is the area in which text is drawn and the view rectangle is that portion of the window within which the text is actually displayed. Fig 5 illustrates the relationship between the destination rectangle and the view rectangle.

Note that 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.

(Destination and view rectangles)

Editing operations may shorten or lengthen 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, and its top determines the position of the first line.

The destination rectangle is central to the matter of scrolling text. When text is scrolled downwards, for example, you can think of the destination rectangle as being moved upwards through the view rectangle.

selRect The selection rectangle boundaries, in local coordinates.
lineHeight The vertical spacing of lines of text. In a monostyled edit structure, the value specifies the fixed vertical distance from the ascent line of one line of text to the ascent line of the next line.

Multistyled Edit Structure. In a multistyled edit structure, this field is set to -1, which indicates that line heights are calculated independently for each line based on the maximum value for any individual character on that line.

fontAscent The font ascent line. For monostyled text, the value specifies how far above the baseline the pen is positioned to begin drawing the caret or highlighting. (For single-spaced text, this is the height of the text in pixels.)

Multistyled Edit Structure. In a multistyled edit structure, this field is set to -1, which indicates that the font ascent is calculated independently for each line based on the maximum value for any individual character on that line.

selPoint The point selected with the mouse, in the local coordinates of the current graphics port.
selStart The byte offset of the beginning of the selection range. When you create an edit structure, TextEdit initialises this field to 0. (Byte offset 0 refers to the first byte in the text buffer.)
selEnd The byte offset of the end of the selection range. (Note that, to include that byte, this value must be one greater than the position of the last byte offset of the text.) When you create an edit structure, TextEdit initialises this field to 0. With both selStart and selEnd initialised to 0, the insertion point is placed at the beginning of the text.
active Set by TextEdit when an edit structure is activated using TEActivate and then reset when the edit structure is rendered inactive using TEDeactivate.
wordBreak Universal procedure pointer to the word selection break function, which determines, firstly, the word that is highlighted when the user double-clicks in the text and, secondly, the position at which text is wrapped at the end of the line.
clickLoop Universal procedure pointer to the click loop function, which is called repeatedly as long as the mouse button is held down within the text.
just The type of text alignment (default, left, centre, or right).
teLength The number of bytes in the text to be edited. The maximum allowable length is 32,767 bytes. When you create an edit structure, TextEdit initialises this field to 0.
hText A handle to the text. When you create an edit structure, TextEdit initialises this field to point to a zero-length block in the heap.
hDispatchRec Handle to the TextEdit dispatch structure. For internal use only.
clikStuff TextEdit sets this field to reflect whether the most recent mouse-down event occurred on the leading or trailing edge of a glyph. Used internally by TextEdit to determine a caret position.
crOnly Specifies whether or not text wraps at the right edge of the destination rectangle. If the value is positive, text does wrap. If the value is negative, new lines are specified explicitly by Return characters only and text does not wrap at the edge of the destination rectangle.
txFont For a monostyled edit structure, this field specifies the font of all the text in the edit structure. If you change this value, the entire text of this edit structure has the new characteristic when it is redrawn. (If you change the value, you should also change the lineHeight and fontAscent fields as appropriate.)

Multistyled Edit Structure. In a multistyled edit structure, if the txSize field (see below) is set to -1, this field combines with txFace and filler to hold a handle to the associated style structure.

txFace For a monostyled edit structure, this field specifies the character attributes of all the text in an edit structure. If you change this value, the entire text of this edit structure has the new characteristic when it is redrawn. (If you change this value, you should also change the lineHeight and fontAscent fields as appropriate.)

Multistyled Edit Structure. If the txSize field (see below) is set to -1, this field combines with txFont and filler to hold a handle to the associated style structure.

txMode The pen mode of all the text in the edit structure. If you change this value, the entire text in this edit structure has the new characteristic when it is redrawn.
txSize In a monostyled edit structure, this field is set to the size of the text in points.

Multistyled Edit Structure. In a multistyled edit structure, this field is set to is -1, indicating that the edit structure contains associated character attribute information. The txFont, txFace, and filler fields combine to form a handle to the style structure in which this character attribute information is stored.

inPort Pointer to the graphics port associated with this edit structure.
highHook Universal procedure pointer to the function which deals with text highlighting.
caretHook Universal procedure pointer to the function that controls the appearance of the caret.
numLines The number of lines in the text.
lineStarts An array containing the character position of the first character in each line. It is declared to have 16001 elements to comply with Pascal range checking. This is a dynamic data structure having only as many elements as needed. TextEdit calculates these elements internally, so do not change the elements of this array. Because this data structure grows and shrinks, the size of the edit structure changes.

The Dispatch Structure

The hDispatchRec field of the edit structure stores a handle to the dispatch structure. The dispatch structure is an internal data structure whose fields, referred to as hook fields or hooks, contain the addresses of functions which TextEdit uses internally to, for example, measure and draw text or determine a character's position on a line. These functions, called hook functions, determine the way TextEdit behaves.

You can use a TextEdit customisation function to replace the address of a default hook function with the address of your own customised function.

Monostyled TextEdit

This section describes the use of TextEdit with monostyled text, that is, text with a single typeface, style, and size. Everything in this section also applies to using TextEdit with multistyled text except where otherwise indicated.

Initialising TextEdit

Before using TextEdit, you need to initialise TextEdit using TEInit which, amongst other things, sets up the private scrap and allocates a handle to it. You may also need to get information about the installed version of TextEdit using Gestalt with the selector gestaltTextEditVersion.

Gestalt is described at Chapter 23 - Miscellany.

Creating, and Disposing of, a Monostyled Edit Structure

Creating a Monostyled Edit Structure

To use TextEdit functions, you must first create an edit structure using TENew. TENew returns a handle to the newly-created monostyled edit structure. You typically store the returned handle in a field of a document structure, the handle to which is typically stored in the application window's refCon field.

The required destination and view rectangles are specified in the TENew call. To ensure that the first and last glyphs in each line are legible in a document window, you should inset the destination rectangle at least four pixels from the left and right edges of the graphics port, making an additional allowance for scroll bars as appropriate. You typically make the view rectangle equal to the destination rectangle. (If you do not want the text to be visible, specify a view rectangle off the screen.)

When an edit structure is created, TextEdit initialises the edit structure's fields based on values in the current colour graphics port structure and on the type of edit structure you create.

Disposing of an Edit Structure

Memory allocated for an edit structure may be released by calling TEDispose.

Setting the Text of an Edit Structure

When you create an edit structure, it does not contain any text until the user either enters text through the keyboard or opens an existing document. The following describes how to specify existing text to be edited.

There are two ways to specify existing text to be edited, namely, by using TESetText or by setting the hText field of the edit structure directly.

Calling TESetText

When a user opens a document, your application can bring the document's text into the text buffer of an edit structure by calling TESetText. TESetText creates a copy of the text and stores the copy in the existing handle of the edit structure's hText field.

One of the parameters you pass to TESetText specifies the length of the text. TESetText resets the teLength field of the edit structure with this value and uses it to determine the end of the text. It also 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. Finally, TESetText calculates the line breaks, eliminating the necessity for your application to perform that task.

TESetText does not cause the text to be displayed immediately. You must call InvalRect to force the text to be displayed at the next update event for the active window.

Changing the hText Field

The second method saves memory if you have a lot of text. In this method, you bring text into an edit structure by directly changing the hText field in the edit structure, replacing the existing handle with the handle of the new text. When you do this for a monostyled edit structure, 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 numLines values to match the new text.

Responding to Events

Activate Events

When your application receives an activate event, it must call TEActivate for an activate event and TEDeactivate for a deactivate event.

An application can have more than one edit structure associated with it. The active edit structure is the one where the next editing operation will take place. TEActivate visually identifies an edit structure as the active one by either highlighting the selection range or by displaying a caret at the insertion point. TEDeactivate changes an edit structure's status from active to inactive, removes the highlighting or caret and, if outline highlighting is enabled, frames the selection range or displays a gray, unblinking caret.

Typically, you include edit structure activation and deactivation in that function in your application which handles window activation and deactivation. That said, it is possible to modify the text of an edit structure associated with a background window; however, to do so, you need to call TEActivate for that edit structure before you call any other TextEdit functions.

Note that, when you use TEClick and TESetSelect (see below) to set the selection range or insertion point, the selection range is not highlighted and the blinking caret is not displayed until the edit structure is activated. (However, if outline highlighting is activated, the text of the selection range is framed or a gray, unblinking caret is displayed.)

Outline highlighting may be activated and deactivated using TEFeatureFlag.

Update Events - Calling TEUpdate

Your application needs to call TEUpdate every time the Event Manager reports an update event for a text editing window. In addition, you must call TEUpdate after changing any fields of the edit structure which affect the appearance of the text or after any editing or scrolling operation which alters the onscreen appearance of the text.

EraseRect and TEUpdate should be called after BeginUpdate and before EndUpdate. (If you do not include the EraseRect call, the black caret may sometimes remain visible (unblinking) when the window is deactivated.)

Mouse-Down Events - Calling TEClick

When your application receives notification of a mouse-down event that it determines TextEdit should handle, it must pass the event on to TEClick. TEClick tells TextEdit that a mouse-down event has occurred. Before calling TEClick, however, your application must perform the following steps:

  • Convert the mouse location passed in the event structure from global coordinates to the local coordinates required by TEClick.

  • Determine if the Shift key was held down at the time of the event.
TEClick repeatedly calls the click loop function (see below) as long as the mouse button is held down and retains control until the button is released. The behaviour of TEClick depends on whether the Shift key was down at the time of the mouse-down event and on other user actions as follows:

User's Action Behaviour of TEClick
Shift key down. Extend the current selection range.
Shift key not down. Remove highlighting from current selection range. Position the insertion point as close as possible to the location of the mouse click.
Mouse dragged. Expand or shorten the selection range a character at a time. Keep control until the user releases the mouse button.
Double-click. Extend the selection to include the entire word where the cursor is positioned.

When TEClick is called, the clickTime field of the edit structure contains the time when TEClick was last called. When TEClick returns, it sets the clickTime field, adjusting the current tick count. The default click loop function uses this value.

Key-Down Events - Accepting Text Input

When your application receives a key-down event which it determines TextEdit should handle, it must call TEKey to accept the keyboard input a byte at a time (or to delete a character when the user backspaces over it). TEKey replaces the current selection range with the character passed to it and moves the insertion point just past the inserted character.

Depending on the requirements of your application, you may need to filter out certain character codes (for example, that for a Tab key press) so that they are not passed to TEKey. You should also check that the TextEdit limit of 32,767 bytes will not be exceeded by the insertion of the character before calling TEKey and you should call your scroll bar adjustment function immediately after the insertion.

Null Events - Caret Blinking

To force the insertion point caret to blink, your application must call TEIdle whenever it receives a null event. You must also ensure that the sleep parameter in the WaitNextEvent call is set to a value equal to or less than the value stored in the low-memory global CaretTime, which determines the blinking time for the caret. That value can be retrieved by a call to LMGetCaretTime.

The blinking time is set by the user using the General Controls Control Panel.

If there is more than one edit structure associated with an active window, you must ensure that you pass TEIdle the handle to the currently active edit structure. You should also check that the handle to be passed to TEIdle does not contain NULL before calling the function.

Cutting, Copying, Pasting, Inserting, and Deleting Text

Cutting, Copying, and Pasting

You can use TextEdit to cut, copy, and paste text within a single edit structure, between edit structures, or across applications. The relevant functions, and their effect in the case of a monostyled edit structure, are as follows:

Function Use To Comments
TECut Cut text. Copies the text to the TextEdit private scrap.
TECopy Copy text. Copies the text to the TextEdit private scrap.
TEPaste Paste text. Pastes from the TextEdit private scrap to the edit structure. (Used for monostyled text only.)
TEToScrap Copy TextEdit private scrap to the Scrap Manager's desk scrap. Copying via the Scrap Manager's desk scrap is required if monostyled text is to be carried across applications.
TEFromScrap Copy the Scrap Manager's desk scrap to TextEdit private scrap. Copying via the Scrap Manager's desk scrap is required if monostyled text is to be carried across applications.
TEGetScrapLength Determine the length of the monostyled text to be pasted. Returns the size, in bytes, of the text in the private scrap.

If you are using TEFromScrap to support pasting to your application from the desk scrap, you will need to ensure that a paste will not cause the TextEdit limit of 32,767 bytes to be exceeded. One way to do this is to call the Scrap Manager's GetScrap function to get the size of the text to be pasted, add this to the size of the text in the edit structure, subtract the size of the selection range, and then compare the result against the maximum allowable length of the edit structure.

You will need to call your vertical scroll bar adjustment function immediately after cut and paste operations.

Inserting and Deleting Text

The following TextEdit functions are used to insert and delete monostyled text:

Function Use To Comments
TEInsert Insert monostyled text into the edit structure immediately before the selection range or insertion point. Does not affect the selection range.

Redraws the text if necessary.

Use for monostyled text only.

TEDelete Remove the selected range of text from the edit structure. Does not transfer the text to either TextEdit's private scrap or the Scrap Manager's desk scrap.

Useful for implementing a Clear command.

Redraws the remaining text if necessary.

You will need to call your vertical scroll bar adjustment function immediately after insertions and deletions. In addition, you will need to ensure that an insertion will not cause the TextEdit limit of 32,767 bytes to be exceeded.

Setting the Selection Range or Insertion Point

You can use TESetSelect to specify the selection range or the position of the insertion point as determined by the application. For example, you can use TESetSelect to position the caret at the start of a data entry field where you want the user to enter a value. TESetSelect modifies the selStart and selEnd fields of the edit structure.

To select a range of text, you pass TESetSelect the handle to the edit structure along with the byte offsets of the starting and ending characters. You can set the selection range (or insertion point) to any character position corresponding to byte offsets 0 to 32767. To display a caret at the insertion point, specify the same values for the selStart and selEnd parameters.

To implement a Select All menu command, specify 0 for starting offset parameter and use the teLength field of the edit structure for the ending offset parameter.

Enabling, Disabling, and Customising Automatic Scrolling

Enabling and Disabling

You can use the TEAutoView function to enable automatic scrolling (which, by default, is disabled). TEAutoView may also be used to disable automatic scrolling.

Customising

As previously stated, the default click loop function does not adjust the scroll bars as the text is scrolled, a situation which can be overcome by replacing the default click loop function with an application-defined click loop function which updates the scroll bars as it scrolls the text.

The clickLoop field of the edit structure contains a universal procedure pointer to a click loop function, which is called continuously as long as the mouse button is held down. Installing your custom function involves a call to TESetClickLoop to assign the universal procedure pointer to the edit structure's clickLoop field.

Scrolling Text

To scroll the text when a mouse-down event occurs in a scroll bar, your application needs to first determine how far to scroll the text. The basic value for vertical scrolling of a monostyled edit structure is typically the value in the lineHeight field of the edit structure, which can be used as the number of pixels to scroll for clicks in the Up and Down scroll arrows. For clicks in the gray areas, this value is typically multiplied by the number of text lines in the view rectangle minus 1. Scrolling by dragging the scroll box involves determining the number of text lines to scroll based on the current position of the top of the destination rectangle and the control value on mouse button release.

To scroll the text, you can use either TEScroll or TEPinScroll, specifying the number of pixels to scroll. The only difference between these two functions is that TEPinScroll stops scrolling when the last line is scrolled into the view rectangle. The destination rectangle is offset by the amount you scroll.

Forcing the Selection Range Into the View

Your application can call TESelView to force the selection range to be displayed in the view rectangle. When automatic scrolling is enabled, TESelView scrolls the selection range into view, if necessary.

Setting Text Alignment

You can change the alignment of the entire text of an edit structure by calling TESetAlignment (old name TESetJust). The following constants apply:

Constant Description
teFlushDefault Default alignment according to primary line direction of the script system. (Left for Roman script system.)
teCenter Centre alignment.
teFlushRight Right alignment.
teFlushLeft Left alignment.

You should call the Window manager's InvalRect function after you change the alignment so that the text is redrawn in the new alignment.

Saving and Opening TextEdit Documents

The demonstration program at Chapter 16 - Files demonstrates opening and saving monostyled TextEdit documents.

Multistyled TextEdit

This section addresses additional factors and considerations applying to multistyled TextEdit.

Text With Multiple Styles - Style Runs, Text Segments, Font Runs, and Character Attributes

Text which uses a variety of fonts, styles, sizes, and colours is referred to as multistyled text.

TextEdit organises multistyled text into style runs, which comprise a sets of contiguous characters which all share the same font, size, style, and colour characteristics. TextEdit tracks style runs in the data structures allocated for a multistyled edit structure and uses this information to correctly display multistyled text.

The part of a style run that exists on a single line is called a text segment. A larger division than a style run is the font run, which comprises those characters which share the same font. The font, style, size, and colour aspects of text are collectively referred to as character attributes.

Additional TextEdit Data Structures for Multistyled Text

The edit structure and the dispatch structure are the only data structures associated with monostyled text. However, when you allocate a multistyled edit structure, a number of additional subsidiary data structures are created to support the text styling capabilities. The additional data structures associated with a multistyled edit structure are shown at Fig 6.

(Style structure and subsidiary data structures)

The Style Structure

The first of these additional data structures is the style structure, which stores the character attribute information for the text. (Recall that, when a multistyled edit structure is created, the bytes at the txFace, txFace, and filler fields of the edit structure contain a handle to the style structure.) The remaining additional data structures are, in fact, elements of the style structure. Those elements are as follows:

  • A handle to a style table, which has one entry for each distinct set of character attributes in the edit structure. Each element in the style table is a style table element structure.

  • A handle to the line-height table, which provides vertical spacing and line ascent information for the text to be edited. The line-height table comprises one line-height element structure for each line of an edit structure. A line number is a direct index into the array of line-height element structures.

  • A style run table, which is an array of style run structures, each of which provides, for each style run, the offset of the starting character to which the character attributes stored in the style table apply and an index into the style table.

  • A handle to the null style structure, which contains a handle to the style scrap structure. The style scrap structure, which is part of the style scrap, stores character attribute information associated with a null selection to be applied to inserted text. It also holds character attribute information associated with a selected range of multistyled text when the character attributes are to be copied, or the text and its attributes are to be cut and copied. Part of the style scrap structure is the scrap style table, which comprises one scrap style element structure for each style run in the style scrap structure. Scrap style element structures hold character attribute information similar to that contained in the style table element structure.

Creating a Multistyled Edit Structure

The multistyled edit structure is created by calling TEStyleNew.

Setting the Text

The alternative method of setting the text (that is, directly setting the hText field of the edit structure) is somewhat more cumbersome for a multistyled text because TECalText does not update the style run table properly. To compensate for this, your application needs to perform the following tasks:

  • Before changing the edit structure's hText field, reduce the style run table to one entry. Do this by setting the edit structure's selStart field to 0 and the selEnd field to 32,767, and then call TESetStyle.

  • Before calling TECalText, set the start character (startChar) field of the style run table to the length of the new text plus one.

TEKey and Multistyled Text

When the user backspaces over characters in a multistyled edit structure, TEKey deletes the characters (as in a monostyled edit structure) but also saves the character attributes associated with the last character deleted in order to apply it to any new characters the user enters. The character attributes are saved in the null scrap's style scrap structure. As soon as the user clicks in another area of the text, TEKey clears the attributes from the null scrap.

Cutting, Copying, Pasting, Inserting, and Deleting Text

The following shows the effects of TECut and TECopy when multistyled text is involved. It also describes TEStylePaste, which is used for pasting multistyled text, and the additional function (TENumStyles), which is involved in cutting and copying multistyled text:

Function Use To Comments
TECut
TECopy
Cut text.
Copies text.
For multistyled text:
  • Copies both the text and its character attribute information to the Scrap Manager's desk scrap under scrap types 'TEXT' and 'styl'.
  • Copies the text to the TextEdit private scrap and the attributes stored in the style table to the TextEdit style scrap.
TEStylePaste Paste multistyled text. Pastes both the text and its attributes from the Scrap Manager's desk scrap to the edit structure.

(Use the Scrap Manager function GetScrap to check the size of the text ('TEXT' data) to be pasted, passing NULL for the hDest parameter to avoid copying the data.)

TENumStyles Determine the memory required for the style scrap before cutting or copying multistyled text. TENumStyles returns the number of attribute changes contained in the range of text. Multiply this by sizeof(ScrpSTElement) and add two to get the number of bytes required.

The following describes TEStyleInsert, which is used to insert multistyled text, and the additional effects of TEDelete when used to delete multistyled text:

Function Use To Comments
TEStyleInsert Insert multistyled text into the edit structure immediately before the selection range or insertion point. Does not affect the selection range.

Redraws the text if necessary.

Applies the specified character attributes to the text. (You should create your own style scrap structure, specifying the style attributes to be inserted and applied to the text. These attributes are copied directly into the style structure's style table.)

TEDelete Remove the selected range of text from the edit structure. Does not transfer the text to either TextEdit's private scrap or the Scrap Manager's desk scrap.

Redraws the remaining text if necessary.

For multistyled text, the character attributes are saved in the null scrap to be applied to characters after the text has been deleted. When the user clicks in some other area of the text, the attributes are removed from the null scrap.

TEDelete can be used to implement a Clear command.

Scrolling Text

The number of pixels to be scrolled vertically for each line of text to be scrolled (determined from the lineHeight field in a monostyled edit structure) is determined from the lnHeight field of the line height table in multistyled edit structures.

Setting and Checking Text Attributes

Your application may need to check the current attributes of a range of text to determine which ones are consistent across a range of text. Your application may also need to manipulate the font, style, size, and colour of a range of text, the text selection consisting of the entire text of the edit structure, a segment of text, a single character, or even an insertion point. The following functions are relevant in this regard:

Function Use To Comments
TESetStyle Change the font, size, style and/or colour of the text in the selection range. Typically used to implement menu commands relating to modifying text attributes.

If called for an insertion point, TextEdit stores the specified attribute information in the null scrap's style scrap structure.

TEContinuousStyle Examine the current selection range and determine whether a specified style attribute is continuous across the range. Can be used as an aid in toggling styles or to determine which of the items in a Style menu should have a checkmark.

The mode parameter specifies which attributes of the selected text are to be examined.

Checking Attributes in a Selection Range

The following example application-defined function shows how to determine the font, size, style and colour of the current selection range.

void  doGetCurrentSelection(TextStyle *textStyleRec,TEHandle editRecHdl)
{
  SInt16   mode;
  Boolean  continuous;

  // doFont, doFace, doSize, and doColor are constants which specify font family
  // number, character style, type size, and colour

  mode = doFont + doFace + doSize + doColor;
  continuous = TEContinuousStyle(&mode,textStyleRec,editRecHdl);

  // When TEContinuousStyle returns, each bit in mode that was set on entry will
  // have been cleared if that style element was not continuous.  For those 
  // attributes which were continuous, the text style (TextStyle) structure fields
  // will contain the actual values.

  if((mode & doFont) != 0)
    // Font for selection = tsFont field of the TextStyle structure.
  else
    // More than one font in selection.

  if((mode & doFace) != 0)
    // tsFace field of the TextStyle structure contains the styles (or plain)
    // common to the selection.
  else
    // No text face is common to the entire selection.

  if((mode & doSize) != 0)
    // Size for selection = tsSize field of the TextStyle structure.
  else
    // More than one size in selection.

  if((mode & doColor) != 0)
    // Color for selection = tsColor field of the TextStyle structure.
  else
    // More than one colour in selection.
}

Handling a Font Menu

The following example application-defined function shows how to handle a Font menu item selection.

void  doFontMenu(WindowPtr windowPtr,TEHandle editRecHdl,SInt16 menuItem)
{
  TextStyle styleRec;
  Str255    fontName;
  SInt16    fontID;

  GetMenuItemText(GetMenuHandle(mFont),menuItem,fontName); // Get text of item.
  GetFNum(fontName,&fontID);           // Get font number matching font name.
  styleRec.tsFont = fontID;            // Assign to tsFont field of text style 
                                       // structure.
  TESetStyle(doFont,&styleRec,true,editRecHdl); // Apply style to selected text ...
                                                // and redraw text immediately.
  doAdjustScrollBars(windowPtr,false);          // Adjust scroll bars.
}

Handling a Size Menu

The following example application-defined function shows how to handle a Size menu item selection.

void  doSizeMenu(WindowPtr windowPtr,TEHandle editRecHdl,SInt16 menuItem)
{
  SInt16    sizeChosen;
  TextStyle styleRec;

  doGetSize(GetMenuHandle(mSize),menuItem,sizeChosen); // Get size from item.
  styleRec.tsSize = sizeChosen;                    // Assign to tsSize field of
                                                   // text style structure.
  TESetStyle(sizeChosen,&styleRec,true,editRecHdl);// Apply size to selected text ...
                                                   // and redraw text immediately.
  doAdjustScrollBars(windowPtr,false);             // Adjust scroll bars.
}

Handling a Style Menu

The following example application-defined function shows how to handle a Style menu item selection.

void  doHandleStyleMenu(WindowPtr windowPtr,TEHandle editRecHdl,SInt16 menuItem)
{
  TextStyle  styleRec;

  switch menuItem
  {
    case iPlain:
      styleRec.tsFace = (Style) normal;
      break;

    case iBold:
      styleRec.tsFace = (Style) bold;
      break;

    case iItalic:
      styleRec.tsFace = (Style) italic;
      break;

    case iUnderline:
      styleRec.tsFace = (Style) underline;
      break;

    case iOutline:
      styleRec.tsFace = (Style) outline;
      break;

    case iShadow:
      styleRec.tsFace = (Style) shadow;
      break;
  }

  if(menuItem != 1)                                    // If Plain not selected
    TESetStyle(doFace + doToggle,&styleRec,true,editRecHdl) // include doToggle.
  else                                                 // If Plain selected
    TESetStyle(doFace,&styleRec,true,editRecHdl);           // delete doToggle.

  doAdjustScrollBars(windowPtr,false);
}

Note that, if you call TESetStyle with the value of false for the redraw parameter, TextEdit does not redraw the text or recalculate line breaks, line heights or font ascents until the next update occurs. This will cause problems if you call a function that uses any of this information before the update occurs.

The following example application-defined function checks the character attributes of the current selection range and, for each style that is continuous across the range, marks the item in the Style menu.

void  doAdjustStyleMenu(TEHandle editRecHdl)
{
  MenuHandle  styleMenuHdl;
  TextStyle   styleRec;
  SInt16      mode;

  mode = doFace;
  styleMenuHdl = GetMenuHandle(mStyle);

  // If TEContinuousStyle returns true, there is at least one style that is 
  // continuous over the selection.  Note that it might be plain, which is the
  // absence of styles.

  if(TEContinuousStyle(&mode,&styleRec,editRecHdl))               // There is a 
  {                                                               // continuous 
    CheckMenuItem (styleMenuHdl,iPlain,styleRec.tsFace == normal);// style so mark
    CheckMenuItem (styleMenuHdl,iBold,styleRec.tsFace & bold);    // all menu items
    CheckMenuItem (styleMenuHdl,iItalic,styleRec.tsFace & italic);// appropriately.
    // Set other items as appropriate.
  }
  else                                                    // There is no continuous
  {                                                       // style so unmark all
    CheckMenuItem (styleMenuHdl,iPlain,false);            // menu items.
    CheckMenuItem (styleMenuHdl,iBold,false);
    CheckMenuItem (styleMenuHdl,iItalic,false);
    // Set other items as appropriate.
  }
}

Handling the Undo Command

If you are implementing an Undo command for multistyled text, you need to save the character attribute information along with the text. There are a number of ways to do this. For example, when you want to save the current attributes of the selected text to allow the user to revert to them, your application calls TEGetStyleScrapHandle, which returns a handle to the style scrap's style structure containing the attributes used for the selected text.

To restore the style later, you call TEUseStyleScrap. You also need to save the offsets into the edit structure's text buffer of the first and last characters to which the character attribute information is applied.

Saving and Opening Multistyled TextEdit Documents

Saving a Multistyled TextEdit Document

To save the contents of a document created with a multistyled edit structure, you need to save all the associated character attribute information in addition to the text.

For the font, remember to save the font name, not the font number.

Because the text attribute information in the style scrap is easier to export that the style structure itself (because it uses the Desk Manager's 'styl' format), you should use the TextEdit functions that use the style scrap for moving character attribute information (TEGetStyleScrapHandle and TEUseStyleScrap). For example, you can use the following steps to save a multistyled text document to disk:

  • Create a text file, select all the text of the edit structure, and save it to the data fork.

  • Call TEGetStyleScrapHandle to get a handle to the style scrap structure. This creates the style scrap structure and uses it to store the character attribute information.

  • Save the character attribute information in the resource fork of the file.
The following example application-defined function uses this method.

void doSaveAsTextEdit(TEHandle editRecHdl)
{
  StandardFileFileReply fileReply;
  StScrpHandle          styleScrapHdl;
  SInt32                dataLength;
  SInt16                dataRefNum;
  SInt16                rsrcRefNum;
  SInt16                savedStart;
  SInt16                savedEnd;
  OSErr                 osError;
  Handle                editText;

  StandardPutFile("\pSave as:","\pUntitled",&fileReply);
  if(fileReply.sfGood)
  {
    savedStart = (*editRecHdl)->selStart;             // Save current selection ...
    savedEnd = (*editRecHdl)->selEnd;                 // starting and ending offsets.

    (*editRecHdl)->selStart = 0;                      // Select all text. (Do not ..
    (*editRecHdl)->selEnd = (*editRecHdl)->teLength;  // use TESetSelect.)
    styleScrapHdl == GetStylScrap(editRecHdl);        // Get list of all attributes.
    (*editRecHdl)->selStart = savedStart;             // Reset original selection.
    (*editRecHdl)->selEnd = savedEnd;

    if(!(fileReply.sfReplacing))                      // Create file & resource ...
    {                                                 // fork if not already created.
      osError = FSpCreate(&fileReply.sfFile,'K JB','TEXT',fileReply.sfScript);
      FSpCreateResFile(fileReply,sfFile,'K JB','TEXT',fileReply.sfScript);
      osError = ResError();
    };

    osError = FSpOpenDF(&fileReply.sfFile,fsCurPerm,&dataRefNum);// Open data fork ..
    rsrcRefNum = FSpOpenResFile(&fileReply.sfFile,fsCurPerm);    // and resource fork.
    osError = ResError();

    dataLength = (*editRecHdl)->teLength;               // Write text.
    editText = (*editRecHdl)->hText;
    osError = FSWrite(dataRefNum,&dataLength,*editText);

    AddResource((Handle) styleScrapHdl,'styl',0,"\p");  // Write attributes.
    WriteResource((Handle) styleScrapHdl);
    ReleaseResource((Handle) styleScrapHdl);

    osError = FSClose(dataRefNum);                      // Close data fork ...
    CloseResFile(rsrcRefNum);                           // and resource fork.
    osError = ResError();
  }
}
     
Notice that this function avoids using TESetSelect to select all of the edit structure's text. TESetSelect sets and highlights the selection range that you specify. You do not want the text to be highlighted because this could mislead the user into presuming that some other action is required.

However, if you want to use TESetSelect, you can circumvent highlighting of the selection range if you first render the edit structure inactive. Also, if you have the outline highlighting feature turned on, turn it off.

Opening a Multistyled TextEdit Document

The following example application-defined function shows how to open a multistyled TextEdit document:

void doOpenAsTextEdit(TEHandle editRecHdl)
{
  StandardFileFileReply fileReply;
  SFFileTypes           fileTypes;  
  SInt16                dataRefNum;
  SInt16                rsrcRefNum;
  Handle                textBuffer;
  SInt32                textLength;
  StScrpHandle          styleScrapHdl;
  OSErr                 osError;
  UInt8                 savedState;

  fileTypes[0] = 'TEXT';

  StandardGetFile(NULL,1,fileTypes,&fileReply);
  if(fileReply.sfGood)
  {
    osError = FSpOpenDF(&fileReply.sfFile,fsCurPerm,&dataRefNum);
    osError = SetFPos(dataRefNum,fsFromStart,0);
    osError = GetEOF(dataRefNum,&textLength);

    if(textlength > 32767)
      textLength = 32767;

    textBuffer = NewHandle((Size) textLength);            // Allocate buffer for text.
    osError = FSRead(dataRefNum,&textLength,*textBuffer); // Read text to buffer.
    LockHHi(textBuffer);
    TESetText(*buffer,textlength,editRecHdl);           // Put text in edit structure.
    HUnlock(textBuffer);
    DisposeHandle(textBuffer);                          // Get rid of buffer.

    osError = FSClose(dataRefNum);                      // Close data fork.

    rsrcRefNum := FSpOpenResFile(&fileReply.sfFile,fsCurPerm);  // Open resource fork.
    osError = ResError();

    styleScrapHdl = GetResource('styl',0);              // Get style scrap.
    osError = ResError();
    if(styleScrapHdl != NULL)
    {                                                   // Apply attributes ...
      savedState = HGetState((Handle) styleScrapHdl);   // to edit structure
      TEUseStyleScrap(0,textLength,styleScrapHdl,true,editRecHdl);
      HSetState((Handle) styleScrapHdl,savedState);
    }

    CloseResFile(rsrcRefNum);                           // Close resource fork.
    osError = ResError();
  }
}


Go to Part 2
 

Community Search:
MacTech Search:

Software Updates via MacUpdate

Latest Forum Discussions

See All

Whitethorn Games combines two completely...
If you have ever gone fishing then you know that it is a lesson in patience, sitting around waiting for a bite that may never come. Well, that's because you have been doing it wrong, since as Whitehorn Games now demonstrates in new release Skate... | Read more »
Call of Duty Warzone is a Waiting Simula...
It's always fun when a splashy multiplayer game comes to mobile because they are few and far between, so I was excited to see the notification about Call of Duty: Warzone Mobile (finally) launching last week and wanted to try it out. As someone who... | Read more »
Albion Online introduces some massive ne...
Sandbox Interactive has announced an upcoming update to its flagship MMORPG Albion Online, containing massive updates to its existing guild Vs guild systems. Someone clearly rewatched the Helms Deep battle in Lord of the Rings and spent the next... | Read more »
Chucklefish announces launch date of the...
Chucklefish, the indie London-based team we probably all know from developing Terraria or their stint publishing Stardew Valley, has revealed the mobile release date for roguelike deck-builder Wildfrost. Developed by Gaziter and Deadpan Games, the... | Read more »
Netmarble opens pre-registration for act...
It has been close to three years since Netmarble announced they would be adapting the smash series Solo Leveling into a video game, and at last, they have announced the opening of pre-orders for Solo Leveling: Arise. [Read more] | Read more »
PUBG Mobile celebrates sixth anniversary...
For the past six years, PUBG Mobile has been one of the most popular shooters you can play in the palm of your hand, and Krafton is celebrating this milestone and many years of ups by teaming up with hit music man JVKE to create a special song for... | Read more »
ASTRA: Knights of Veda refuse to pump th...
In perhaps the most recent example of being incredibly eager, ASTRA: Knights of Veda has dropped its second collaboration with South Korean boyband Seventeen, named so as it consists of exactly thirteen members and a video collaboration with Lee... | Read more »
Collect all your cats and caterpillars a...
If you are growing tired of trying to build a town with your phone by using it as a tiny, ineffectual shover then fear no longer, as Independent Arts Software has announced the upcoming release of Construction Simulator 4, from the critically... | Read more »
Backbone complete its lineup of 2nd Gene...
With all the ports of big AAA games that have been coming to mobile, it is becoming more convenient than ever to own a good controller, and to help with this Backbone has announced the completion of their 2nd generation product lineup with their... | Read more »
Zenless Zone Zero opens entries for its...
miHoYo, aka HoYoverse, has become such a big name in mobile gaming that it's hard to believe that arguably their flagship title, Genshin Impact, is only three and a half years old. Now, they continue the road to the next title in their world, with... | Read more »

Price Scanner via MacPrices.net

B&H has Apple’s 13-inch M2 MacBook Airs o...
B&H Photo has 13″ MacBook Airs with M2 CPUs and 256GB of storage in stock and on sale for up to $150 off Apple’s new MSRP, starting at only $849. Free 1-2 day delivery is available to most US... Read more
M2 Mac minis on sale for $100-$200 off MSRP,...
B&H Photo has Apple’s M2-powered Mac minis back in stock and on sale today for $100-$200 off MSRP. Free 1-2 day shipping is available for most US addresses: – Mac mini M2/256GB SSD: $499, save $... Read more
Mac Studios with M2 Max and M2 Ultra CPUs on...
B&H Photo has standard-configuration Mac Studios with Apple’s M2 Max & Ultra CPUs in stock today and on Easter sale for $200 off MSRP. Their prices are the lowest available for these models... Read more
Deal Alert! B&H Photo has Apple’s 14-inch...
B&H Photo has new Gray and Black 14″ M3, M3 Pro, and M3 Max MacBook Pros on sale for $200-$300 off MSRP, starting at only $1399. B&H offers free 1-2 day delivery to most US addresses: – 14″ 8... Read more
Department Of Justice Sets Sights On Apple In...
NEWS – The ball has finally dropped on the big Apple. The ball (metaphorically speaking) — an antitrust lawsuit filed in the U.S. on March 21 by the Department of Justice (DOJ) — came down following... Read more
New 13-inch M3 MacBook Air on sale for $999,...
Amazon has Apple’s new 13″ M3 MacBook Air on sale for $100 off MSRP for the first time, now just $999 shipped. Shipping is free: – 13″ MacBook Air (8GB RAM/256GB SSD/Space Gray): $999 $100 off MSRP... Read more
Amazon has Apple’s 9th-generation WiFi iPads...
Amazon has Apple’s 9th generation 10.2″ WiFi iPads on sale for $80-$100 off MSRP, starting only $249. Their prices are the lowest available for new iPads anywhere: – 10″ 64GB WiFi iPad (Space Gray or... Read more
Discounted 14-inch M3 MacBook Pros with 16GB...
Apple retailer Expercom has 14″ MacBook Pros with M3 CPUs and 16GB of standard memory discounted by up to $120 off Apple’s MSRP: – 14″ M3 MacBook Pro (16GB RAM/256GB SSD): $1691.06 $108 off MSRP – 14... Read more
Clearance 15-inch M2 MacBook Airs on sale for...
B&H Photo has Apple’s 15″ MacBook Airs with M2 CPUs (8GB RAM/256GB SSD) in stock today and on clearance sale for $999 in all four colors. Free 1-2 delivery is available to most US addresses.... Read more
Clearance 13-inch M1 MacBook Airs drop to onl...
B&H has Apple’s base 13″ M1 MacBook Air (Space Gray, Silver, & Gold) in stock and on clearance sale today for $300 off MSRP, only $699. Free 1-2 day shipping is available to most addresses in... Read more

Jobs Board

Medical Assistant - Surgical Oncology- *Apple...
Medical Assistant - Surgical Oncology- Apple Hill Location: WellSpan Medical Group, York, PA Schedule: Full Time Sign-On Bonus Eligible Remote/Hybrid Regular Apply Read more
Omnichannel Associate - *Apple* Blossom Mal...
Omnichannel Associate - Apple Blossom Mall Location:Winchester, VA, United States (https://jobs.jcp.com/jobs/location/191170/winchester-va-united-states) - Apple Read more
Cashier - *Apple* Blossom Mall - JCPenney (...
Cashier - Apple Blossom Mall Location:Winchester, VA, United States (https://jobs.jcp.com/jobs/location/191170/winchester-va-united-states) - Apple Blossom Mall Read more
Operations Associate - *Apple* Blossom Mall...
Operations Associate - Apple Blossom Mall Location:Winchester, VA, United States (https://jobs.jcp.com/jobs/location/191170/winchester-va-united-states) - Apple Read more
Business Analyst | *Apple* Pay - Banco Popu...
Business Analyst | Apple PayApply now " Apply now + Apply Now + Start applying with LinkedIn Start + Please wait Date:Mar 19, 2024 Location: San Juan-Cupey, PR Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.