Creating the Ultimate Button
December 23, 1998
by Alex Zavatone
Basic stuff: making buttons that work.
One thing that has become obvious in my few years of programming is that if something looks simple, there probably was a lot of work done to make it look that way. That is definately true with Director and even getting the simple things to work. And we can't get more basic than creating buttons that really truly work.
One misconception with creating buttons is that it should be easy. It can be easy - but only after a basic understanding of how proper button behaviours should be structured.
For a button in Director to act like a standard button, the button must be created to have several button states. For this case, we will be creating a button with the up and active state, a down state, an active rollover state and a disabled state. Official "made in the paint window programmer graphics" are displayed below.
For the button to be functional, the code that controls the UI - or how the button reacts to the mouse and displays its state - needs to be separated from the actual task that the button performs on a successful mouse click. Other behaviours can be added to the button as necessary to add more functionality. In one recent project, I had 7 separate bits of functionality (ala behaviours) that were on a sprite to turn it into a button. The order in which the behaviours are added are the order in which they get executed so it is important to order the scripts properly. My button script list from that project follows:
button enable/disable master control
button UI script (we will be creating this)
cursor rollover controller
Text Legend display
Reset Section Text
Navigate down a level
Start New Section
The purpose of the button enable/disable master control is disable or enable all the rest of the functionality. Sometimes buttons need to be turned on or off on demand. This is important in more complex cases like button groups where some buttons are enabled or disabled depending on the settings of the information they are controlling. Buttons that set max and min values from a list are direct examples of this. Clicking one generally implies that you want to turn the other off.
For a button to behave properly, it needs to return a successful click in the following situation: If the button is in an up and enabled state and the mouse is depressed on the graphic, then a down state is set. When in the down state and the mouse is still over the button graphic, if the mouse is released, a successful mouse click is registered.
This sounds easy but in all the possibilities of mousing down, dragging off the button and mousing up or clicking outside the button and dragging inside and mousing up all need to return a false for "did a click happen?" Sometimes when creating a button behaviour, clicking and dragging off the button will set the button state to true for the next time you click the button. All in all, it's a whole lot trickier than it appears to be. Also note that a successful click does not happen on the mousedown - it happens on a mouseUp.
With all this info on how buttons should behave, let's go over what is required to get a button behaviour script to actually work.
The first step is to create a behavior script called "4 state button UI". This script sets up the names of the graphics to be used in each of the button states and provides the "hooks" to disable or enable the button and set the proper graphic for that state. Here is a simple movie of that button functioning for mouse up, mouse down and rollover states. Try clicking and try all cases to generate a false click.
The above movie properly shows off 3 of the 4 button states but how do we make it happen? In the button script, the code will need to respond to several events. These events (called in handler form) follow:
MouseDown: this starts the click process.
MouseUp: this is the end of a successful click process.
MouseEnter: for the setting of the highlight and state tracking.
MouseLeave: for the removal of the highlight and state tracking.
MouseUpOutside: for resetting the pMouseDownOnMe property to 0 for the next click.
SuccessfulClick(): is the pSuccess variable true or not? Returns the value of pSuccess, 1 or 0.
These are all the events that are needed to track the mouse and its state. The properties that are required to hold the info that will make this work also follow: spriteNum: this is a built in property of all behaviors. I just defined it for clarity. pMouseDownOnMe: Need to define this to 1 to designate that a mousedown happened inside the sprite. Prevents users from mousing down on another sprite, dragging over to another button and releasing the mouse and registering a false click.
pSuccess: Did we have a successful click on the button? Values of 1 for yes or 0 for nope.
pBaseMember: the name of the graphic that is for the base or up and active state.
pOverMember: the name of the graphic that is for the active and rolled over state.
pDownMember: the name of the graphic that is for the active and mousedowned state.
pDisabledMember: the name of the graphic that is used for the disabled and inactive state.
Ancestor: holds the routines to control enabling or disabling of the button.
Ok, great but this is supposed to be a 4 state button with a disabled state too right? We can add another script in behavior form that gets called to toggle the button from enabled to disabled. Or we can use a parent/child form to make this easier to apply to a button. By using parent/child, you don't add 2 scripts to the button to make it work and allow it to be disabled/enabled on demand, you just add 1. It's really convenient since, if you don't care about disabling the button, you can just comment out the line where the ancestor is set. Pretty easy stuff. Appropriate handlers need to be added to the ancestor and the button script to control the UI and functionality when switching betwen disabled and enabled. These need to intercept all the events for the button functionality and do nothing if the script is disabled and let the event pass if it is enabled. For the sake of controlling the enabling of the button, the following handlers and properties will be added to the 4 state button script and the disable/enable ancestor script:
Ancestor
Handlers:SetEnabledState: Enable button by setting disabled prop to false and calling UI update handler
SetDisabledState: Disable button by setting disabled prop to true and calling UI update handler
ToggleEnabledState: Based on disabled state call the handler to set other state and UI
GetdisabledState( ): returns if the button is enabled or disabled.
Properties:
pDisabled: 1 is disabled, 0 if active4 State Button UI Script:
Handlers:SetDisabledUI: display the appropriate base graphic for the disabled state
SetEnabledUI: display the appropriate base graphic for the enabled state
But if you want to enable or disable the button, how do you do it? Really simple. If your button is in sprite 3, call the following routines to do exactly what they are named:
SetEnabledState( sprite 3 )
SetDisabledState( sprite 3 )
ToggleEnabledState( sprite 3 )
And one final thing, how do you check for a successful click? The handler named SuccessfulClick() returns that result for you. If your button is in sprite 3, the code to check for a click follows:
if SuccessfulClick( sprite 3 )then -- do the stuff you want the button to do end if
That's about all that's required to create fully functional 4 state button scripts. With all this info and without further adeau... there is a downloadable movie (Mac or PC)with the functional scripts and sample button graphics.
Copyright 1997-2024, Director Online. Article content copyright by respective authors.