Configure player

Close

WWDC Index does not host video files

If you have access to video files, you can configure a URL pattern to be used in a video player.

URL pattern

preview

Use any of these variables in your URL pattern, the pattern is stored in your browsers' local storage.

$id
ID of session: wwdc2002-306
$eventId
ID of event: wwdc2002
$eventContentId
ID of session without event part: 306
$eventShortId
Shortened ID of event: wwdc02
$year
Year of session: 2002
$extension
Extension of original filename: mov
$filenameAlmostEvery
Filename from "(Almost) Every..." gist: ...

WWDC02 • Session 306

Cocoa Text

Cocoa • 1:00:54

Cocoa provides a sophisticated and comprehensive text system for entering, editing, and drawing text in multiple scripts. It includes advanced typography features and support for a variety of text services, such as spell checking. Using demos and examples, this session presents an overview of text concepts, the Cocoa text system architecture, and additional text-related services and classes, including those added in the past year. This session information is aimed at both beginning and experienced Cocoa developers.

Speaker: Doug Davidson

Unlisted on Apple Developer site

Transcript

This transcript was generated using Whisper, it has known transcription errors. We are working on an improved version.

Good afternoon, everyone. I'm here to talk to you about the Cocoa text system. I'm Doug Davidson. So one of the most important features of Cocoa is its powerful and sophisticated text system. The text system is very important to Cocoa because it is involved in just about everything in Cocoa that puts text up on the screen. Now, by now, most of you have probably seen our instant text editor demo, and you probably all worked with applications like TextEdit and Mail and Project Builder. So you should have some idea of the sorts of features that the Cocoa text system provides you by default.

But what may not be quite so obvious is that the text system is also designed to be highly customizable in a variety of ways. For example, you might have taken a look at a couple of new applications, iChat and the new Address Book application. These are both Cocoa applications, and they may be a little bit more sophisticated than the other applications. But they are both very easy to use. And they are very easy to use. And they are very easy to use.

And they are very easy to use. And they are very easy to use. And they are very easy to use. And they make use of the Cocoa text system to do some rather interesting things. Now, I want to say, we did not add anything to the text system to support these applications. What they did with the text system, any of you could do with the sort of things that I'm going to be talking about today.

So I'm not going to be able to go into great detail on any one area, but what I want to do is at least tell you where you can get started for each different kind of modification. What I'm going to do is first I'll talk about some general principles and how the text system operates and how it's used, and I'll discuss how you can customize it, and I'll give some very simple examples of this.

So, you probably know by now that Cocoa fundamentally deals with strings as sequences of Unicode characters. But the fundamental object for the text system is not the string, but the attributed string. That is, sequence of characters with certain attributes attached to a given character. And these attributes can be any of a wide variety of things. They might be character level attributes like fonts or colors. They might be paragraph level attributes, things like margins, indentation, justification, and so forth, and a variety of other things.

So the job of the text system is to take an attributed string and convert it into the sort of things that you might see displayed up on the screen when there's text. Now, These things that are displayed on the screen are not characters, but they may look like it. They're glyphs.

A glyph is an individual, displayable element in a particular font. And the relationship between characters and glyphs is not simple. It's not necessarily one-to-one. It may be that a single character ends up being represented by several different glyphs, and it may be that several different characters combine and are represented by a single glyph.

What the text system does is to take this attributed string and convert it into a list of glyphs. Then it takes these glyphs and it positions them appropriately for display, breaks them up into lines and positions them. And then it passes them on down to Quartz to be rendered and displayed on the screen. So one other fundamental concept is the container. And a container represents a geometrical region within which text is laid out, for example, such as a page or a column on a page.

So, for example, we might have a character that represents an A with an acute accent. and it might have some attributes, like a font, Helvetica 64, and a color blue. Now, depending on the font, or possibly even on the font implementation, this might be represented by a single A accent glyph, or it might be represented by two glyphs, an A glyph and an accent glyph. The text system figures that out. calculates these glyphs and then positions them appropriately to get the final displayed result, which is, appropriately, a blue accented A in the right font.

Now, in order to do this job, the text system goes through a number of separate processes. In an attributed string, conceptually, you could have any combination of characters with any attributes. But that doesn't necessarily mean that every combination makes sense. The job of attribute fixing is to reform the text so that the combination of characters and attributes does make sense. For example, we make sure that the font attribute associated with a given character is a font that can actually display that character.

And we make sure that paragraph-level attributes are actually constant over the length of a given paragraph, that is, from one hard-line break character to the next.

