ActionScript.org Flash, Flex and ActionScript Resources - http://www.actionscript.org/resources
Scrolling a text box II
http://www.actionscript.org/resources/articles/110/1/Scrolling-a-text-box-II/Page1.html
Patrick Mineault
Freelancer behind 5 1/2 math and physics enthusiast Patrick has a knack for making seemingly simple things overly complicated. Perfect for a tutorial writer. 
By Patrick Mineault
Published on September 9, 2005
 
Tutorial details:
Written By: Patrick Mineault
Author e-mail: [email:info@5andahalf.com]
Author website: www.5andahalf.com
Time: 45 minutes
Difficulty: Intermediate
Requirements: Flash 5
Topics covered: text boxes, onClipEvents, scroll and maxscroll
Assumed knowledge: variables

Part 1: Getting Started
Tutorial details:
Written By: Patrick Mineault
Author e-mail: [email:info@5andahalf.com]
Author website: www.5andahalf.com
Time: 45 minutes
Difficulty: Intermediate
Requirements: Flash 5
Topics covered: text boxes, onClipEvents, scroll and maxscroll
Assumed knowledge: variables
Download FLA

Actionscript for Flash 5 dummies: Scrolling a text box II

Welcome to the second installment in the Actionscript for Flash 5 dummies series, scrolling a text box II. You'll need to read (and hopefully understand) the first tutorial before going on with this one; it's linked in the Related Articles at the bottom of this page.

I'm glad to say I've gotten some very positive feedback from people, so I would like to announce that the Actionscript for Flash 5 dummies series is here to stay; if I'm not too busy, I'll try and write a tutorial every two or three weeks. You can send a blank e-mail to [email:as_for_flash5_dummies-subscribe@yahoogroups.com] with "subscribe" in the subject line if you wish to be reminded of any new tutorials.

Today's tutorial will build on what we learned last time on scrolling a text box. Mainly, we'll modify the script in three points: loading the text from an external text file, getting rid of the hand cursor, and adding a scrollbar. These three points were suggested to me by readers of the first tutorial. Unfortunately, they are not as easy to create as a simple scroller; I'll try my best, however, to explain them in an easy to understand way.

The Movie

Without further ado, here's the movie we're going to make:

As you can see, there's a lot of functionality added, as well as easier management because of the external text file. Don't worry though, whilst it is true that a lot of code has been added, it should be pretty easy to understand, provided you have a sufficient amount of coffee handy.

Get your old .fla file ready from the last tutorial, as we'll start adding the actionscript.

Step 1: Loading an external text file

Hard-coding your text may be easy, but it sure makes updating a pain in the buttocks. Therefore, we'll be using an external text file which we'll load into Flash at run-time. Let's get going.

Using the technique described last tutorial ( ...list variables, remember?), copy your text into an empty Notepad, or similar plain text editor. Your entire text should be on one line, unless you have word wrap turned on. Keep this instance of Notepad open, you'll need it later.

You'll need to make some adjustments to the text in order to load it into Flash. You see, when you hard-code text into Flash, the program uses certain encoding entities for characters, so that it won't interfere with scripting. You need to un-encode these entities before putting your text inside of a text file. These entities are , " and ', which need to be changed to , ", and ' respectively. This will turn your text into the so-called "literal" representation of your text.

Additionally, you'll need to encode your literal text using URL-encoding. URL-encoding consists of replacing "at-risk" characters with their hexadecimal ASCII codes preceded by the percent (%) sign. "At-risk" characters consist of some symbols, like &, %, =, which have special meaning in the context of URL-encoding, as well as characters in the top half of the ASCII table, like ÀÉÖÇ, who tend to get butchered on systems with non-standard character sets, in particular MacOS. You can get a list of characters and their URL-encoded equivalents at Macromedia.

If the preceding sounded like chinese, don't worry. Being a nineteen year old college dropout with no job, girlfriend or social life, I've used my spare time to make a little Windows application that will take care of the gory details of reformatting text into a usable form. You will find, in the attached zip file, a file called textformatter.exe. You can extract it on the desktop. Double-click on it from there. You should see a blue screen of death followed by a prompt saying: "Your computer will now explode in 5 seconds. Mouhahaha". Just kidding. Seriously, you should see this:

