A Button Behavior with a Visited State
August 17, 2000
by Gary Rosenzweig
I often get asked about how to make a button that changes color or appearance if the user has already visited the frame that the button leads them to. This is an understandably desirable feature, as hyperlinks in Web browsers work this way.
It used to be that buttons only needed one graphic: the button. Then user interfaces became more sophisticated and demanded an up and down state to a button. Soon, art directors wanted rollover states as well. In addition, a "gray" or inactive state of a button is sometimes useful. Now, we also need to add "visited" states to buttons. Of course, these states overlap. You can have a button that has been visited and that is also under the cursor at the moment. In this case, you need a "visited rollover" state.
The complete total comes to seven states: a normal or up state, a down state, a rollover state, a visited normal state, a visited down state, a visited rollover state and an inactive state. That's a lot of graphics when you also consider that you might have dozens of buttons in your program.
Instead of having lots of buttons, each with seven state graphics, I prefer to use other methods, such as Imaging Lingo, to display my buttons and their states. But as this column is about a behavior with a "visited" state, not Imaging Lingo, I'll stick with a simpler solution. We'll have seven button states, each without a text label. Then, we'll overlay a text member on the Stage so that the text appears on the button. This way, each button can use the same set of button graphics, and the only difference will be the text in the sprite on top of it. As a matter of fact, we won't even bother with the inactive button state here, just to keep it to six graphics.
Creating a visited state for a button requires that we keep track of which buttons the user clicked on. More specifically, we want to keep track of which button actions have occurred. This way, if more than one button jumps to the same frame, all such buttons will appear in the visited state once the user uses one of them. So, we will actually be keeping track of frames visited, not buttons used. If your movie is not about jumping from frame to frame, then you should be able to use the same concepts to keep track of whatever you are doing instead.
In this sample movie, we have four frames: a main menu, and three chapters. The three buttons will take you to each of the three chapter frames. On those frames, a "Main Menu" button will take you back to the first frame. As you visit each frame, the chapter buttons show you which you have already visited.
Director 8 sample movies are available for download in Mac or PC format.
In order to keep track of the frames visited, we need to use a global. This is unfortunate, as the behavior must rely on an external piece of information. However, it is necessary, as the list of visited frames must persist from frame to frame, each of which will carry different sprites and behavior instances.
This global will be a list that will contain the name of each frame that the user visited by using this button behavior. It will use the getOne() function to test this list against the frame that the button is meant to take the user to, and display the visited states of that button if applicable.
The rest of the behavior is very similar to the button behaviors that I show in my books. It allows you to specify the frame label that the button takes the user to. It also allows you to have the button not use the visited states. In the sample movie, the "Main Menu" button uses this to avoid the visited state.
-- list of visited frames
global gVisitedFrames
-- button properties
property pJumpFrame, pPressed, pMarkVisited
on getPropertyDescriptionList me
list = [:]
addProp list, #pJumpFrame, [#comment: "Go to frame", #format: #string, #default: ""]
addProp list, #pMarkVisited, [#comment: "Mark if visited", #format: #boolean, #default: TRUE]
return list
end
on beginSprite me
pPressed = FALSE
-- init global if needed
if voidP(gVisitedFrames) then gVisitedFrames = []
-- determine if being rolled over now
if rollover (me.spriteNum) then
setState(me,"Roll")
else
setState(me,"Up")
end if
end
-- rollover
on mouseEnter me
if pPressed then
setState(me,"Down")
else
setState(me,"Roll")
end if
end
-- not rolled over
on mouseLeave me
setState(me,"Up")
end
-- down
on mouseDown me
pPressed = TRUE
setState(me,"Down")
end
-- up, perform action
on mouseUp me
if pPressed then
pPressed = FALSE
setState(me,"Roll")
add gVisitedFrames, pJumpFrame
go to frame pJumpFrame
end if
end
-- up, no action
on mouseUpOutside me
pPressed = FALSE
end
-- set button depending upon previous visits
on setState me, state
if getOne(gVisitedFrames,pJumpFrame) and pMarkVisited then
visited = "Visited"
else
visited = "Normal"
end if
sprite(me.spriteNum).member = member("Button" && visited && state)
end
Note that this behavior is only built to handle frame labels, not numbers. It is always best to use only frame labels, never frame numbers. However, you can modify the script to use frame numbers if you wish. Another note is that if you also offer some other way for the user to get from frame to frame, such as a shortcut key, then you need to add each frame to the gVisitedFrames list as that happens. Otherwise, the behavior will have no way of knowing when to show the visited state of the button.
Gary Rosenzweig's new book "Special Edition Using Director 8" is now available. It's the most comprehensive guide to Director ever, including tons of examples and demo movies. It's suitable for novices and experts alike. More information about the book can be found at http://clevermedia.com/resources/bookstore/book5.html. It can be purchased there, or in your local bookstore.
Copyright 1997-2024, Director Online. Article content copyright by respective authors.