[Transcript missing]

is Glyph Generation, in which the text system takes the characters and their attributes and combines them to form a list of glyphs.

Then the next process is layout, in which the glyphs are positioned within their containers, broken up into lines, positioned within the lines. And finally, we have display, in which the list of glyphs is marched up with their positions and sent on down to Quartz to be rendered. Now, it's characteristic of the Cocoa text system that these processes are generally performed lazily, automatically, on demand, as they are needed when some particular information is required that needs them.

So, for example, the display mechanism follows the standard Cocoa pattern, where typically a view will have "set needs display" called on it, which will eventually, later on, cause some display as needed. But because all of these processes are typically on demand, what often happens is that this is driven backwards. That is, some view needs to be displayed, but in order to display, we need to have the layout information, so layout happens. But in order to do layout, we need to have the glyphs, so glyph generation must occur.

In order to do glyph generation, we have to fix the attributes, so attribute fixing occurs. So the whole process gets pulled from the display end. Now, that's not always what happens. It may happen often, but also if the text system finds some idle time, it will, in some cases, precompute some of these things for performance.

So I've discussed some of the fundamental concepts. Now I want to talk about some of the classes that implement these things and perform these processes. So this is a diagram of the four major text system classes in the order in which they contribute. So NSTextStorage stores the text. NSLayoutManager controls the glyph generation and layout. NSTextContainer models the geometry of the containers. And the NSTextView is the view that actually sits in the display hierarchy and handles user input and display. And we'll be coming back to this diagram again later on.

Why so many different classes? Well, the text system is one of the more complex examples in AppKit of the model view controller paradigm. That is, we have some classes that represent the model, in this case, the underlying text and its attributes and the geometry of it. And we have other classes that handle the view portion, that actually sit in the view hierarchy that do display, do user interaction. And we have controller classes that sit in the middle and intermediate between them and manage things.

So I'm going to talk about each of these in turn. Now, I spoke of the text as being an attributed string. And in Foundation, there are the classes NSAttributedString and NSMutableAttributedString. But the actual storage for the text system is not one of these. It is an AppKit class called NSTextStorage. And NSTextStorage is a subclass of NSMutableAttributedString.

Keep that in mind. Whenever you're dealing with a text storage, you can use all the NSMutableAttributedString methods on it. But it has something extra. And the extra thing that NSTextStorage does is that whenever it changes, it notifies other components of the text system that it has And okay, there are other classes that are model classes that model the attributes of the text, the obvious ones, NSFont, NSColor.

For paragraph-level attributes, we have NSParagraphStyle, which models things like line spacing, justification, margins, and so forth. And also, it may contain multiple tab stops, which--each of which is modeled by the NSText tab. And there's a special class called NSTextAttachment, which models an attached file or an inline image.

And finally, I'm going to consider the text container as being a model class. What an S-text container does is it's pure geometry. It simply models a geometrical region. It might be a page or a column or something more complicated within which text is going to be laid out. Now, instead of speaking of an instance of the class NSTextStorage, for short, I might say a text storage, and so on for the other classes.

Next, we have the controller classes, of which the most important--probably the most important class in the tech system is NSLayoutManager. NSLayoutManager manages the processes of glyph generation and layout. It stores all the layout information. It stores the glyphs themselves. And NSLayoutManager, interestingly enough, is actually the class that does the display, that is, that marshals glyphs and sends them to Quartz to be rendered at the request of the view.

If you want to know anything about the glyphs or anything about the layout, you ask NSLayoutManager. In addition, there is another class which we usually do not deal with directly that is controlled by NSLAM Manager called NSTypeSetter. NSTypeSetter is a class that actually does the layout of the glyphs into the containers.

Finally, we have the view classes, of which the most important is NSTextView. One NSTextView handles the display and user input for the text displayed in a single container, a single NSText container. When you drag that object off the palette in Interface Builder, what you get is an NSTextView.

It's probably a class most of you have dealt with. One thing to mention about NSTextView is that for historical reasons it has a super class, NSText. And some of the NSTextView methods are actually defined there. But currently, the only subclass of NSText is NSTextView. So you can think of them as being the same thing.

As I said, one NSTextView handles the display and input for a single NSTextContainer. So if you have a situation with multiple text containers, say, multiple pages in a document or multiple columns on a page, then there would be one text container for each of these and one NSTextView for each of the containers. And these associated TextViews will know about each other, will work together, and will have some shared state.

