-- HORIZONTAL SCROLL (TEXT) -- -- -- © Nov 2OOO, James Newton -- May 2002 revised: -- * copes with cut and pasted text -- * scrolls faster when the left or right arrow keys are -- pressed -- * no longer garbles text when an addition is made -- anywhere before the end -- Sep 2002 * a callback instance can now be set in the SetText -- call to validate the text on Return or Enter -- * SetText will populate a property list with its -- member number and behavior reference, if a -- propList is passed as a parameter. -- Oct 2002 * ID parameter added, so that this can be used to -- filter for the appropriate value during a SetText() -- call if a propList is used as the first parameter. -- If the first parameter of a GetText() call is a -- propList then this ID symbol will be used as the -- property name to which the full text of the behavior -- is attached. To use the member number is the property -- (as in previous versions of this behavior), use TRUE -- or #number as the second parameter (useMemberNumber). -- Feb 2003 * choice of separate callback handlers for Return and -- Enter keys (#validateHandler), and for every other key -- press (#updateHandler) -- Mar 2003 * Scroll() public method added -- * SetCallback() public method added, and SetText() -- adjusted to allow callback object and handlers to be -- set from within a SetText() call. -- -- Use with text members. Makes an editable text member scroll -- horizontally if the user enters more text than can be displayed in -- the sprite. -- -- LIMITATIONS: -- - Command-A and Ctrl-A will only select the text from the beginning -- of the visible section onwards. To select the whole text, the -- user will need either to: -- * Triple-click on the sprite to select the entire text -- * Press the home key to jump to the beginning of the text. -- -- Attempting to detect the Edit | Select all menu item or the -- associated keyboard shortcut is beyond the scope of this -- behavior. -- -- - It is not possible to scroll the text by dragging a selection. -- After a click on an editable field, the playback head does not -- move until the mouse is released. There are thus no frame -- events which could be used to update the contents of the member. -- Nor is there anyway to intercept copy, cut and paste commands -- that would affect a selection which extends beyond what is -- visible in the sprite (see above) so creating such an extended -- selection is somewhat meaningless. ---------------------------------------------------------------------- -- PROPERTY DECLARATIONS -- property spriteNum -- author-defined properties property ID -- symbol id for this sprite/text member property validateHandler -- callback handler for Return and Enter keys property updateHandler -- callback for all other keys -- property pSprite -- sprite(spriteNum) property pMember -- pSprite.member property pWidth -- width of pMember property pAutoTab -- duplicate of the member's autotab property -- property pVisibleText -- text which appears in pMember property pFullText -- text as typed by the user property pClippedChars -- number of characters not shown before -- pVisibleText starts property pScrollTicks -- the value of the ticks when accelerated -- scrolling will start with the arrow keys property pTripleTicks -- after a double-click, ticks before which -- user must click again for a triple-click -- which will select the entire text property pCallback -- instance to call on callback -- EVENT HANDLERS -- on beginSprite(me) --------------------------------------------------- -- ACTION: Initializes the behavior and member properties -------------------------------------------------------------------- pSprite = sprite(spriteNum) pMember = pSprite.member pWidth = pMember.width pFullText = pMember.text pVisibleText = pFullText pClippedChars = 0 -- Convert callback handlers to symbols, as required if updateHandler <> "" then updateHandler = symbol(updateHandler) end if if validateHandler <> "" then validateHandler = symbol(validateHandler) end if -- Ensure the text member has the expected properties pMember.boxType = #fixed -- pMember.editable = TRUE pMember.wordWrap = FALSE pAutoTab = pMember.autotab pMember.autotab = FALSE end beginSprite on endSprite(me) ----------------------------------------------------- -- ACTION: Restores the full text of the member -------------------------------------------------------------------- pMember.text = pFullText pMember.autotab = pAutoTab end endSprite on mouseUp(me) ------------------------------------------------------- -- ACTION: Detects if the user has triple-clicked on the sprite and -- if so, selects the entire text of the member -------------------------------------------------------------------- if the doubleClick then if pTripleTicks > the ticks then -- This is a tripleClick: select the whole text me.mJumpToBeginning() pMember.selection = [0, pFullText.char.count] end if pTripleTicks = the ticks + 20 end if end mouseUp on exitFrame(me) ----------------------------------------------------- -- ACTION: Accelerates the use of right and left arrows to scroll -- the contents of the text member, and detects the use of -- cut and paste -------------------------------------------------------------------- if the clickOn = spriteNum then if pScrollTicks then me.mArrowScroll() else if pMember.text <> pVisibleText then me.mCutOrPaste() end if end if end exitFrame on keyDown(me) ------------------------------------------------------- -- ACTION: Calls the appropriate handler depending on the user's -- input -------------------------------------------------------------------- case the key of RETURN, ENTER: -- Call the callback instance if appropriate return me.mCallback(validateHandler) -- exit handler TAB: if pAutoTab then -- Call the callback instance... me.mCallback(validateHandler) -- ... and jump to next editable sprite return me.mAutoTab() -- exit handler else -- Allow the tab key through pass end if end case case the KeyCode of 115, 116, 126: -- home, page up, up arrow me.mJumpToBeginning() 119, 121, 125: -- end, page down, down arrow me.mJumpToEnd() 123: -- left arrow me.mMoveBack() if not pScrollTicks then pScrollTicks = the ticks + 20 end if 124: -- right arrow me.mMoveForward() if not pScrollTicks then pScrollTicks = the ticks + 20 end if 51, 117:-- BACKSPACE, delete me.mDeleteChars(the keyCode = 117) otherwise -- alphanumeric key me.mTreatAlphaNumericKey() end case end keyDown on keyUp(me) case the keyCode of 36, 76, 115, 116, 126, 119, 121, 125, 123,124: -- The text has not changed 48: -- Only allow TAB key to trigger update callback if it is not -- used to trigger the validate callback if not pAutoTab then me.mCallback(updateHandler) end if otherwise: -- text has changed me.mCallback(updateHandler) end case end keyUp -- PUBLIC METHODS -- on GetText(me, aPropList, useMemberNumber) --------------------------- -- INPUT: may be VOID or a property list -- has no effect unless it is TRUE or -- #number and is a propList. In this case, -- this member number will be used as the key to the string -- in rather than the ID set for this sprite. -- OUTPUT: the full text of this behavior. If a property list is -- passed as a parameter, the full text of a number of -- behavior instances can be collected in a single call. --------------------------------------------------------------------- if ilk(aPropList, #propList) then case useMemberNumber of TRUE, #number: -- Provide this member's number as a reference aPropList.addProp(pMember.number, pFullText) otherwise: -- Provide this sprite's ID as a reference aPropList.addProp(ID, pFullText) end case return aPropList else -- aPropList is not a propList return pFullText end if end GetText on SetText(me, aStringOrList, aPropList) ----------------------------- -- INPUT: can be a string or it can be a property -- list either of the following structures: -- [: , ...] -- OR [: , ...] -- NOTE: The symbols #instance, #update and #validate have a -- special meaning as property names. If the ilk of the -- values of such properties is #script, #instance or -- #symbol, they will be used to define the callback for -- this behavior. If you use these symbols as IDs, and -- supply string values for them, no callback changes will -- be made. See the SetCallback() handler for details. -- is intended for output rather than input. If -- it is a property list, it will be populated with the -- member number of the text member and pointer of this -- behavior. -- ACTION: Sets the text of the member of this sprite. If -- is a property list, the appropriate -- string is chosen from the list, allowing a single call to -- be sent to a number of sprites. -------------------------------------------------------------------- case ilk(aPropList) of #propList: aPropList.setaProp(pMember.number, me) end case case ilk(aStringOrList) of #string: -- Continue after the case statement #propList: -- Check if the propList defines a callback object and handlers me.SetCallback(aStringOrList) -- Filter for this sprite's ID or the text member's number tIndex = aStringOrList.findPos(ID) if tIndex then -- This sprite's ID is present aStringOrList = aStringOrList[tIndex] else tIndex = aStringOrList.findPos(pMember.number) if tIndex then -- The number of this text member is present aStringOrList = aStringOrList[tIndex] end if end if if not stringP(aStringOrList) then -- No valid string is supplied for this sprite exit end if end case pFullText = aStringOrList pVisibleText = aStringOrList pClippedChars = 0 pMember.text = aStringOrList end SetText on SetCallback(me, aPropList) ---------------------------------------- -- SENT BY SetText() and from other scripts -- INPUT: should be a property list which may contain -- one or more of the following properties: -- [#instance: