-- HORIZONTAL SCROLL (FIELD) -- -- -- © July 2OOO, James Newton -- Revised November 2000 -- -- Use with field members. Makes an editable field scroll -- horizontally if the user enters more text than can be displayed in -- the sprite. -- -- Clicking and dragging to make a selection is buggy when the -- selection is extended to the right. -- PROPERTY DECLARATIONS -- property spriteNum property mySprite -- sprite(spriteNum).member property myMember -- mySprite.member property myRight -- mySprite.right property myLeft -- mySprite.left property myWidth -- width of myMember property myVisibleText -- text which appears in myMember property myFullText -- text as typed by the user property myClippedChars -- number of characters not shown before -- myVisibleText starts -- properties for scroll drag property myStartChar -- the adjusted selStart on mouseDown property myEndChar -- the adjusted selEnd on mouseDown property mySelection -- similar to a text member's selection -- EVENT HANDLERS -- on beginSprite(me) mySprite = sprite(spriteNum) myMember = mySprite.member myRight = mySprite.right myLeft = mySprite.left myWidth = myMember.rect.right myFullText = myMember.text myVisibleText = myFullText myClippedChars = 0 myMember.boxType = #fixed myMember.editable = TRUE myMember.wordWrap = FALSE mySelection = [0, 0] end beginSprite on endSprite(me) myMember.text = myFullText end endSprite on mouseDown(me) -- Tell the next exitFrame to set the myStartChar and myEndChar -- since the selStart and the selEnd have not yet been updated. If -- the user double-clicks, this will adapt to the whole word. myStartChar = -1 end mouseDown on mouseUp(me) myStartChar = VOID the selStart = mySelection[1] - myClippedChars the selEnd = mySelection[2] - myClippedChars end mouseUp on mouseUpOutside(me) me.mouseUp() end mouseUpOutside on keyDown(me) case the keyCode of 36: -- RETURN sendSprite(spriteNum, #validate, myFullText) 48: -- TAB pass 115,116, 126: -- start, page up, up arrow me.jumpToBeginning() 119,121, 125: -- end, page down, down arrow me.jumpToEnd() 123: -- left arrow me.moveBack() 124: --right arrow me.moveForward() 51, 117:-- BACKSPACE, delete me.deleteChars(the keyCode = 117) otherwise -- alphanumeric key me.treatAlphaNumericKey() end case mySelection = [the selStart, the selEnd] + myClippedChars end keyDown on exitFrame(me) if integerP(myStartChar) then -- The mouse was clicked on this field if myStartChar = -1 then -- The user has just clicked on this editable field myStartChar = the selStart + myClippedChars myEndChar = the selEnd + myClippedChars mySelection = [myStartChar, myEndChar] else if the mouseH > myRight or the mouseH < myLeft then -- The user is scrolling the selection me.scrollDrag(the mouseH > myRight) end if mySelection = [the selStart, the selEnd] + myClippedChars end if end exitFrame -- PUBLIC METHODS -- on getText(me) -------------------------------------------------------- -- Allows other scripts access to the full text of this behavior --------------------------------------------------------------------- return myFullText end getText on setText(me, newText) ----------------------------------------------- -- Allows other scripts access to the full text of this behavior --------------------------------------------------------------------- myFullText = newText myVisibleText = newText myClippedChars = 0 myMember.text = newText end getText -- PRIVATE METHODS -- on jumpToBeginning(me) -- sent by keyDown() if the key is Start, Page up, Up arrow myVisibleText = myFullText myMember.text = myVisibleText myClippedChars = 0 the selStart = 0 the selEnd = 0 end jumpToBeginning on jumpToEnd(me) -- sent by keyDown() if the key is End, Page down, Down arrow -- Sum the width of each character starting from the last, until -- we have reached the width of the field member myMember.text = myFullText lastChar = myFullText.char.count fullWidth = myMember.charPosToLoc(lastChar + 1).locH myClippedChars = lastChar repeat while myClippedChars startWidth = myMember.charPosToLoc(myClippedChars).locH if fullWidth - startWidth > myWidth then exit repeat end if myClippedChars = myClippedChars - 1 end repeat me.showText() -- Place the insertion point at the end lastChar = lastChar - myClippedChars the selStart = lastChar the selEnd = lastChar end jumpToEnd on moveBack(me) -- sent by keyDown() if the key is Left arrow if the selStart <> the selEnd then -- Unhilite the text without moving the selStart the selEnd = the selStart else if the selStart then -- Move the insertion point back manually the selStart = the selStart - 1 the selEnd = the selStart else -- The insertion point is at the beginning of the visible text if myClippedChars then -- Move the visible text to the right myClippedChars = myClippedChars - 1 me.showText() -- the selStart does not move end if end if end moveBack on moveForward(me) -- sent by keyDown() if the key is Right arrow, and also by -- treatAlphaNumericKey() theStart = the selStart if theStart <> the selEnd then -- Unhilite the text without moving the selEnd the selStart = the selEnd else if myMember.charPosToLoc(theStart + 2).locH < myWidth then -- Move the insertion point forwards manually the selStart = theStart + 1 else -- The insertion point would disappear beyond the end of the -- visible text: move the visible text to the right if myClippedChars < myFullText.char.count then thisChar = theStart + 2 repeat while thisChar if myMember.charPosToLoc(thisChar).locH < myWidth then exit repeat end if myClippedChars = myClippedChars + 1 me.showText() -- the selStart does not move thisChar = thisChar - 1 end repeat end if end if end moveForward on deleteChars(me, deleteKey) -- sent by keyDown() if the key is BACKSPACE or Delete theStart = the selStart startChar = theStart + myClippedChars endChar = the selEnd + myClippedChars if startChar = endChar then -- Insertion point is between two characters if deleteKey then startChar = startChar + 1 if startChar > myFullText.char.count then exit else theStart = theStart + 1 end if end if if startChar then delete myFullText.char[startChar] case theStart of 0: myClippedChars = max(0, myClippedChars - 2) theStart = theStart + (myClippedChars <> 0) 1: if myClippedChars then myClippedChars = myClippedChars - 1 else theStart = theStart - 1 end if otherwise theStart = theStart - 1 end case else exit end if else -- Delete the selected chunk delete myFullText.char[mySelection[1] + 1..mySelection[2]] deleteKey = 1 end if me.showText(theStart) if myMember.charPosToLoc(myFullText.char.count + 1) <= myWidth then me.jumpToEnd() me.showText(mySelection[1] - myClippedChars - not deleteKey) end if end deleteChars on treatAlphaNumericKey(me) -- sent by keyDown() if the key is any other (i.e. alphaNumeric) key startChar = the selStart + myClippedChars endChar = the selEnd + myClippedChars if startChar = endChar then -- The insertion point is between two characters if startChar then put the key after char startChar of myFullText else put the key before char startChar + 1 of myFullText end if else -- A chunk of text is selected put the key into char startChar + 1 to endChar of myFullText end if me.showText() the selEnd = the selStart moveForward(me) end treatAlphaNumericKey on showText(me, insertPoint) -- Sent by jumpToEnd(), moveBack(), moveForward(), deleteChars(), -- treatAlphaNumericKey() myVisibleText = myFullText if myClippedChars then delete myVisibleText.char[1..myClippedChars] end if myMember.text = myVisibleText if integerP(insertPoint) then the selStart = insertPoint the selEnd = insertPoint end if end showText on scrollDrag(me, toRight) if toRight then -- Scroll selection left and extend it if myMember.charPosToLoc(myFullText.char.count + 1) <= myWidth then -- No need to clip any more characters else myClippedChars = myClippedChars + 1 end if me.showText() the selStart = myStartChar - myClippedChars the selEnd = the selEnd + 1 mySelection = [myStartChar, the selEnd + myClippedChars] else -- Scroll selection right and extend it if myClippedChars then myClippedChars = myClippedChars - 1 me.showText() the selStart = 0 the selEnd = myEndChar - myClippedChars mySelection = [myClippedChars, myEndChar] end if end if end scrollDrag -- BEHAVIOR DESCRIPTION AND PARAMETERS -- on isOKToAttach(me, spriteType, spriteNumber) return sprite(spriteNumber).member.type = #field end isOKToAttach on getBehaviorTooltip(me) return \ "Use with field members."&RETURN&RETURN&\ "Makes a field scroll horizontally"&RETURN&\ "if the user enters more text than"&RETURN&\ "can be displayed in the sprite." end getBehaviorTooltip on getBehaviorDescription(me) return \ "HORIZONTAL SCROLL (FIELD)"&RETURN&RETURN&\ "© 17 July 2OOO, James Newton "&RETURN&RETURN&\ "Use with field members."&RETURN&RETURN&\ "Makes an editable field scroll horizontally if the user enters more text than can be displayed in the sprite. Clicking and dragging will scroll the text, as will pressing the arrow keys"&RETURN&RETURN&\ "Use sendSprite(, #getText) to return the full text of the field, and sendSprite(, #setText, ""E&"New text""E&") to place new text in the field." end getBehaviorDescription