For example, the user's selected range in the text. And there are other classes at the view level. The standard AppKit ruler classes are used for text rulers. And there is a special subclass in NSL called NSTextAttachmentCell, which does the drawing for the NSText attachments, that is, for attached files or inline images.

So now, how do these classes work together? We're back at the diagram. This is the most common situation. That is, where you have a single instance of each of the major classes: one NSTextStorage, one NSLayoutManager, one TextContainer, one TextView. This is not the only possibility. For example, a single text, that is a single NS Text Storage, might be presented to the user in multiple ways. And for that, each of these ways can have its own layout manager, representing a different layout of the same text. So a single NS Text Storage may have one, or more than one, NS Layout Manager.

Now, likewise, as I mentioned before, a single NSLayoutManager may be laying out into a single text container, a single page or a single long document. Or there may be more than one NSTextContainer representing, for example, multiple pages. So one NSLayoutManager may have one or more than one NSTextContainer. And these are in an ordered list so that the text flows from the first text container to the next to the next as it is laid out.

But, as I mentioned before, a text container has at most one text view and vice versa. Now, usually the conceptual ownership flows in the direction I'm talking about. That is, the text storage owns the layout, owns the container, owns the view, although there is another simplified option that we'll talk about in a moment. So this is what the diagram would look like if you have multiple text containers on a single layout manager. That is, for example, in this case, multiple pages. And as you can see, the text flows as it's laid out from the first text container into the next.

This, on the other hand, is what the diagram would look like if you have multiple layout managers, that is, multiple presentations, on the same text. So each layout manager would have its own text container or set of text containers, and they each present the same text in possibly different ways.

So now we've discussed some of the basic text system concepts, and we've at least touched on the classes. So now I'm going to talk about how you use the text system. So first, I want to touch briefly on the very simplest uses of the text system, those that don't involve you touching an NS TextView directly.

Now, the very simplest APIs are just categories on--defined in the app kit on NSString and NSAttributedString that simply say, "Draw this string, and then you can use it to create text." So, this is a very simple system. You just want to do some simple drawing. You want to put this text here. No fuss, no muss. Just draw it.

Under the hood, there are all of these text system classes working for you, but you don't have to deal with them directly. The next simplest situation is that that might be used by a control, let us say a button that needs to draw its title, for example. And what it uses in that situation is an NSL. And the NSL knows how to draw itself. The NSL does the drawing. The NSL talks to the text system for you. You don't have to deal with it, although it is there under the hood.

So what happens if a control doesn't need to just display itself, but it also needs to do some input? Say a text field is editing. For that we--what we do is that each window has a single shared text view called the field editor for the window. Only one control is going to be editing in the window at any given time, so the field editor can be shared among controls.

And when a control starts editing, the field editor is attached to it, is put in there in the view hierarchy, and while that control is editing, the field editor takes over the display and does all the input for it. So input in the text system is always handled by a text view.

There is one more usage of the text system that doesn't involve a text view that's somewhat more complicated, and that is that in a custom view of yours, you can use a layout manager with text containers without text views to do measuring of text or to do drawing for you. And I'll mention that briefly again later on.

So next I want to talk about the simplest usages of the text system that do involve you touching an NSTextView directly. And So the simplest and most common case is that in which there is one text storage, one layout manager, one text container, one text view. And that's what you get when you drag that object off the palette in Interface Builder.

And when you create a text view in this way, the text view automatically creates all of the other elements of the text system for you. And in this situation, you use a simplified ownership model where the text view conceptually owns all the other pieces so that, if you like, you don't ever need to talk to any other object.

You don't need to deal with anything but the text view. Now, even in this very simple situation, there's actually a great deal that you can do in the way of customization of the text system. You may think that I'm going to talk here about subclassing in NSTextView, but I'm not, not yet. One rule of thumb in Cocoa is that subclassing of the kit objects should not be your first resort, but rather one of your last.

Before you try subclassing, first thing you should think of is to do everything you can with notification and/or delegation. And in the case of NSTextView, there is actually quite a bit that can be done as the TextView The TextViews delegate is notified of any change that the user makes to the text, and it gets to veto or modify that change.

The TextView's delegate is notified of any change that the user makes to the selection of the text and gets to veto or modify that change. The TextView's delegate is also notified when the user presses some special key, like an arrow key. And again, the delegate gets to veto or modify that action.

So what this means is that the TextView's delegate has almost complete control over the user's interaction with the TextView. I want to emphasize this point because this is the number one question that I get asked about the text system. That is, "I'm working with the TextView and I want to do something special when the user presses, let us say, the return key.

