-- RADIO BUTTON STATES -- -- -- © 31 May 2000, James Newton -- ---------------------------------------------------------------------- -- 040322 JN: getPDL() parameter names simplified. Comments improved. ---------------------------------------------------------------------- -- Use with a group of graphical sprites which act as radio buttons. -- -- When the user clicks on one of the sprites in the group, that -- sprite is displayed in its selected state, while all other sprites -- in the group are deselected. -- -- This behavior only modifies the graphic state: it does not launch -- any action. Use a separate behavior on the same sprite to execute -- an action. Place the Radio Button States behavior at the beginning -- of the list of behaviors on the sprite. This will block any mouse -- clicks when the button is inactive. -- ---------------------------------------------------------------------- -- PARAMETERS: -- -- * Single word identity for this radio button group -- * Single word identity for this particular button -- * Image for OFF state -- * Image for ON state -- * Image if ON state is clicked -- * Image for inactive state -- * Button is intially selected by default? (TRUE | FALSE) -- ---------------------------------------------------------------------- -- ASSOCIATED SCRIPTS: -- <> Use a separate behavior on the same sprite to execute an action. ---------------------------------------------------------------------- -- PROPERTY DECLARATIONS -- property spriteNum -- author-defined parameters property ourIdentity -- #symbol identity of the radio button group property action -- #symbol identity of this particular button property offMember -- member to display when button is deselected property onMember -- member to display when button is selected property switchMember -- member to display when button is selected -- and the user clicks on it a second time property nullMember -- member to display when button is inactive property isSelected -- TRUE if the sprite is selected -- internal properties property pSprite -- sprite(me.spriteNum) property ourGroupList -- list of instances in the radio button group. property ourOnButton -- list of format [anAction], where "anAction" -- is the the value of for the -- selected instance in the radio button group. property ourLastButton-- similar to ourOnButton, but with the action -- symbol for the previously selected button. property pMouseOver -- TRUE if the mouse is over the (active) sprite property pMouseDown -- TRUE while the mouse is held down on the -- (active) sprite property pSaveState -- Temporarily TRUE when a selected button is -- clicked a second or subsequent time property pActive -- TRUE if the button can react to mouse clicks -- SPRITE HANDLER -- on new(me) ourGroupList = [] end new on beginSprite(me) me.initialize() end beginSprite -- EVENT HANDLERS -- on mouseEnter(me) ---------------------------------------------------- -- ACTION: Treats rollover states -------------------------------------------------------------------- if not pMouseDown then exit else if not pActive then exit end if pMouseOver = TRUE -- Show that this button may be toggled call #Toggle_Select, ourGroupList, action end mouseEnter on mouseLeave(me) ---------------------------------------------------- -- ACTION: Treats end of rollover state -------------------------------------------------------------------- if not pMouseDown then exit else if not pActive then exit end if pMouseOver = FALSE -- Revert to showing the currently selected button call #Toggle_Select, ourGroupList, ourOnButton.getLast() end mouseLeave on mouseDown(me) ----------------------------------------------------- -- ACTION: Indicates that the button is pressed and may be selected -------------------------------------------------------------------- if not pActive then -- Prevent the mouseDown event from affecting this or any -- subsequent behavior on this sprite stopEvent exit end if pMouseDown = TRUE pMouseOver = TRUE -- Remember what state the button was in before it was clicked pSaveState = isSelected -- Show that this button may be activated call(#Toggle_Select, ourGroupList, action) end mouseDown on mouseUp(me) ------------------------------------------------------- -- ACTION: Indicates that the button has been selected and allows -- the #mouseUp event through to subsequent behaviors -------------------------------------------------------------------- if not pMouseDown or not pActive then -- Prevent the mouseUp event from affecting this or any -- subsequent behavior on this sprite stopEvent exit end if pMouseDown = FALSE -- Remember which button was previously selected if ourLastButton[1] <> ourOnButton[1] then ourLastButton[1] = ourOnButton[1] end if -- Select this button and deselect all the others ourOnButton[1] = action call(#Toggle_Select, ourGroupList, action) updateStage -- In case the mouseUp action is long -- ** Uncomment the following lines if you want to use a customized -- ** #mouseUp call to subsequent behaviors on the sprite. -- -- Inform subsequent behaviors on the sprite that the button has -- -- been activated. The value of pSaveState is used to indicate -- -- whether the button was already selected before it was clicked. -- -- This lets the behavior concerned determine whether or not to -- -- re-excute the action. -- -- stopEvent -- behaviors = duplicate(pSprite.scriptInstanceList) -- -- Remove any behaviors which have already received the -- -- #mouseUp event -- i = behaviors.getPos(me) -- repeat while i -- behaviors.deleteAt( i) -- i = i - 1 -- end repeat -- call(#mouseUp, behaviors, pSaveState) -- Switch pSaveState off now that it has served its purpose pSaveState = FALSE end mouseUp on mouseUpOutside(me) ------------------------------------------------ -- ACTION: Forgets that the button was pressed -------------------------------------------------------------------- pMouseDown = FALSE end mouseUpOutside -- PRIVATE METHOD -- on initialize(me) ---------------------------------------------------- -- SENT BY beginSprite -------------------------------------------------------------------- pSprite = sprite(spriteNum) pActive = TRUE -- button is active -- Find other behaviors in the same radio button group -- ourGroupList = [] tTempList = [] sendAllSprites(#Toggle_Identify,ourIdentity,ourGroupList,tTempList) if count(tTempList) then ourOnButton = tTempList[1] ourLastButton = tTempList[2] else ourOnButton = [action] ourLastButton = [action] end if if isSelected or count(ourGroupList) = 1 then -- Show the 'selected' member for this button. If a subsequent -- behavior has isSelected set to TRUE that behavior will take -- precedence. call(#Toggle_Select, ourGroupList, action) end if end initialize -- PUBLIC METHODS -- on Toggle_Identify(me, anID, aGroupList, aReturnList) ---------------- -- SENT BY the initialize (beginSprite) handler of this behavior or -- by anothersprite with this behavior -- -- ACTION * Sets ourGroupList to the most recent list of member of -- the radio button group -- * Tells other instances in the group which button is -- currently selected, via aReturnList[1], which acts as a -- pointer to the selected button -------------------------------------------------------------------- if anID <> ourIdentity then -- The call is intended for a different radio button group exit end if aGroupList.append(me) ourGroupList = aGroupList if not count(aReturnList) then if listP(ourOnButton) then aReturnList[1] = ourOnButton aReturnList[2] = ourLastButton end if end if end Toggle_Identify on Toggle_Select(me, anAction, anIDorList) --------------------------- -- SENT BY a behavior on this or another sprite -- INPUT: should be a symbol corresponding to the action -- property of this (or another) Radio Button States -- instance -- can be a symbol or a list of symbols. If -- this handler is called using sendAllSprites() from a -- different script, you can use to determine -- which radio button groups will be affected. -- ACTION: Toggles the button's isSelected property between ON and -- OFF states. If the button is currently inactive, the new -- state is set but the button will not adopt the -- appropriate image until it has been reactivated using -- Toggle_Active. -- If is the same as this instances's -- property, this button will be selected. If not it will -- be deselected. -------------------------------------------------------------------- -- Filter for radio button group if symbolP(anIDorList) then if anAction <> action then exit end if else if listP(anIDorList) then if not anIDorList.getPos(ourIdentity) then exit end if end if -- Set the state of this button isSelected = (anAction = action) if not pActive then -- New value will only take effect once button has been activated exit end if -- Show the appropriate image for the state of the button if isSelected then if pSaveState and pMouseOver and pMouseDown then -- This button has been reselected pSprite.member = switchMember else -- This selection will replace the current selection pSprite.member = onMember end if else -- Deselect this button pSprite.member = offMember end if end Toggle_Select on Toggle_Active(me, aBoolean, anIDorAction) ------------------------- -- SENT BY a behavior on another sprite -- INPUT: may be TRUE or FALSE. Any other value is -- considered to mean "toggle the current value" -- may be a symbol corresponding to either the -- action or ourIdentity properties, or VOID. If it is -- any other value, this handler will ignore the call. -- NOTE: If is a symbol, its value will be used for -- , and will be considered to be -- VOID. You can thus toggle a single button in a group -- ACTION: Sets the pActive state of this behavior, according to -- the value af aBoolean. -- SYNTAX: * Switch on all radio buttons in all groups: -- sendAllSprites(#Toggle_Active, 1) -- * Switch off all radio buttons in group #Choices: -- sendAllSprites(#Toggle_Active, 0, #Choices) -- * Invert state of all radio buttons in group #Options: -- sendAllSprites(#Toggle_Active, #Options) -- * Invert state of #bonus button in group #Options: -- sendAllSprites(#Toggle_Active, #bonus, #Options) -------------------------------------------------------------------- if symbolP(anIDorAction) then case anIDorAction of ourIdentity, action: -- continue otherwise -- This instance is not concerned by the Toggle_Active event exit end case end if case ilk(aBoolean) of #integer: -- Ensure that aBoolean is either 1 (TRUE) or 0 (FALSE) aBoolean = (aBoolean <> 0) if pActive = aBoolean then -- Respect the status quo exit end if -- Toggle to the new value pActive = aBoolean #symbol: case aBoolean of ourIdentity, action: -- No new value is given: toggle to the opposite value pActive = not pActive otherwise -- This instance is not concerned by the Toggle_Active event exit end case otherwise -- No new value is given: toggle to the opposite value pActive = not pActive end case -- Show the appropriate image for the state of the button if pActive then if isSelected then pSprite.member = onMember else pSprite.member = offMember end if else pSprite.member = nullMember end if end Toggle_Active on Toggle_GetSelection(me, aPropList, anID) -------------------------- -- SENT BY a different script in order to determine which button in -- the radio button group is currently selected -- INPUT: may be a property list -- may be a symbol -- ACTION: Adds the action and instance reference of the selected -- button to a property list, in response to a -- sendAllSprites call, or a call to ourGroupList. -- SYNTAX: -- put sendAllSprites(#Toggle_GetSelection, [:], #radioGroup) -- -- [#radioGroup: [#selection: #button2, #instance: ]] -- -- groupList = sendAllSprites(#Toggle_GetGroupList, #radioGroup) -- selectionList = call(#Toggle_GetSelection, groupList, [:]) -- put selectionList -- -- [#radioGroup: [#selection: #button2, #instance: ]] -- put selectionList.radioGroup.selection -- -- #button2 -- -- groupList = sendAllSprites(#Toggle_GetGroupList, #radioGroup) -- put (call(#Toggle_GetSelection, groupList))[1].selection -- -- #button2 -------------------------------------------------------------------- if symbolP(anID) then -- Filter for the appropriate radio button group if anID <> ourIdentity then exit end if else if ilk(aPropList) <> #propList then aPropList = [:] end if if isSelected then -- This is definitely the selected instance aPropList[ourIdentity] = [#selection: action, #instance: me] else -- This may be the selected instance... if none has been indicated -- in the Behavior Parameters dialog, and the user has not yet -- made a choice. if not aPropList.findPos(ourIdentity) then tResult = [#selection: action, #instance: me] aPropList[ourIdentity] = tResult end if end if return aPropList end Toggle_GetSelection on Toggle_SelectPrevious(me) ----------------------------------------- -- SENT BY another script -- ACTION: Resets the buttons in the group to the way they appeared -- before the last selection. This can be useful, for -- example, if the radio buttons indicate the current tool -- selection, and a temporary tool (e.g., eyedropper) is -- used once, then the previous tool is re-adopted. -------------------------------------------------------------------- previousButton = ourLastButton[1] ourLastButton[1] = ourOnButton[1] ourOnButton[1] = previousButton call(#Toggle_Select, ourGroupList, previousButton) end Toggle_SelectPrevious on Toggle_GetSelectedAction(me, aList) ------------------------------- -- SENT BY another script -- INPUT: may be a list or propList -- ACTION: if aList is a list or propList, adds a pointer to -- ourOnButton to the list -- OUTPUT: Returns a pointer to ourOnButton so that the other -- scripts can track changes to the button states at all -- times -------------------------------------------------------------------- case ilk(aList) of #list: if not aList.count() then aList.append(ourOnButton) end if #propList: aList[ourIdentity] = ourOnButton otherwise: return ourOnButton end case end Toggle_GetSelectedAction on Toggle_GetGroupList(me, anIDorList, aList) ------------------------ -- SENT BY a different script -- INPUT: may be an ID symbol, or a list if no -- filtering by ID is required -- may be a list, in which case a pointer to -- ourGroupList will be added to it. -- OUTPUT: Returns a pointer to ourGroupList -- BASIC SYNTAX: -- put sendAllSprites(#Toggle_GetGroupList, #radioGroup) -- -- [, , ...] -------------------------------------------------------------------- case ilk(anIDorList) of #symbol: if anIDorList <> ourIdentity then -- This instance is not concerned by the call exit end if #list, #propList: -- Only one parameter is being used if not listP(aList) then aList = anIDorList end if end case case ilk(aList) of #list: if not aList.getPos(ourGroupList) then aList.append(ourGroupList) end if #propList: aList[ourIdentity] = ourGroupList otherwise: return ourGroupList end case end Toggle_GetGroupList -- UTILITY -- on GetDefaultValues (me)---------------------------------------------- -- CALLED by getPropertyDescriptionList -- OUTPUT: Returns usable values even if Director is simply -- recompiling the scripts. If the chosen members have a -- name, this is used. Otherwise a reference of the format -- (member x of castLib y) is used instead. -------------------------------------------------------------------- if the currentSpriteNum then spriteMember = sprite(the currentSpriteNum).member memberNumber = spriteMember.number memberName = spriteMember.name if memberName = "" then memberName = spriteMember end if selectedMember = member(memberNumber + 1) selectedName = selectedMember.name if selectedName = "" then selectedName = selectedMember end if switchMember = member(memberNumber + 2) switchName = switchMember.name if switchName = "" then switchName = switchMember end if disabledMember = member(memberNumber + 3) disabledName = disabledMember.name if disabledName = "" then disabledName = disabledMember end if return [ \ symbol(string(memberName)), \ memberName, \ selectedName, \ switchName, \ disabledName \ ] else return [#Action, member 1, member 1, member 1, member 1] end if end GetDefaultValues -- BEHAVIOR DESCRIPTION AND PARAMETERS -- on isOKToAttach (me, spriteType, spritetNumber) if spriteType = #graphic then -- Allow any type of graphic sprite return TRUE else -- Can't attach to the script channel return FALSE end if end isOKToAttach on getPropertyDescriptionList (me) defaultValues = GetDefaultValues(me) defaultAction = defaultValues[1] defaultValues.deleteAt(1) propertyList = [:] propertyList[ \ #ourIdentity] = [ \ #comment: "Single word identity for this radio button group:", \ #format: #symbol, \ #default: #radioButtonGroup \ ] propertyList[ \ #action] = [ \ #comment: "Single word identity for this particular button:", \ #format: #symbol, \ #default: defaultAction \ ] propertyList[ \ #offMember] = [ \ #comment: "Image for OFF state:", \ #format: #graphic, \ #default: defaultValues[1] \ ] propertyList[ \ #onMember] = [ \ #comment: "Image for ON state:", \ #format: #graphic, \ #default: defaultValues[2] \ ] propertyList[ \ #switchMember] = [ \ #comment: "Image if ON state is clicked:", \ #format: #graphic, \ #default: defaultValues[3] \ ] propertyList[ \ #nullMember] = [ \ #comment: "Image for inactive state:", \ #format: #graphic, \ #default: defaultValues[4] \ ] propertyList[ \ #isSelected] = [ \ #comment: "Button is intially selected by default?", \ #format: #boolean, \ #default: FALSE \ ] return propertyList end getPropertyDescriptionList on getBehaviorToolTip return \ "Use with a group of graphical sprites which act as radio buttons."\ &RETURN&\ "When the user clicks on one of the sprites in the group, that "&\ "sprite is displayed in its selected state, while all other "&\ "sprites in the group are deselected."&RETURN&\ "This behavior only modifies the graphic state: it does not launch "&\ "any action. Use a separate behavior later on the same sprite to "&\ "execute an action." end getBehaviorToolTip on getBehaviorDescription (me) -- The handler name is followed by a space: this handler will not -- appear in the Behavior Inspector scriptName = sendSprite(0, #getScriptName, me) if stringP(scriptName) then code = member(scriptName).scriptText return \ getInitialComments(code)&RETURN&RETURN&\ getHandlerData(code) end if end getBehaviorDescription