Application Technologies • 58:03
Learn how HITextView can replace custom text controls in your application and easily handle Unicode text, advanced typography, URLs and multimedia content. Hands-on demonstrations will take you step-by-step through code to show how you can maximize HITextView's benefits to your application.
Speakers: Dan Fenwick, Aaron Haney
Unlisted on Apple Developer site
Transcript
This transcript was generated using Whisper, it has known transcription errors. We are working on an improved version.
Welcome to session 111, HITextView Unleashed on Tiger. This is a hands-on session, so if you haven't done so already, go ahead and download the code at the HITextView session WWDC site. My name is Daniel Fenwick. I'm an engineering manager in charge of Atsui, MLTE, text encoding and text encoding converter, and Unicode utilities.
So who are we trying to address this to? We want to help Carbon developers design and create edible, edible scrollable text fields in their applications. And also we want to address MLTE clients who want more ease of use in their applications for their text encoding. And developers also interested in MLTE features that are new in Tiger, a few of those will be raised also.
What we hope you'll learn is how simple it is to instantiate an HITextView in your application. This can be done either programmatically or through Interface Builder. And embedding HITextView into other views is really useful. Some of the benefits of that are that you get compositing, scrolling, resizing, and lastly, or not lastly, enabling UI features such as font and spelling panel support and font substitution. Really quick and easy. And lastly, getting data into and out of an HITextView is also going to be covered. And these are some of the new features in Tiger.
So let's take a look at the framework hierarchy as it stands now. At the lowest level is ATSUI, which I just mentioned, and many of you are already familiar with that. It gives you the ultimate power over your glyphs and placement. Above that is MLTE, which calls ATSUI to do its layout. Higher level, and then higher still is HITextView using MLTE.
So MLTE and above is all Carbon. Below, in Atsui, is application services. And once again, HITextView provides the highest level of abstraction. So objects at lower levels, though, can be accessed for greater control. Though some MLTE APIs are disabled when using HITextView, it's a higher level, you don't get quite the control.
Let's compare HITextView versus MLTE. Some of the advantages of using HITextView are better interface builder integration, The ordering and compositing with HIViews is available, which includes scrolling and resizing, transparency. More automatic event handling, such as menu updating and the font panel I mentioned in an earlier slide. Focus. And that all equates to less code to write. Disadvantages again are some MLTE features are disabled.
So let's do some coding. We're not ready for a demo just yet. Let's go over what we can demo. So getting started with the HITextViews, you need to call HITEXTView create. And that's a single call. MLTE-specific options can be passed in at that time. And let's take a look.
You declare your HIV ref, your bounds, and your TXN frame options. And incidentally, when I mention TXN, that's just the preface for the MLTE calls. So there's no confusion. The HITextView create, then, is a preface for the MLTE calls. Excuse me. Where the first option is the bounds. You can set that however you want.
The second parameter is HITextView specific options. Right at this time, it's not used, so set that to zero. The third parameter are the MLTE-specific options, which we'll get into later, but one in particular is the Do Font Substitution mask. That'll allow your text editor to use font substitution automatically. And this is really useful, highly advised for you to...
[Transcript missing]
So, you can basically just click on the text view icon here in your controls panel in Interface Builder and drag it over and size it the way you want. It's that easy. Adding resize support is just as easy. Let's take a look. You have binding. In this case, I'm giving an example of just binding left, but you'd want to do this for all the sides, depending if you want a full bound HITextView to a resize window. So you declare your layout info. If my clicker works. You tell it what kind you want, in this case, again, is bind left. ToView equals null indicates that you want to bind to the parent view just as default.
And at this time, the offset is unused, so it's a float. Set that to zero. And you set the HIView set layout info and you're in business. You can also do this in Interface Builder using the View Inspector. Go down to Layout and set all the sides of your view. Here's the top view and we're just setting that binding.
So my demo engineer is stuck in traffic, no surprise. So I'm going to have-- oh, he's here. This is Aaron Haney. He's our text engineer, and he's going to demo what I just went over. Aaron, glad to see you. Glad to be here. Can everybody hear me OK? So if you look at the sample code disk image that you can get on the attendee website, inside that there's a folder for this session. It's numbered 111-HITEXTVIEW. Inside that there's a disk image, and you can see the contents.
[Transcript missing]
So what we're going to do is instantiate the HITextView with Interface Builder. However, as Dan mentioned, you can also do it through code. And if you take a look inside the Getting Started folder, there's a file called extras.c that demonstrates how to do it through code.
So in cases where there's more than one way to do something, I've put the extras file in place to show you the other way, the way that I'm not going to do on stage. So on stage, we're going to do this through Interface Builder. When we edit the nib, we'll see that it looks exactly like what you get when you create a blank Carbon application in Xcode. And as Dan mentioned, to create an HITextView in Interface Builder, all you have to do is select the text controls portion of the palette. Hover over the text view right here.
It says just text view, but it's actually an HITextView. So we just click and drag that over. And I'm going to actually resize it to take up the entire window. You can see the Snap 2 guys. They're actually kind of hard to see when they get towards the edge, but I actually am snapping it to the very edge of the window.
All right, now once we get it resized to cover the entire window, it's very hard to see, but if you go to the NIV view right here, And select outline view. Then you can clearly see that we have a window and inside that there's the root view, which is always present. And inside that there's the text view. Now we're just going to set a few options Interface Builder gives you access to MLTE options at creation time. So let's always deal with Unicode text. We'll check that one. We want line wrapping on.
And as Dan emphasized, font substitution is very important, so we want to use that too. And we'd also like this text view to resize along with the window automatically. And that can be done in the layout portion of the inspector. For any HIView, this is valid. So I'm just going to go through on every side and bind to the corresponding side of the parent view. And then we should get automatic resizing. So let's build and run our project. And it's going to ask me for save confirmation. Now that we have it, you notice I can click inside the window, and we get our blinking cursor, and I can type.
If I select something, the items in the edit menu are updated automatically. So I can cut, copy, paste. So let's select everything. We want to get a large amount of text in here so we can see what view wrapping looks like. Let's do a little exponential, sorry. So I'm going to copy that, paste it, select all, copy, paste. Again. So let's get a huge amount of text in here.
And you notice word wrapping works just as we would expect since I turned that on in Interface Builder. Now all of those options can also be controlled at creation time when you create your HITextView. There's a slight problem here. If I select all and copy and paste one more time, one or two more times, I've got more text than will really fit in a reasonably sized window. So despite the fact that we have automatic word wrapping on, we still can't quite see everything when we get a large amount of text. So what we need in addition to this is scrolling. And that's what Dan is going to talk about next. Dan? Thanks, Aaron.
Can we go back to the slides, please? Slides, please. There you go. I need scrolling support. What you need to do here is create a HIScrollView and embed the HITextView within it. So options for controlling that scroll behavior are passed to the HIScrollView. Let's take a look. So, again, HIViewRef, ScrollView, TextView, and some option bits.
The HIScrollViewCreate, for once a nice, reasonable name. And let's take a look at the options. The HIScrollViewOptionsVerticalScroll, that will set up for the vertical scroll bar. And since we don't need the horizontal in this case, we don't or it. And then finally, we add the HITextView, or we embed the HITextView within the HISchoolView. And that's all there is to it.
Adding scrolling support can also be done through the interface builder. You go down to the Layout menu, go down to Embed in, Scroll View. That's it. Aaron, you want to give a show? Okay. All right, so taking a look inside folder number two, if you're following along, the begin project is going to look exactly like the end project from the previous example. And what we're going to do is, like Dan showed, add scrolling support.
Again, this can be done through both Interface Builder and code. I'm going to do it on stage using Interface Builder. If you look at the extras.c file inside the folder, it explains how to do it with code. Also, every folder I forgot to mention earlier contains a README file, which describes all the steps that we go through in each of the demos.
So let's take a look inside our nib. This is just like what we had in the previous example. Looking at Outline View inside the NIV, we can see that we have a text view inside our window. So let's make sure it's selected by double-clicking it in Outline View. And as Dan showed, we can embed it in a Scroll View just by selecting that from the Layout menu. Layout, Embed in, Scroll View.
And when you embed a view inside a scroll view in Interface Builder, the scroll view that it creates is the size of the view you're embedding plus enough extra room for the scroll bar. So you can't see the scroll bars yet because they're actually off the edge of the window. So I'll just resize the window a little bit. And it snaps to the edge. And now you can see the scroll bars.
And all of the options for the scroll view Can be controlled through the inspector. Since we've already got word wrapping on in our text view, we don't need a horizontal scroll bar, so let's just turn that off. And because it goes all the way to the edge of the window and there's a grow box there, let's select allow grow box so the scroll bar doesn't conflict with the grow box.
Lastly, we want to make sure that this resizes along with the window. Now that the text view is embedded in the scroll view, it's going to resize along with the scroll view because that's its current parent. So in order to make everything resize along with the window automatically, we also have to bind the scroll view to the window. So now we go to the layout portion of the inspector, go around and bind it on all four sides. And that should be it. And as you can see, we now have a scroll bar. As before, we can click and edit.
So I'm going to do the exponential trick here to get a huge amount of text very quickly. And now you can see the scroll bar is updating. As we resize, when we resize large enough, it actually kind of goes away. I didn't have auto-hide scroll bars on, so you can still see it, but the scroll slum disappears when we get big enough.
Let's make it really small. You can see that we can scroll all the way to the bottom. As we type new text, the scroll thumb gets smaller. Now we've got a pretty full-featured little text view without having to do a lot of work. However, at the moment, all we can do is type, cut, copy and paste. It's also nice to be able to change the style. That requires font panel support. That's what Dan is going to talk about next. Thanks, Aaron. Slides, please.
Adding font panel support. You would probably want to create a UI element for your end user to access the font panel, but we're not going to cover that on this. You would do a HICommandShowHideFontPanel for that. And then, or Aaron will give a demo later on that. And set the HITEXTView's TXN object, again, that's the MLTE object, to handle font panel events. Let's take a look. First thing we need to do is get the TXN object out of the HITextView. You do that using the HITEXTView getTXN object.
Next, we get the options that are currently in that TXN object so we can OR in our font command processing and our font command updating. That's the two-way communication to the font panel back to the TXN object. Once we order those in to our options, we set the command event support back into the TXN object. And that's all there is to it. Aaron? Okay. Can we have demo machine one, please? Thanks.
So in this example, we're going to show how to add font panel support. There's only one way to do it, so there's no extras file this time. The README goes over the steps, and there's also a file called CodeToAdd, which has commented code explaining exactly where it's to be inserted into the project.
And as always, the end project shows what it looks like after we've done our demo steps. So let's start with our begin project, which in this case is still identical to the end from the previous example. Now what we want to do is, as Dan mentioned, first give the user a way to bring up the font panel.
And the usual way to do something like that is through a menu item. So let's take a look at the menu bar. I'm just going to add an item to the Edit menu. To show the font panel, so let's just drag it over and put an extra separator here. We'll give it a name. Show fonts and it's option semicolon to create an ellipsis character.
Now let's edit this menu item in the inspector and make sure it sends the proper command event. Unfortunately, it's not in this pop-up menu, but it is defined in fontpanel.h inside common panels. You can find that just by searching for show hide font panel. And the readme file explains that the four character code for the command ID to show and hide the font panel is SHFP, for show font panel. And the readme file explains that the four character code for the command ID to show and hide the font panel is SHFP, for show font panel.
Now that we've given the user a way to access the font panel, we also want to make sure that our text view responds to the font panel.
[Transcript missing]
I'm also going to bring up the code to add file. We first want to come up with a way to refer to our text view.
So in the code, I've defined a view ID, which is a four-character code plus a numerical constant, so that we can refer to our text view. And I called it MTXT for My Text View. So let's copy and paste that over to Interface Builder. We use Outline View to select the text view.
Make sure it's selected. And then go to the control portion of the inspector to paste that in. And it was MTXT0. We'll save the nib now. So now we have a way to refer to it. So let's just take this and you can see the comment there tells you to put this at the top of the file. So I'm just going to, oops, going to drag and drop this into main.c.
And now we have a function that we're going to add, which when called will-- Grab the HITextView out of the window based on that ID that I just defined. Then it will get the underlying TXN object, or MLTE object, as it's also called, It'll get the current command event support, so that way we don't stomp on any of the currently existing options. Then we'll add these two constants to it.
This one... Font Command Processing tells MLTE to process commands that come from the font panel. And this one, Font Command Updating, tells MLTE to keep the font panel updated based on its current selection. Together, they provide full font panel support. Dan Fenwick, Aaron Haney Font Command Processing tells MLTE to keep the font panel updated based on its current selection. Together, they provide full font panel support. And this one, Font Command Updating, tells MLTE to keep the font panel updated based on its current selection. Together, they provide full font panel support.
So, down here we've just got a little bit of code. To install it, to call it on the text view. So after the window creation, anytime after we've created the window, we can set these options. So let's just drag and drop that in here. You can see the create window is up here. So as long as we're after that, that's fine. And we also have this. Exit condition defined, so I'll just need to add that label down at the bottom. And that's it. So let's see what happens when we build and run it.
All right, now we have the window with the scroll bar. We can click and type. We also see the menu item that we created. All right, now we have the window with the scroll bar. We can click and type. We also see the menu item that we created.
And just to show you that it isn't just the basics, you know, we can select another font. Let's select Skia. Everything in the font panel is hooked up. We can do drop shadow, we can change the color, we can change the underline. Even the typography panel is hooked up. It's all automatic, it's all done for you. This is the kind of thing that you could always do before. The font panel's been available in Carbon for a while, but it took a lot more work. Now it's much more automatic.
As you can see, we can play with variations, we can play with all the ligature controls, all of the advanced font panel stuff. It all just works for you. Very easy. Isn't that great? This is the kind of thing that's...
[Transcript missing]
It's now become kind of boilerplate in text views to also have spelling support. And that's something we added new in Tiger. And that's what Dan is going to talk about next. Dan? Hey, thanks Aaron.
So adding spelling panel support. It's very similar to adding the font panel support. You need to create UI elements to send the command events. In this case, check spelling, show spelling panel, and the check spelling as you type. And you need to set the HITEXTView's TXN object to handle these events. Let's take a look.
There are the two options for sending and receiving information from your spelling panel. Whoops, let me go back. And the last one there is TXN set command event support. Very similar to the font panel support. And that's all I have to show and Aaron will demonstrate how to install. Okay. Thanks, Dan.
So now, we'll go to folder number four for spelling panel support. And as Dan showed, adding spelling panel support is almost exactly like adding font panel support. First thing we need to do, as before, is give the user a way to access the spelling panel. And we'll do that through menu items. So let's create a new submenu here.
We'll make this look just like the standard menu that you see all throughout Mac OS X. It's going to say "Spelling" and inside that submenu there's going to be three items. Whoops, I'm sorry. One to bring up the spelling panel. One to initiate spell check. And one to toggle automatic spell checking.
and that's exactly how it appears in the standard menus seen throughout Mac OS X. So for each of these menu items, we just need to edit them in the inspector and set the appropriate command ID. So the first one for the spelling panel, Again, it's not defined in this pop-up menu. However, the reading tells you what it is, and you can also find it in the Carbon events header. It's SHSP, for Shell Spelling Panel.
Now we want to make sure this menu item has auto-disabled checked, so that way whenever an HITextView doesn't currently have focus, it's not enabled. Otherwise, the user would have a useless menu item sitting there. And we want to turn off update single item to make sure that Carbon Events always checks it whenever events come in. And the standard menu key for this, the standard shortcut key is command colon.
Now to initiate spell check, the four character code for the command ID is CKSP. You can find that in the README and the Carbon Events header. We also want to do auto-disable and turn off update single item. Make sure it always gets updated. The shortcut key is command semicolon.
Lastly, for text spelling as you type, first of all, we want to check that by default because it is on by default once you add spelling panel support. Again, we want to turn off update single item and turn on auto-disable. And there isn't a standard... Shortcut key for this one, so we'll leave that off.
But we do want to make sure we have the correct command ID for this. And it is, I'm going to have to refer to the readme, I can't remember. I think it's ASPC. Yes, it is. It's ASPC for auto spell check. You can always refer to the Carbon events header to find the correct command ID. So now that we've done that, the only thing we need to do is tell the HITextView's underlying MLTE object to respond to spelling event support.
And that's easy enough to do. We edit main.c. Scroll down to the point where we added font panel support in the last example. And we're just going to add a couple more lines. You can find them in the code to add file. There's just two extra lines. Add spelling panel options. So let's just drag those over.
That's it. This looks almost identical to adding font panel support. The first constant tells MLTE to process events from the spelling panel. Second constant tells MLTE to keep the spelling panel and all of its associated menu items updated based on its current state. Everything else remains exactly the same. So let's build and run it.
Let me make this a little bigger so that you can see it. Now as you can see, The HITextView currently has focus, so the spelling items are all on. If I were to quit and restart this, in fact I'm going to do that real quick. Let's quit and restart it.
Now right now there's no blinking cursor. The HITextView doesn't have focus. So if you look at the spelling menu items, they're actually disabled. As soon as I click in the HITextView, it has focus and the spelling menu items are automatically enabled. So let's just type a little bit. Make it a little bigger so that you can all see it.
Make a deliberate mistake. And you can see it's automatically underlined for me because I have "Check Spelling As You Type" on. So let's turn that off. You see it go away. And I can also say check spelling. It jumps to the first misspelled word and I can also say bring up the spelling panel. Now because I have that punctuation in there, it confused the spell check. So let's... Let's get a better example. Let me just pull that out. And we'll check spelling again. There we go.
And I can make corrections, and when I click correct, MLT will automatically update the text based on events from the spelling panel. So now everything all just works, and it's all very automatic. This is all new in Tiger. We encourage you to use it. Now Dan is going to talk about something even more fancy, transparency. Hey, thanks Aaron. I don't know about you, but I wish that was around two years ago. I could have really used it.
Quite useful. So adding transparency. To add transparency to an HITextView, use the function HITEXTVIEW, set background color, with some non-opaque color. Let's take a look. So the first thing here is I grabbed the CG color ref from the HITextView. It's just an easy way to create a CG color ref with all the settings that are currently in the HITextView.
But you could also just create one from scratch, set your color space, etc. So here I modify that color with an alpha that I've set to 0.5 in this case. And I release that previous color since we don't need it anymore. Then, using HITextView's set background color, we simply set it right into the-- All right. Thanks, Dan.
So starting with the begin project in folder number five, you can see it's almost identical to the end project from the previous one. However, there's two new files here. We know transparency.c.h. What that does is encapsulate a little bit of code that makes the content view of the window completely transparent.
Because a transparent HITextView still won't show anything behind it unless there is nothing in the way between it and other applications or other windows that are behind it. You can see an example of transparency in MLTE Showcase if you have the Tiger development CD installed. Go to /developer/examples/carbon/mlte-showcase. There's an example where the text view is partially transparent and behind it there is a CG image view.
In this case, we're going to do something a little different. We're just going to make the window itself transparent so that way you can see through to the desktop or whatever windows are behind it. And that's what window transparency does. Inside that file there's just enough event handling code to tell the toolbox to make the content view completely transparent. Otherwise, this project is completely unchanged from the previous one. So to do this, let's edit main.c.
You can see we have one extra call, make window transparent, and that calls into windowtransparency.c. Oops. Other than that, everything is the same as before. So let's take a look at code2add.c. That contains code which looks almost like what Dan just showed on his slides. It's just encapsulated into a function. What this does is for a specified HITextView, it'll set its alpha by getting the previous background color and changing it. To whatever you ask. So let's scroll up just a little bit. and drag and drop that function over into main.c.
The function doesn't do much good unless we call it. So we'll scroll down a little bit and we've got an extra-- Couple of lines of code, just to call it. And in this case, because we want to make it really apparent that the window is really transparent, we're going to use an alpha value of 0.25.
You can use whatever you want. Now when you're setting the background color, you notice we're saying HITextView copy background color in order to get a CGColorRef to start with. You don't have to do that. Actually what you can do is create a CGColorRef from scratch. You can get it from any kind of source.
This is just a really quick way for us to do it without altering anything else because we just want to change the alpha. And when you set the background color in the HITextView, it will retain the color ref for you. So then you don't have to keep it around anymore. You can do CGColorRelease.
So that should be it. Let's build and run this. I'm also going to hide Xcode so that it's really apparent. Now you can see here this partially transparent window. Its alpha value is very small. It's only 0.25. And I can still type. I can even select. You can see the selection shows up like that. You can bring up the font panel and make it bigger. Whoops. I apologize, I keep clicking a little too easily.
Now when that window is in the background, you'll notice that... Let's put it up here. Let's put it over something white. Even the highlight color has an alpha when it's in the background. So you can see it blending in there. If there was a...let's actually move it over here.
Now you can see the icon through the highlight color. So now everything is transparent. You get proper compositing. If you add any type of HI TextView or any other kind of content behind the TextView, it will all get composited correctly. You can also put stuff on top of it with alpha values and that will all get composited correctly. So these are the benefits of wrapping up all the Carbon text editing code inside an HIView object.
So now we've done some pretty fancy things, but this text view isn't really much good unless we can easily get data into and out of it. So far I've just had to type and copy and paste. It'd be really nice to be able to load and save files directly into this object. And that's what Dan is going to talk about next. Hey, thanks Aaron.
So responding to file menu. These are new for Tiger. They're for reading and writing. TXN read from CFURL and TXN write range to CFURL.
[Transcript missing]
You can set this up to auto-detect what type of file you're going to be reading from and that's what I'm showing here. Let's go through the parameters.
First thing to do is grab the TXN object from your HITextView. And these second and third parameters refer to the data within the TXN object that you wish to paste that information into. In this case, it's the entire TXN object. The third here, data options, refers to what I was just talking about, auto-detection of the file type.
And the fourth is the file URL. And finally, this is set to null to basically ignore, but that's if you wanted to grab the metadata from that file and have it accessible that way. Now, writing to a CFURL, it's similar. You set up a CFDictionary to supply the information about the file type.
Take a look. First thing again is to extract the TXN object from the HITextView. Again, the entire TXN object is going to be written. And the data options, which is the CFDictionary, and we'll discuss that after the slide, is set there. Null being the doc attributes. Again, in this case, it's set to null, meaning I'm not writing any specific metadata to this file and the file URL.
Now the data options, let's take a look at those. Dictionary, and it contains information about the document type as I mentioned. And a CFDictionary is composed of values and keys. And in this case, you have a choice of two keys. The first being the data option document type key.
And the values that are available are RTF, plain text, MLTE Document Type and QuickTime Document Type. That's only for loading, though. Now, the second key available is the Data Options Character Encoding key. And that's mainly for plain text if you didn't wish to output to UniCode encoding. So you would just use that.
and all these are available in the MacText... MacTextEditor.h Ah, MacTextEditor.h. Now, creating the DataOptionsCF dictionary supplies information about - Let's see, this is just going over, I'm sorry, this is just going over how to create the CFDictionary, which many of you have already done. In this case, it's setting one key value pair, the data options document key type.
Sending the number of pairs to one. And those last two parameters were CFDictionary callbacks for that data. Now, finally, let's go over the document attributes. They provide access to documents for the Rich Text Format and MLTE Format documents. As an example, TxEdit has a show properties in it with all the document attributes available. Author, company, copyright, etc.
We're not going to cover setting up the UI for this, but I just wanted to show it to you. This is easy to set up in terms of accessing your metadata. And of course, Spotlight uses the same metadata. The keys are predefined in MacTextEditor.h And all the values are CF types. Most are CFStringRefs. Here's a list of them.
And Aaron will give a demo on how to set up this. Okay. There you go. All right. Thanks, Dan. So what we're going to do is add enough code to make our little app respond to most of the stuff in the file menu. New, close, open, save, save as. If you look at the begin project in folder number six file menu, you can see that it looks a little different.
This is the one project in the demo today that has a little bit of a jump from the end of the previous demo. But let me just quickly go over. Let's close all the files from the previous example. example. That's what I get for hiding it instead of closing it.
You can take a look and see that we still have window transparency.c. That's unchanged. We still have main. We still have our nib, which is also unchanged. We have a few new files, nav.c and nav.h. All that does is encapsulate just enough code to do open and save dialogues using nav services. That's probably very familiar to everyone, so I'm not going to go over the contents of those files.
We've also got two new files called documentwindow.c and documentwindow.h. Main was getting a little big because we kept adding more and more stuff directly inside it, so all I've done is taken most of what was in there and pushed it off into this extra file, documentwindow.c. You'll notice, if we open it up, We still have a lot of the functions from the previous examples that are totally unchanged. Here's the text view set alpha.
Here's TextView set options. This is all exactly like before. This is where we set the font and spelling panel support. We've also added a tiny little accessor function which finds by ID the text view in any of our windows, which as we set it up in Interface Builder, it was MTXT.
I've also added a couple of tiny little helper functions here at the bottom to set and get a CFURL for the proxy in the window. So that way, because we're going to be opening multiple windows now, we want to be able to keep track of what document each window refers to.
So just with a little bit of code here, we can make the windows get the standard proxy icon and title that you see throughout Mac OS X. And at the very top, I've encapsulated all the code from main.c before, which would create one of the windows and set up all the text view options. Most of this is just copy and pasted straight over from main.c from before.
We're still calling make window transparent. We're still calling set text view options and text view set alpha. And we just set the window title to Untitled to start with whenever we create a new one. Now if you take a look at main.c, It's actually much more empty now. We just have our main entry point. It's really short. We just set up the menu bar.
and we call Create New Document Window, which is that encapsulated code I just showed you a second ago. We're also installing a command event handler, an application-wide command event handler, so that we can respond to stuff in the file menu. This is probably very familiar. Here's the event handler that I've created.
If you scroll down, you see a switch statement, which is very familiar. And we're just responding to the standard file menu items-- Command-New, Command-Open, Save, and Save As. And we've got these comments saying insert code to actually open the file here. You know, we've done everything creating the new window except actually loading the data into the file. And that's what we're going to add in the demo. So opening up code to add, you can see it's very short. Like Dan said, TXN read from CFURL operates on an MLTE object, a TXN object, as it's also called.
And so we're doing that and we're getting it from the text view in our window. Sorry, my selection is... I'm a little bit skillful with my mouse here. The next two parameters are offsets, which refer to, these always refer to what's in memory. Whenever you see these, it's referring to what's currently in the TXN object. So when you're reading in a file, it's like, okay, where do you want it to go in the TextView object? By passing in these predefined start and end offsets, we want it to replace the entire contents of the TXN object.
This parameter here is the data options dictionary, which when you're opening, you probably want to be as flexible as possible and just open everything that MLTE supports. So you can pass null here and MLTE will auto-detect it for you. One of the cases where you might want to specify a dictionary is if you want to allow the user to specify a particular text encoding if it's not auto-detecting it correctly. But most of the time you just want to pass null.
This is the file URL that we're opening. We're going to assume that the code around it that's already pre-existing in the project is going to set that up for us. And lastly is the metadata document attributes dictionary, which in this case, we're not going to pay attention to it, but it's pretty straightforward.
If you just take a look in the MacTextEditor.h, you'll see all the keys defined for you. Most of the types are very simple CF types, like string refs. It's actually very easy to use. So to make our application open correctly, let's just select a single line of code.
[Transcript missing]
You can get it done with just a single call. However, you usually want to specify a file type when you're saving. It's not like opening where you want to support everything. When you're saving, you're saving to a particular type.
If you pass no for the data options dictionary, you'll get the ML2E document type. And that's not really the standard format on Mac OS X. It's kind of ML2E is the boilerplate standard format for saving a file type. Wait, did I say MLT or rich text? Rich text is the standard format for saving style text. So what we're doing here in these three lines of code-- let me just make this window a little bigger so we don't get line wrapping.
We're going to create a dictionary like Dan showed on the slides. This is the default allocator. We have a pair of keys and values, one pair. We're going to specify a document type and we're going to specify the RTF document type so that way you can save to the rich text format which MSE supports.
We only have one pair of keys and values and these last two parameters are just for callbacks in case you have something other than a CF type, you need your own allocators and deallocators and most of the time that's unused. In this case, we definitely don't need it since we're just using these predefined keys for you.
Now we write to the CFURL, and this is going to go into main.c so that we're going to assume the CFURL is already set up for us. We've gotten it from the file save dialog. This operates on a TXN object. We get that from the window, and then we get the TXN object from the-- first we get the text view from the window, then we get the underlying TXN object from it.
We're going to save the entire document. Again, these offsets always refer to what's in memory. Since we're writing to a file, it's how much of what's currently in memory do we want to actually go out to disk. In this case, we want all of it, so we'll just pass in these predefined start and end offsets.
Next, we pass in our data options dictionary, which we created one line up. That tells MLTE to save in the rich text format, because that's what we specified. Here's where, if we were interested in saving metadata, we would pass it in right here. We encourage you to do that, because that way you'll get spotlight in this indexing.
But for the purposes of brevity right now, we're going to leave it out up here on stage. and lastly there's the file URL. Once we're done with the data options dictionary, we can go ahead and release it. So select this code and drop it where we put the placeholder.
[Transcript missing]
Now you notice I didn't have to set up anything in the menu because when you create a new Carbon project in Xcode, you get standard file menu with all the proper command IDs already. So, now you can see it looks just like the previous example with the alpha, we've still got the font panel and spelling menu items, but now we have a proxy icon and a window title. We can open multiple windows because I hooked up the new command ID to create one of these windows.
So let's take a look at Open. Let me drag, we need a rich text file to work with, so I'm just going to use the README that comes along with this project. Let's copy that to the desktop and get that window out of the way. So we'll do file, open, this is just the standard Nav Services. I'm going to select that README file, click open, and you can see there it is.
And it looks just like it does in TextEdit. Now I'm also gonna be able to type in some stuff. We'll play with it in FontPanel. Let's make it big. Let's make it bold. I selected one of the words. and make that a different font. Let's pick something that's really gonna stand out like Times. We'll make it a different size. OK. So this way we'll know that styles are really being preserved. So we'll do save as.
Save it to the desktop. Now let's turn off hide extensions so you can see that we're going to save it as an RTF. Let's open it in TextEdit and verify that it really does look exactly like it did in our text view. And because of transparency, we can even line it up directly on top of it and see that it really is the same.
So now you can see that we have the ability to open and save the standard RTF format on Mac OS X very easily. You can exchange files with other applications like TextEdit. This gives you a lot of flexibility to get data into and out of your HITextViews. Now if you want a little bit more in-depth example, I encourage you to take a look at MLTE Showcase. It's in /developer/examples/carbon. That shows how to use the type pop-up in the file save dialog so that you can choose different formats.
You can choose the MLTE format, you can choose plain text, which also uses the extra keys in the data options dictionary to select an encoding. Now any valid CFString encoding is available for use there. So it just demonstrates two. It shows you how to save as UniCode or Mac Roman, but you can choose any of the CFString encodings. They're all available.
And that's it. I'm going to turn it back over to Dan. Hey, thanks Aaron. So, in summary, At least I think HITextView rocks and a lot of other people expressed gratitude of getting these APIs available to you. It really makes quick work of setting up a text editor in your application to free you up to really make your application shine. And it's very easy to create and embed.
and add font and spelling panel support. Read and write files was just added in Tiger and For more information, let's take a look. Here you got the Carbon HI Toolbox Feedback Forum tomorrow at 10:30. Really come to that and express your desires for any new features, including the HITextView. Text, fonts, international technologies feedback forum. That's on Friday at 9:00 a.m. And take your application global, which is immediately following that on session 141.
Documentation sample code, of course, is at the WWDC 2005 site. Click on the HITextView session and you'll get all the sample code that Aaron just went over, plus all the documentation for MLTE also. Who to contact? Xavier Lagros of the Worldwide Developer Relations. You can forward any emails to him and they'll get to the right person.