What do I do?" And my answer to this is always, "Well, the first thing you should try is acting as the TextView's delegate." And now I have a very simple demo of that. We can move over to the demo screen. So suppose you're writing a, say, a chat program. And, well, while the user is typing in a message, they can edit it freely, but once they hit return, that message is sent and can't modify it anymore.

The simplest way you can do that is as a TextViews delegate. Now, I've written a very simple demo of that. When I was writing up these demos, I decided I wanted to make them as simple as possible, so I limited myself to 25 lines of code in any individual demo. And I think these demos should be available from ADC as download. I'm just going to show it to you here.

So, for example, I can type along, and then when I hit return, The TextView's delegate is notified. In this case, it makes some changes to the text. It turns it red. In the text that I'm typing, I can edit it. Once I've hit return, though, That text is selectable, but I can't modify it because the TextViews delegate is forbidding that change. All right. Let's go back to the slides.

So, next thing I want to talk about is some more complicated text system usages, where you go beyond the single layout manager, single text container, single text view model. So, the simplest and most common case here

[Transcript missing]

The way this works is that the layout manager has a list, an ordered list, of its text containers.

And it lays the text in these containers. The text flows from one to the next as it's laid out. You can add or remove containers from this list, and the text will automatically be laid out into them. As I said before, you will have one text view. If you want text views, you'll have one text view per container.

If there are many text containers and text views on a single layout manager, they will know about each other and they will share some state, such as the user-selected region. So again, here is a diagram where we have multiple text containers on a single layout manager. The text flows from one to the next. This is what you would use if you had multiple pages or, for example, multiple columns on a page.

Another possibility is that you may wish to have multiple presentations of the same text. For example, if you're writing, let us say, a slide presentation application. You might want to have one presentation of the text in a list of small fixed-sized text containers representing the slides on one side. And on the other side, you might want to have a separate presentation of the same text in a single long text container as a continuous outline.

So, what you would do in that case is you would set up two different layout managers on the same text storage. : Then one layout manager would get a single long text container. The other layout manager would get a series of small, appropriately-sized text containers. And that's all you need to do. The text system will automatically lay out the text in all these and present it in both at the same time. Now, what happens if the user makes a change in one of these presentations of the text? All right.

Here's a sequence of what happens. The user makes a change, say, types in one of them, in one of these text views. The text view then makes that change on the underlying text storage. Now, remember I said that the special thing about NSTextStorage was that when it changes, it makes some notifications. It notifies its layout managers that it has changed.

And these layout managers, when they receive that notification, what they do is they notice, depending on the region that is changed, which of the portions of glyph and layout information that they maintain are now made invalid by that change. And they mark them as invalid. They don't necessarily recalculate them right away.

Then they tell the affected text views that they're going to need display, a set needs display. Now, eventually at some later point, some of those text views may be displayed. When that happens, the text view will need display, so it will ask the layout manager for layout information to determine what needs to be displayed.

So the layout manager has already marked as invalid some portions of its information, so it knows it needs to be displayed. And then it will ask the layout manager to determine what needs to be displayed. So the layout manager knows it needs to be recalculated, so they will be recalculated on demand. The glyph generation and layout will be performed. And then the views will be properly redisplayed.

So in this way, the changes made in one text view in one presentation propagate to all the others. I emphasize this because if you understand how this works, you go a long way toward understanding how the text system works changes propagate down from the views to the model, and they propagate back up through the controllers back to the views again.

And again, here is a diagram for the situation in which you have multiple layout managers, multiple presentations of the same text on the same text storage. They present the same text in possibly different ways. Now, there are also a number of options that you can set as to how your text is going to be shown.

When you drag that object off the palette and interface, though, you may notice that it scrolls in only one direction. That is the--and the text in it is arbitrarily long, but it's not arbitrarily wide. It's fixed width. These are options that are set on your TextView in your text container. And you could set these things independently in the horizontal and vertical directions.

For this, I would like to point you to an example on your CDs, the text sizing example in the app kit examples, which has some very clear and complete examples of many different combinations of this sort of thing. There are also some positioning options. You can set an amount by which the text container is inset within the text view. And when you're laying out the text in the text container, you can set an amount of padding by which text is inset within the text container.

There are also quite a few options that can be set on the Textview itself. And many of these are probably familiar because they're represented as checkboxes in Interface Builder. Not all of them are, though. For example, on the Textview you can control whether the Textview is selectable, whether it's editable, whether it shows plain and rich text, whether attachments can be dragged in, whether rules will be shown, whether the font panel will be used, whether as you type spell checking is allowed, whether it uses a so-called smart cut-and-paste behavior.

You can control the attributes that will be given to designate selected text. It doesn't have to be a gray background. And you can also control whether the Textview acts like a field editor. That means acts like a field editor with respect to tab and return. For a field editor, tab and return. and editing rather than inserting tab and return characters.

There are also some options, not quite as obvious, that can be set on the layout manager, on the text view. By setting options on the layout manager, you can control, for example, whether hyphenation is used. You can control whether the layout manager does that precalculation, the background layout I mentioned at idle time. You can control whether inline images and attachments are scaled to fit the text container. And you can control whether the layout manager would use fonts with screen metrics if they're available.

So at this point, people usually want to know, how do you put the pieces together to get one of these things working? So the usual process would be, first you create this text storage and populate it with your text. Then you create a layout manager and simply add it to the text storage. Text storage can have any number of layout managers. Then you create however many text containers you want, size them appropriately, add them to the Layout Manager.

If you want text views, you create those and set them for the text containers. Set all the options, and you're done. It's that simple. The text system will automatically lay out the text for you. So, at this point, I have a small demo of this. So here is the sort of situation that I was talking about before, where we have on one side of the screen, the text is laid out as a single long text view as an outline. And the other side, we have some smaller fixed-size containers, which might represent slides.

Again, a very simple demo. All I do is create these objects, add them to each other, position them under 20 lines of code. You can download this example from ADC. Now, just to show you what happens when you make changes in one of them. As you can see, they're automatically transferred from one of these presentations to the other. Let's go back to the slides.

So at this point, I would like to talk about what you can do when you deal directly with the text storage, with the model layer of the system. Most people, when they start out working with the text system, start off working with nsTextView. And nsTextView certainly does have some methods that allow you to alter the underlying text. But at some point, you'll probably want to go beyond that. For complete control over the text, you want to deal directly with the underlying model, the text storage.

Now, let me say again, NSTextStorage is a subclass of NSMutableAttributedString, and all of the mutable attributed string methods can be used on it. The special thing about the text storage, though, is that when it changes, it notifies all its layout managers that it changes. There's one corollary to that, and that is that if you're making a lot of small changes, you don't want the text contained to the -- you don't want the layout managers to be notified of each one individually, and have to do work for every single one.

So for efficiency's sake, if you're making a number of changes in a row, what you should do is wrap them first in a call to begin editing, and finally, when you're done, with a call to end editing that allows these notifications to be coalesced into one at the end.

So what can you do with the text storage? One very common thing you'll want to go to is to be able to set attributes. And the attributes that are available that are recognized by the text system are listed for you in the app kits and as distributed string.h header.

: And let me just mention some of them. You can set fonts. You can set colors, foreground and background colors. You can set underlines, subscripting and superscripting. You can move the baseline up or down. You can control the use of ligatures. You can modify kerning. And there are also paragraph-level attributes, things like

[Transcript missing]

As I say, the paragraph level attributes are all part of NSParagraphStyle.

And they're all set by setting NSParagraphStyle. And this includes things like margins, line spacing, justification, the wrapping style, and tab stops. Now one thing that is new for Jaguar is that we now have complete support for all different kinds of tabs, that is left tab stops, right, center, decimal tabs.

There are a couple of special attributes that I want to mention. One of them--okay, when you have a document open in TextEdit and you drag in a file, what you get is usually either an icon, or if the file's an image, you might get inline representation of the image in the text. This is called an attachment. It's represented in the text storage as a special character, the text attachment character, with a special attribute, the text attachment attribute.

And the value of that attribute is a text attachment, an NSTextAttachment. This--what an NSTextAttachment usually does is it points to a file wrapper. And this file wrapper-- I'm not gonna discuss in detail file wrappers here, but the file wrapper models the contents of the file or a link to the file.

How is that going to be displayed by the text system? If you just create one with a file wrapper, then the text system will automatically create some appropriate cell with an appropriate image, typically according to what it thinks is best to represent that, usually either an icon or an image representation, if it's an image file.

But you can change that programmatically. For example, if you have some alternate image you want to use, you can simply set that image as the image for the attachment cell. Or if you have some alternate kind of cell you want to use, you can set that cell for the text attachment. You can even create a custom subclass of an attachment cell, and we'll discuss that in a moment, to do more or less arbitrary drawing inside the text.