Select the text you copied into Notepad, and then in the Text formatter app, press "Paste from Clipboard" to paste the text into the textbox. You can then press on the "URL-encoded text" tab to translate the text into a form usable for inclusion in a text file. Then press "Copy to clipboard", and back in Notepad, paste it.

What you say? The app doesn't work? You're on a Mac? You're afraid the app will scan your hard drive for porn and then send everything it finds to everyone in your Outlook address book, along with a message that says "<person> sucks!"? Well, don't worry, I've thought about you too. You'll find a Flash version of the formatter, textformatter.swf, in the zip file as well. Be aware though, because it uses Flash's super slow string functions, it takes a while to refomat the text, and on large text files it tends to crash.

All right, now that you have your reformatted text in Notepad, add "daTextBox=" (without the quotes) at the beginning of your text. Save this file as "text.txt" in the same directory where you will add your movie later.

Your text should now look like this:

 

<plug> Before you ask, no, that is not Notepad, but rather an excellent Notepad replacement by the name of Metapad. It's only 70k, and its block-indenting options are perfect for coding. Best of all, it's free. You can get it at: http://welcome.to/metapad/ </plug>

Now that your text is ready, you'll need to update containerMC's actionscript (old code is grayed out):

[as]onClipEvent (load) {
    this.loadVariables("text.txt");
    scrolling = 0;
    frameCounter = 1;
    speedFactor = 3;
    refreshRate = 12;
    refreshCounter = 0;
    refreshLastMaxScroll = 0;
    loaded = false;
}
onClipEvent (enterFrame) {
    if (loaded) {
        if (refreshCounter%refreshRate == 0 && daTextBox.maxscroll != refreshLastMaxScroll) {
            //Scrollbar should be refreshed here
            refreshLastMaxScroll = daTextBox.maxscroll;
            refreshCounter = 0;
        }
        refreshCounter++;
    }
    if (frameCounter%speedFactor == 0) {
        if (scrolling == "up" && daTextBox.scroll>1) {
            daTextBox.scroll--;
        } else if (scrolling == "down" && daTextBox.scroll<daTextBox.maxscroll) {
            daTextBox.scroll++;
        }
        frameCounter = 0;
    }
    frameCounter++;
}
onClipEvent (data) {
    loaded = true;
}[/as]

Not much anything new, is there? Yes, that is a relief.

The first thing that we added is the loadVariables statement. This loads the variables from the text.txt file. Now, when Flash opens the text file, it sees daTextBox=blablabla, so it sets the internal variable daTextBox to «blablabla». Note that we use the "this" operator, which refers to the current clip, to show Flash that we want the variables loaded into containerMC, not in the main timeline or in some other clip.

This single line asks Flash to load the text file into the movie. Now, remember that we will tie this in later with a scrollbar, and the scrollbar will vary in height depending on how long the text is. So we would like it, later on, that the scrollbar be updated to reflect the length of the text, first when the text is loaded, and then every half-second or so after that.

This way, if we reload other text into the textbox, then the script will catch the event half a second later and update the scrollbar accordingly. Neat, huh? Now, of course, since we don't to unnecessarily put too much pressure on the CPU, we'll only update the scrollbar if the length of the text has changed since last time we checked.

So let's look at how we accomplish this. First, in the load clip event, we define some variables that we'll use later on in the script. You'll need to change the refreshRate so that it will be half of your movie's frame rate. My movie is set to 24 fps, so I set refreshRate to 12.

We set loaded to false, since there's no use in updating the scrollbar if the text isn't loaded yet. Now, in order to find out when the text is loaded, we introduce a new clip event, the data clip event. This event will be fired automatically when the text is loaded. Hence, we set loaded to true when the event is fired.

Now, for the hard part. In our enterFrame clip event, which, as you remember, is fired on every frame, we first check to see if the text file is loaded. If it is, then we check if:

a) It is time to refresh the scrollbar
b) The scrollbar needs to be refreshed