Another attribute is the link attribute, which is typically used to represent clickable hyperlinks. And usually the value of that link might be an NSURL. The default behavior when clicking on a section of text with this is to open that link in the user's default browser, usually. But you can override that. Again, as the TextView is delegate, you can respond to that click and do whatever behavior you want.

I mentioned attribute fixing earlier. Attribute fixing is something that is performed by the NS Text Storage lazily on demand whenever something asks for some of its attributes. And it's at this point that we make certain, for example, that by font fixing that the font attribute for each character is a font that can actually render that character.

And we also do something called paragraph fixing and make sure that the paragraph style attribute is actually constant over the length of the entire paragraph, that is, from one hard library character to the next. And another thing, among the things we do is attachment fixing, which makes sure that the attachment attribute always goes with the attachment character.

So one obvious question is, how do I get text into or out of a text storage? The format that the app--that Cocoa usually uses for storing and transferring text is RTF, or an extension RTFD for text that has attachments. This is the format that we'll provide when putting styled text on the pasteboard. Of course, we do provide plain text as well. And there are methods that you can use to easily read or write RTF, RTFD to and from an NS Text storage or any sub-range thereof.

There are also some methods that you can use to read into a text storage from a file. And for these methods, what we can do, if you choose, is have the text system automatically decide what format that file is in and automatically import from that file. Now, the formats we can import from are obviously plain text, RTF and RTFD, plus a few others. We can import from the simple text file format. And we can import from HTML. We do not write HTML out.

And this list can also be extended with the third-party additions called filter services. What a filter service is, is something that one of you might write, install on the system, and it would advertise what format it understands and what format from among the ones we natively understand that it converts to.

As when this is installed on the system, the text system will know about it. And when a file of that type is tempted to be opened, your filter service can automatically be invoked to do that conversion. So any application using the text system could then open files at that time.

At this point, I should probably say a little something about services in general. Filtered services are one small special case of the general mechanism called services, which are means of allowing third-party editions that act on text. Well, they actually act on more than text, but this is a text talk, and so I'll talk about how they apply to text.

In a typical case of a service, what will happen is that you can select some portion of text in any application, invoke the service, that text is placed on the pasteboard, send over to your service-providing application and process, which then acts on it, performs whatever custom modification your service provides, puts it back on the pasteboard, sends it back to the requesting application, or it's pasted back in. That's the standard kind of service. There are also filter services, as I have mentioned. Filter services for text. There are also--are filter services available for images.

And there's one other custom kind of service, and that is a spell checking service. So it is possible, as you know, Cocoa applications can make use of spell checking. But it is possible for anyone to write a third-party spell checker that can be installed on the system and made available to users as an option they can select in the spelling panel.

Of course, Apple does ship a spell checker with the system. I should note that for Jaguar, that our spell checker has been entirely replaced. We now have an entirely new spell checker that is much improved in its English version and that also has support now for a number of other languages as well.

One other way of storing things in the text system is archiving. Archiving is a mechanism, for example, that Interface View Builder uses to store its nibs. I can't discuss archiving in complete generality here, but I do want to say some things about it for those of you who know what it is and what it does. If you were at the Cocoa What's New session, you know that there have been some significant changes to archiving. We now have the new keyed archiving system.

Now, it used to be pre-Jaguar that most of the classes in the text system would not archive themselves. It was just one special case that was used by Interface Builder for TextViews. But now, with the new keyed archiving, all the major classes in the text system can archive. So it is now possible to archive more or less arbitrary configuration, like the one I have on this demo app, of multiple layout managers, text containers, text storages, TextViews, and so forth.

Now, when you archive a text storage, well, when you store a text as RTF, the attributes have to be converted into the form of RTF_understands, and only those attributes that are convertible to RTF will be stored. When you archive a text storage, on the other hand, all the attributes will be stored. But one corollary to this, of course, is that if you create some custom attribute, which you certainly can, it might be a good idea to make sure that the values used for that normal.

So we've discussed dealing with the model layer, the text storage. Now I want to talk about sorts of things you can do by dealing with the controller level of the system, that is, with the layout manager primarily. I said the layout manager controls the processes of lift generation and layout. The Layout Manager is the object that stores the glyphs themselves. It stores all the layout information and performs glyph generation and layout as needed on demand.

And as we saw in our example of the multiple layout managers, that when the text is changed, the layout manager observes that change, the text storage notifies it, and the layout manager invalidates any stored information it might have that is made invalid by that change for later recomputation on demand. It is also possible for you to manually invalidate some of that information if you want to force it to be recalculated.

Now, remember what I said at the beginning, that the mapping between characters and glyphs is not necessarily one to one. So since it's the LayoutManager that controls the glyph generation, the LayoutManager is the one that knows exactly how this mapping works. So if you want to know which character, which range of characters maps to which range of glyphs in the glyph stream, you ask the LayoutManager. LayoutManager will tell you.

LayoutManager stores the glyphs. And if you can ask it what the glyphs are for any particular range, Generally speaking, the glyphs are just numerical indexes into a font. There are a couple of special values that we use. There's a control glyph that's used for non-printed characters like tabs and line breaks and so forth. And there's a null glyph that the layout manager will sometimes use for padding for its own internal purposes. The layout manager also stores certain what are called glyph attributes on the glyphs.

These are completely different from the character attributes we've been talking about along. The glyph attributes are things like the elastic attribute, which appears usually on spaces to show that they can be -- they might not need to be laid out at the end of a line. They can be expanded as needed for justification. There is also an inscription attribute, for example. This would be used on things like an accent character to show that the accent should be laid out above the preceding glyph instead of following it.

When the Layout Manager needs to do layout, it contacts the typesetter, instance of NSTypeSetter, which actually does the layout. So the typesetter contacts the layout manager to find out what the glyphs are. Then it contacts the text container to find out what the geometry, what the geometric region they are to be laid out in. And then it's the typesetter that breaks the glyphs up into lines and positions the lines in the containers, positions the glyphs in the lines.

And the typesetter is also allowed to make insertions or changes in the glyph stream as necessary. For example, if hyphenation is in effect, then the typesetter might need to insert a hyphen glyph into the glyph stream when a hyphenation is performed. And then when the typesetter has done this, it calls back and notifies that layout manager as to exactly where each glyph ended up.

So it tells the layout manager which container a glyph ended up in and what line within that container the glyph ended up in, what position of the line is and the size of the line, and the location of each individual glyph in that line. And the layout manager stores that information. So usually you will not want to contact the typesetter directly. You ask the layout manager for any of that information.

So, for example, if you were writing your chat program and you wanted to put some nice fancy bubbles around your text, you need to know where it was laid out. You ask the layout manager. The layout manager can tell you many things about layout. It can tell you where each line is located, what its size is positioned within a text container. It can tell you which glyphs ended up in a particular text container. It can tell you for any particular glyph what text container it ended up in, what line it ended up in, and where in that line it went.

It can also do a number of different conversions. For example, if you have a particular point and you want to know what glyph lies at that point or closest to that point, the Layout Manager will tell you. If you have some range of glyphs and say these are the selected glyphs and you want to know what rectangle should be drawn to represent the selection, the Layout Manager will tell you that.

And again, it is actually the layout manager that does the drawing at the request of the view. That is, the layout manager marshals the list of glyphs, their positions, and sends them down to courts to be drawn, along with drawing other things like backgrounds and underlines. And You do not have to actually use an NSTextView to use this.

You can do this, for example, in your own custom view class, a couple of caveats. You must have locked focus on some appropriate view to do the drawing. And one other thing to remember when you do this is that the LayoutManager's notion of position of glyphs is almost always relative to the text container, not necessarily coordinates in any particular view. It's coordinates in the text container.

Now, there is an example of this, again, on your CDs. This is the CircleView example in the AppKit examples. And that gives a very straightforward example of how to draw glyphs in a custom view by talking to the lab manager directly. Now, at this point, I have another small demo.

So, suppose you wanted to do something else, something like, something special for a rollover, a rollover effect in your text view. I decided to give a very simple example of that. If you want to know If you know where the mouse is in the text view, then you can ask the layout manager to find out, for example, what glyph it's over, what character that corresponds to or what set of characters, and other things like what line it's in. And so, for example, as I roll over, I've asked that, and then I've highlighted those characters, those glyphs, in some specific colors. Again, a very simple example, under 25 lines, and you should be able to download it from ADC.

On to the final and more dangerous portions of the talk. If you want to go beyond this, you may wish to subclass one of the objects in the text system. So before you subclass one of the objects in the text system, first I'd like you to check to see whether you can do what you want to do without subclassing.

So there are quite a lot of options and settings that you can use. I've mentioned so far, there are many that I haven't mentioned. And you should take a look at some of these. They can do a lot of interesting things for you without subclassing. For example, I mentioned something about selected text attributes in the text view. Usually the selection is displayed as a gray rectangle. That's by changing the background color. But that's actually something you can choose arbitrarily. You could choose an arbitrary set of attributes.