The way we accomplish point A is by checking if our frame counter can be divided by our refresh rate. We use the same principle we did when we wanted to slow down the scrolling of our text box in the last tutorial.

For point B, we check if the length of our text is different then the last time we checked by looking at daTextBox's maxscroll property.

If so, then the scrollbar would need to be refreshed, and we'll introduce this in the last part of this tutorial. For now, we just reset our refresh counter and the variable that holds the previous length of the text. We finish by incrementing our refresh counter.

This will take care of updating the scrollbar every half second. You might be wondering, however, what will happen when the text is first loaded. Well, we initialized our variables in the load clip event in such a way that the first time our text is loaded, the if will be true, and the updating of the scrollbar will be done immediately. Sneaky, eh?

That wasn't too hard now, was it? It's time for some hardcore ActionScript.


Part 2: Getting rid of the hand cursor

Part 2: Getting rid of the hand cursor

As you probably have figured out by now, when you make a button in Flash, and you put your mouse over it, the cursor changes into a hand. This can be useful in certain circumstances, as the user can easily identify a clickable area.

However, in our case, the hand is just plain annoying. For one thing, users already know a scroller can be clicked, so there's no need to put visual emphasis on that point; in fact, it's just plain distracting. Secondly, the hand cursor is, in my opinion, a bit less precise. Finally, we want to emulate an everyday OS scroller here, and OS scrollers don't show the hand cursor.

So we need to get rid of the hand cursor. Unfortunately, there's no hidden setting in Flash that'll allow us to disable the hand cursor on a button. So we need to, as the PR people say, think outside the box. If there's no button, there's no hand cursor, right?

So we'll use a movie clip instead of a button for our up and down arrows. Go into containerMC, and delete the up and down buttons from the movie clip, as well as from the library. Don't be afraid, trust me on this one.

Now create a new movie clip and name it "upMC". Your movie clip should have two frames: the first one is the button in its normal (up) state, the second frame, the button in its hit (down) state. You can add your own graphics for the up and down states. Click on the first frame, go into the frame actions panel, and add a stop() action so that the movie clip doesn't constantly cycle between up and down.

For the graphics, I simply took a screenshot of a scroller (press the PrintScrn button on your keyboard, it's on the right of the F12 key), and pasted it (ctrl+V) into Fireworks. I then isolated the buttons and made separate images of them, and then imported them into Flash. Of course, as I mentionned earlier, you may use your own graphics if you want.

You can follow these steps again in order to create another movie clip named "downMC", which, you guessed it, will be the down arrow.

Now, go into containerMC, and place an instance of both upMC and downMC in it. Name your clips "up" and "down" in the instance properties. Your movieclip should look something like this:

It's now time to update containerMC's actionscript (once again, old stuff is greyed out):

[as]onClipEvent (load) {
    this.loadVariables("text.txt");
    scrolling = 0;
    frameCounter = 1;
    speedFactor = 3;
    refreshRate = 12;
    refreshCounter = 0;
    refreshlastMaxscroll = 0;
    loaded = false;
}
onClipEvent (enterFrame) {
    if (loaded) {
        if (refreshCounter%refreshRate == 0 && daTextBox.maxscroll != refreshLastMaxScroll) {
            refreshLastMaxScroll = daTextBox.maxscroll;
            refreshCounter = 0;
        }
        refreshCounter++;
    }
    if (frameCounter%speedFactor == 0) {
        if (scrolling == "up" && daTextBox.scroll>1) {
            daTextBox.scroll--;
        } else if (scrolling == "down" && daTextBox.scroll<daTextBox.maxscroll) {
            daTextBox.scroll++;
        }
        frameCounter = 0;
    }
    frameCounter++;
}
onClipEvent (mouseDown) {
    if (up.hitTest(_root._xmouse, _root._ymouse)) {
        scrolling = "up";
        frameCounter = speedFactor;
        up.gotoAndStop(2);
    }
    if (down.hitTest(_root._xmouse, _root._ymouse)) {
        scrolling = "down";
        frameCounter = speedFactor;
        down.gotoAndStop(2);
    }
    updateAfterEvent();
}
onClipEvent (mouseUp) {
    scrolling = 0;
    up.gotoAndStop(1);
    down.gotoAndStop(1);
    updateAfterEvent();
}
onClipEvent (data) {
    loaded = true;
}[/as]

Too... much... Actionscript... Yes, I know. Don't worry, it's not as complicated as it seems.

The changes lie in the addition of two new clip events, mouseDown and mouseUp. These events are fired respectively when the the mouse is clicked and depressed.

Now I know what you're thinking: isn't onClipEvent(mouseDown) the same as on(press)? Well, no. For one thing, onClipEvent(mouseDown) only works in clips, whilst on(press) works in buttons. Secondly, the mouseDown clipEvent is an impersonal event, while on(press) is a personal event.

What this means is that if you click outside of a button, its on(press) action won't be fired, while with onClipEvent(mouseDown), even if you click a 1000 pixels off the clip, the event will still be fired.

This gives onClipEvent(mouseDown) a great advantage: with a single script, you can control the click actions of several clips. The same goes for onClipEvent(mouseUp).

Getting back to the code, you'll see the second new line is:

[as]if(up.hitTest(_root._xmouse,_root._ymouse)){[/as]

The hitTest function checks to see if certain coordinates touch a caller clip, and returns true or false. In our case, the caller clip is the "up" movie clip, and the checked coordinate is actually the mouse position in relation to the main timeline, (_root._xmouse, _root._ymouse). So the line can literally be read as: «If the mouse coordinates touch the "up" movie clip, do the following». Essentially, the combination of mouseDown and hitTest() give us the same functionnality as on(press).

You'll recognize the two following lines from the last tutorial; they are literally copied from the ex-button's actions, and unsurprisingly, they serve the exact same purpose as they did before. That is, the scrolling variable is set to up so that the onClipEvent(enterFrame) can know that it must scroll up, and the frameCounter is set to speedFactor so that we can have instant feedback (this being related to the use of % to skip a few frames in the scrolling, remember?). The third line tells our up movie clip to go to its second frame, so that it can show its down state.

The second "if" is basically the same as the first, only for the down button. The mouseDown clip event closes with the updateAfterEvent() function. Normally, the screen is refreshed after every frame; using the updateAfterEvent() function, the screen is refreshed instantly after the mouse is clicked. What this gives us is instant gratification. To see what I mean, temporarily change your movie's framerate to 2 fps, and test the movie with and without the updateAfterEvent() line. Makes a big difference, doesn't it?

Next, we have the onClipEvent(mouseUp) action, which is fired every time the mouse is depressed. What we do here is that we first reset the scrolling variable, then we place the two buttons back in their up state. Once again, we use the updateAfterEvent() action to instantly refresh the screen.

As you can see, we basically took our previous button scripts and concentrated them in a single area, the containerMC actions. Since the clips are not buttons, the hand cursor does not appear when you mouse over them.

Now before you send me an e-mail stating that it's pretty stupid to spend a half hour doing something so insignificant, please understand that using this technique yields several other advantages. Since the script is all in one place, this makes updating it extremely easy. Also, in some circumstances, using the above technique can save you tons of code.

Say for instance that you have a hundred buttons on the stage, and you want it so that when user clicks the buttons, a caption appears with the number of the button. That would be 6 lines of code per button, for a grand total of 600 lines of code! With decentralized mouseUp and mouseDown actions, you could realistically reduce that number to 15.

On with the third and final part of our tutorial, adding the scrollbar.


Part 3: Adding the Scrollbar

Part 3: Adding the scrollbar

The last addition to our script, and certainly the most noteworthy is the scrollbar. With it, we can properly emulate an everyday operating system scroller. Unsurprisingly, it is also the toughest part yet, so buckle your seatbelts, it's going to be one hell of a ride.

A scrollbar requires several elements in order to work. First, it must be draggable within certain limits. Its position will dictate the scroll of our text box.

It also must scale depending on the length of the text; this will give the viewer an idea of just how long the text is. For example, if the text is 2 times longer than the view area, then the scrollbar should be half its maximum height. People instinctively know that a tiny scrollbar means lots and lots of text.

Finally, it must move when the user clicks the up and down buttons. Let's see how each of these elements can be accomplished in Flash.

In order to drag something, we use the startDrag() action. This enables us to drag a clip around with the mouse within certain bounds that can be specified. We can then stop the dragging with stopDrag().

We'll need to know the position of the scrollbar in order to scroll the text; this means we'll have to play with clip properties. This may be your first time using clip properties, so I'll give you a quick crash course on reading and writing them.

Remember when we used daTextBox.scroll in order to retrieve and set the scroll of our textbox? Clip properties work in much the same way. In order to read a clip's property, you can use the following syntax:

[as]value = clipName._property;
[/as]

To set a property, use this:

[as]clipName._property = value;[/as]

There are several properties you can use, and all start with an underscore (_). The most common are _x, _y, _xscale, _yscale, _width, _height, _rotation and _alpha. I'm sure you can guess what most of these do.

Every property you read or write is calculated depending on the position of the center cross of the clip in question. This may be a bit hard to fully understand, so I made a movie that allows you to play with the _xscale of three similar rectangles, where each of their center crosses are placed differently:

Now do you understand what I mean? The movieclips are scaled in relation to the location of their center cross, and once again, this is very important to understand.

The _x and _y properties go one step further. Say you have a setup where a child clip is inside of a parent clip. If you get the child's y position, you will actually get the y distance between the parent clip's center cross and the child clip's center cross.

Scaling the scrollbar and moving it with the arrow buttons also involves playing with properties.

Okay, enough with the blablabla-ing, let's get to work.

Create a new movie clip and name it scrollbarMC. Place a graphic of a scrollbar in it. Make sure the top of the scrollbar is on the center cross. This way, when we'll scale the movie clip, its bottom side will move up, which is what we want.

Place your scrollbar inside of containerMC, in between the up and down arrows. Name it "scrollbar" in the instance properties panel. You will need to make sure that the scrollbar fits exactly in between of the two arrows, like so:

In order to fit the scrollbar in between the two buttons, do not scale it from controllerMC; otherwise, we'll have problems when we'll scale the scrollbar in actionscript. Instead, go into scrollbarMC itself and change the height of the scrollbar from there.

You will need to place the scrollbar at a 0 y position in controllerMC. If you look at the screenshot, you will see that both containerMC and scrollbarMC's crosses are aligned horizontally. If we read scrollbarMC's y position in actionscript, we'll see that it's 0, and this will help us later on.

Okay, it's time for some ActionScript already! Once again, old code is grayed out.

[as]onClipEvent (load) {
    this.loadVariables("text.txt");
    scrolling = 0;
    frameCounter = 1;
    speedFactor = 3;
    numLines = 7;
    resetOnNewFile = true;
    origHeight = scrollbar._height;
    origX = scrollbar._x;
    refreshRate = 12;
    refreshCounter = 0;
    refreshlastMaxscroll = 0;
    loaded = false;
    function refreshScrollBar() {
        daTextBox.scroll = resetOnNewFile ? 1 : Math.min(daTextBox.maxscroll, daTextBox.scroll);
        var totalLines = numLines+daTextBox.maxscroll-1;
        scrollbar._yscale = 100*(numLines)/totalLines;
        deltaHeight = origHeight-scrollbar._height;
        lineHeight = deltaHeight/(daTextBox.maxScroll-1);
        updateScrollBarPos();
    }
    function updateScrollBarPos() {
        scrollbar._y = lineHeight*(daTextBox.scroll-1);
    }
}
onClipEvent (enterFrame) {
    if (loaded) {
        if (refreshCounter%refreshRate == 0 && daTextBox.maxscroll != refreshLastMaxScroll) {
            refreshScrollBar();
            refreshLastMaxScroll = daTextBox.maxscroll;
            refreshCounter = 0;
        }
        refreshCounter++;
    }
    if (frameCounter%speedFactor == 0) {
        if (scrolling == "up" && daTextBox.scroll>1) {
            daTextBox.scroll--;
            updateScrollBarPos();
        } else if (scrolling == "down" && daTextBox.scroll<daTextBox.maxscroll) {
            daTextBox.scroll++;
            updateScrollBarPos();
        }
        frameCounter = 0;
    }
    frameCounter++;
}
onClipEvent (mouseDown) {
    if (up.hitTest(_root._xmouse, _root._ymouse)) {
        scrolling = "up";
        frameCounter = speedFactor;
        up.gotoAndStop(2);
    }
    if (down.hitTest(_root._xmouse, _root._ymouse)) {
        scrolling = "down";
        frameCounter = speedFactor;
        down.gotoAndStop(2);
    }
    if (scrollbar.hitTest(_root._xmouse, _root._ymouse)) {
        scrollbar.startDrag(0, origX, deltaHeight, origX);
        scrolling = "scrollbar";
    }
    updateAfterEvent();
}
onClipEvent (mouseUp) {
    scrolling = 0;
    up.gotoAndStop(1);
    down.gotoAndStop(1);
    stopDrag();
    updateAfterEvent();
}
onClipEvent (mouseMove) {
    if (scrolling == "scrollbar") {
        daTextBox.scroll = Math.round((scrollbar._y)/lineHeight+1);
    }
    updateAfterEvent();
}
onClipEvent (data) {
    loaded = true;
}[/as]

Oh, the humanity! Take a deep breath, make yourself a coffee, and get ready for some serious explanations.

In order to decipher this, we need to look at how the script is executed chronologically. The load clip event is the first one that's fired. We've added a few variable definitions. The numLines variable is the only one you'll need to change; it defines the visible number of lines in the textbox. The resetOnNewFile variable is used to indicate the behaviour of the scroller when we load a new file: if false, the scroller stays there, and if true, the scroller resets to the beginning of the text. We also store the original height and x position of the scrollbar, which we'll need later on.

We also added two custom functions. The load clip event is an ideal place for custom functions, since it only gets fired once. We'll talk about what these two functions do later on.

Once the text file is loaded, we need to change the height of the scrollbar according to the length of the text, and so we use the custom refreshScrollBar() function.

Let's take a look at the initScrollBar function line by line:

[as]1. function refreshScrollBar(){
 
2.  daTextBox.scroll = resetOnNewFile ? 1 : Math.min(daTextBox.maxscroll, daTextBox.scroll);

3.  var totalLines = numLines + daTextBox.maxscroll - 1;
4.  scrollbar._yscale = 100*(numLines)/totalLines;
5.  deltaHeight = origHeight - scrollbar._height;
6.  lineHeight = deltaHeight/(daTextBox.maxScroll - 1); 
7.  updateScrollBarPos();
  
8. }[/as]

The second line deals with loading multiple text files. Depending on the value of resetOnNewFile, the movie will either reset the scroller when it encounters a new text file, or it will stay where it used to be. This line uses a shorthand if function. The way it works is simple:

[as]valueOfVariable = condition ? valueIfTrue : valueIfFalse;[/as]

It is simply a means of saving space when using very simple ifs. The Math.min(daTextBox.maxscroll, daTextBox.scroll) is used to correct a bug in Flash where the maxscroll property of a textbox can be greater than the scroll property. This would mean that the scrollbar would be bigger than the space between the arrows.

Next, in the third line, we simply store the total number of text lines in our scroller in the totalLines variable.

The fourth line does the real job here. It sets the y scale of the scrollbar in proportion to the number of lines of text. Let's see how this works with an example.

Say we have 20 lines of text and a viewable area of 10 lines; hence, the scrollbar should be half of its maximum height. In that case, numLines is 10, and maxscroll is 11, so totalLines = 10 + 11 - 1 = 20. Our _yscale calculation would give us 100*10/20 = 50, and this would set the scrollbar's y scale to 50%. This is exactly what we wanted.

Moving on, on line 5, we define the deltaHeight variable, which is the available space for the drag. That available height is the difference the original height of the scrollbar, and the new, adjusted size.

Now, in order to know where the scrolled text should be in relation to the scrollbar, we need to define a lineHeight variable, which we will reuse later. This lineHeight variable is the amount of pixels by which we should move the scrollbar in order to scroll the text by 1. We finish this off by asking another function to update the scrollbar's position, aptly named updateScrollBarPos(). We'll take a look at this function later.

Well, that was the hard part. The rest is pretty simple, and essentially builds on what we have just seen. In the mouseDown clip event, we have added an action to account for clicks on the scrollbar:

[as]1. if(scrollbar.hitTest(_root._xmouse,_root._ymouse)){
2.     scrollbar.startDrag(0,origX,deltaHeight,origX);
3.     scrolling = "scrollbar";
4. }
[/as]

The first line is simply a hitTest to ensure that it was indeed the scrollbar that was clicked, much the same way we tested this with the up and down buttons.

If we clicked the scrollbar, then we should start dragging it; hence we use the startDrag() action. The arguments for startDrag() are, in order, top, left, bottom and right; they are the coordinates of the bounds of the imaginary rectangle in which the caller clip can be dragged. Don't worry, that order confuses me too!

Vertically, we should drag from 0 to deltaHeight, which, as mentioned earlier, is the available space between the scrollbar and the up and down arrows. Horizontally, the scrollbar should stay in the same spot, so we drag it from its original X to its original X, essentially locking it in place horizontally. We finish this up by setting the scrolling variable to "scrollbar", so that other parts of the script know we're dragging.

The updating of the text box's scrolling is handled by the mouseMove clip event:

[as]1. onClipEvent (mouseMove){
2.    if(scrolling == "scrollbar"){
3.       daTextBox.scroll = Math.round((scrollbar._y)/lineHeight + 1);
4.    }
5.    updateAfterEvent();
6. }[/as]

Yep, that's yet another clip event. The mouse move clip event is fired every single time the mouse is moved. This is very useful if we want to adjust the properties of a clip depending on the mouse position, for example.

On the second line, we check that we are indeed dragging the scrollbar. Otherwise, there's no need to update the text box.

The third line is the real engine of the scrollbar. It sets the scroll of the text box according to the y position of the scrollbar. For example, say our lineHeight is 10, and the y position of the scrollbar is 30. That means that we should scroll by 3 lines of text. Since the scroll property is one-based, we add 1 to to these three lines of text, giving us a scroll property of 4. We surround everything with a Math.round function, which rounds our number to the closest integer, because, you guessed it, the scroll property only allows integer values.

We end this clip event with an updateAfterEvent(). Using updateAfterEvent() is particularly useful with mouseMove, as the screen will get updated every time the mouse is moved. This is great if you have drag actions, which are normally jerky, but will be silky smooth if you add an updateAfterEvent() in a mouseMove clip event.

In our mouseUp clip event, we added a stopDrag() action so that the scrollbar stops dragging when the user releases the mouse.

All that we need now is a way to move the scrollbar when we click the up or down buttons. You'll notice that in our enterFrame clip event, we added a call to the updateScrollBarPos() custom function if we are scrolling up or down. Let's dig inside this function:

[as]function updateScrollBarPos(){
 scrollbar._y = lineHeight*(daTextBox.scroll - 1);
}[/as]

The reasoning on this one is the exact inverse of what we had with the mouseMove clip event earlier. Instead of figuring out the scroll of the text box from the y position of the scrollbar, we do the inverse, figuring out the y position of the scrollbar from the scroll of the textbox. Both equations are mathematically equivalent.

That's it?

Yes, that's it. You just deciphered a hefty 100 lines of code using only your wits and willpower. That's right, you, who always said "I don't understand coding, I think I'm thickheaded". Now go into your bathroom, look at yourself in the mirror, and smile. Now look at your watch. It's 4 AM.

Unbeknownst to you, you just learned the fundamental elements of highly complex interactivity. You now know 6 of the 7 clip events, how to manipulate properties, custom functions, loading variables, and how to create un-button buttons. Next thing you'll know, you'll change your username to Flashguru2 on the boards.

I'm happy if this tutorial helped you in any way. If you have any suggestions for upcoming tutorials, or have any questions/technical problems, please e-mail me at [email:patrickmineault@sympatico.ca]. If you want to be notified of upcoming tutorials, simply write a blank e-mail to [email:as_for_flash5_dummies-subscribe@yahoogroups.com] with "subscribe" in the subject line.

Until next time, happy flashing!