for representing the selected text. Another thing is a mechanism called temporary attributes. And that was actually the mechanism I used on this most recent demo to change the background color. Temporary attributes are character-style attributes, like primarily colors, that can be set at the layout manager level. So they affect only some specific layout manager. They don't change the underlying text storage.

They can be used for things like temporary highlighting, maybe syntax coloring or something of that sort. So you should take a look at many of the options that can be set. You should try using notification and delegation. As I mentioned, it's a very powerful mechanism. For example, the first demo I did, you can intercept a wide variety of user actions this way.

But if you do decide that you need a subclass, if what you want to do can't be done, one of the things I've mentioned so far, then you should try to override the user actions. The second thing is to use the minimal set of methods to do what you want to do. So let me talk about some of the interesting things you might want to subclass and what you can You might want to subclass the model level, NSTextStorage. You could subclass an NSTextStorage, for example, to provide your own storage mechanism for the text.

For example, maybe your underlying model in your app is not an attributed string, but say, some character-- sequence of characters with nested style sheets or something of that sort. You might have a custom text storage subclass that converts from your underlying representation to the representation the app gets once, text storage.

You might subclass NSTextStorage if you want to intervene at the attribute fixing level, if you want to modify what is done in attribute fixing, if you want to add some attribute fixing of your own. Or perhaps you might want to modify it to subclass NSTextStorage so it notifies not just the layout managers but some other objects of your own when it changes.

You can subclass in this text container. I should say that all the objects I'm mentioning here now have fairly well-defined subclass interfaces, and so they should be reasonably easy to subclass. The obvious reason to subclass NSTextContainer is to provide some custom geometry that's more complicated than just a rectangle. And you can get more or less arbitrary geometry by subclassing NSTextContainer.

The way this works is that your text container subclass will be asked by the typesetter. The typesetter will say, "I want to lay out some text in this line. I propose this rectangle here." And you get to modify it and say, "No, no, you really want to use this rectangle here." And if you have holes in your text container, you can say, "And by the way, there's some more space following the hole that you can use, too." Subclass NSTextView Subclass NSTextView is what does the drawing and the user interaction.

You can subclass NSTextView to alter, in more or less arbitrary ways, the way that the view interacts with the user. You might alter selection behavior, you might alter drawing behavior, you might alter click behavior, you might alter auxiliary things like context menus, you might alter the behavior of cut and paste or drag and drop, any number of things.

Going a little further, you might want to subclass possibly NSLayoutManager. Now, remember that NSLayoutManager is a class that actually does the drawing. So, you might want to subclass NSLayoutManager if you want to provide, let's say, some custom drawing behavior at this level, custom background drawing, or custom, maybe you want to respond to some custom attributes that you have set.

You might want to subclass to store additional attributes that you may have defined on that occur on the glyphs rather than on the characters. Or you might subclass to override some of the other behavior that a layout manager provides. As I said, the layout manager is what gets interrogated to find out what glyph lies under a particular point, or it provides the rectangles that represent selections. So you might override NSLayoutManager to override any of that behavior.

You might override NSTextAttachmentCell. As I mentioned, there are many ways that you can alter the drawing that represents a text attachment. You can supply a custom image. You can supply a custom cell. You can use a custom subclass in NSTextAttachmentCell. And with this, you can obtain more or less arbitrary drawing within some region that you get to pick in line in the text. And not only that, but it is also possible with such a subclass to be able to handle user clicks within that region in the text view.

[Transcript missing]

At this point, I have one final demo. This is one I didn't write. So here's a new address book application. Let's see how some of all this comes together in a real application. So first of all, let's notice what sort of things we have here. We have, well, there might be an image here, a picture of the user, if we had a picture. And there's a custom text container here that is cut out with space for this image.

You notice some nice little rollover effects as we move over various items. You've seen how to do that. Let's see if we go to edit it. There are some changes to selection behavior. What else do we have? Awesome. Custom cell for drawing this. Well, there are a number of little tricks in here, and I'll let you play around with it yourselves. You all have a copy of this, and you can see how it works.

So where do you go from here? I've mentioned a number of examples. There are some others. There are a number of text-related examples on your CD. There is also some documentation of this. They -- in the Cocoa documentation section, you can find it on the website, if you have one. There are, of course, a number of books, program topics, and other things Of course, most of the sessions have already occurred. And you can contact Heather Hickman, our technology manager. And we also have a mailing list, Cocoa Dev, and a feedback address for sending feedback to us.