Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Fixes issues where mobileScroller is not recreated when returning to card with DataGrid on it
local sDataArray -- Multi-dimensional array
local sIndexSequencing -- sDataArray indexes in order they should appear
local sInit -- Has control been opened once before?
local sControlIsOpen
constant kDefaultDimmedHiliteColor = "212,212,212"
constant kRowColor = "255,255,255"
constant kHeaderBkgrndStartColor = "219,219,219"
constant kHeaderBkgrndEndColor = "188,188,188"
constant kHeaderBkgrndHiliteStartColor = "194,207,221"
constant kHeaderBkgrndHiliteEndColor = "125,147,148"
constant kHeaderDividerColor = "168,168,168"
constant kHeaderDividerThreeDColor = "227,227,227"
constant kAlternateRowColor = "230,237,247"
constant kDefaultTableColWidth = 100
constant kDefaultRowHeight = 21
constant kDefaultRowColor = "255,255,255"
constant kDefaultCornerColor = "232,232,232"
constant kAlternatingRowModValue = 0 -- 0 to have first color be first, 1 to have first color be alternating color
constant kSortTypes = "text,international,numeric,datetime,system datetime"
constant kSBWidthWin = 17
constant kSBWidthMac = 15
constant kSBWidthLinux = 16
constant kErrInvalidArray = 422
constant kErrInvalidBoolean = 452
constant kErrInvalidNumber = 453
constant kErrPropDoesntExist = 456
constant kErrInvalidInteger = 354
constant kErrInvalidPoint = 355
constant kErrInvalidRect = 356
constant kErrInvalidColor = 343
constant kErrReadOnlyProp = 449
constant kErrInvalidProperty = 348
constant kErrCantFindObject = 619
constant kErrRenameErrorInDestination = 487
constant kFieldEditorName = "DataGridFieldEditor"
local sFieldEditor
local sControlOfIndexA -- Links an index to a particular control. Used when dgProps["cache controls"] = true and drawing is not done in real time.
local sControlHeights -- if uFixedLineHeight is true then the height of a single contorl. Otherwise an array keyed by INDEX of sDataArray.
local sFormattedHeight
local sFormattedWidth
local sControlsRequiredToFillSpace
local sHilitedIndexes -- comma delimited list
local sFirstIndexClickedWithShiftKeyDown -- When shift clicking we need to store first index clicked on for reference
local sPendingMsgsA
local sRunningActionsA
local sIsAnimating = false
local sDeselectOnMouseUp
local sSystemA -- stores system specific settings
local sFocusLeftMe
local sDefaultDropIndicatorRect
local sDropStructure
local sLockDrawing -- todo: add set/get. When locked we don't redraw when data is created, deleted, reordered or updated.
## for tables
local sTableObjectsA
local sScrollerId
local sPollID
--> Messages (engine)
before preopenControl
if the target is not me then pass preopencontrol
local isOpen
put sControlIsOpen into isOpen
try
_Initialize
put true into sControlIsOpen
if not isOpen then
_DrawAlternatingRows
end if
catch e
put e
end try
pass preopenControl
end preopenControl
before closeControl
if the target is not me then pass closeControl
DeleteFieldEditor
put false into sControlIsOpen
put true into sFocusLeftMe
if the environment is "mobile" then
mobileControlDelete sScrollerId
put empty into sScrollerId
end if
cancel sPollID
pass closeControl
end closeControl
before newGroup
if the target is not me then pass newGroup
_Initialize
pass newGroup
end newGroup
on __PollVisibility
cancel sPollID
if __HasMobileScroller() then
send "__PollVisibility" to me in 300 milliseconds
put the result into sPollID
mobileControlSet sScrollerId, "visible", the effective visible of me
end if
end __PollVisibility
private command _Initialize
if not sInit then
set the wholeMatches to true
local theMasterRect
put the rect of me into theMasterRect
switch the platform
case "Win32"
if "registryRead" is among the items of the securityPermissions then
put queryRegistry("HKEY_CURRENT_USER\Control Panel\Colors\HilightText") into sSystemA["hilited text color"]
if sSystemA["hilited text color"] is not empty then
replace space with comma in sSystemA["hilited text color"]
end if
local theValue
put queryRegistry("HKEY_CURRENT_USER\Control Panel\Desktop\WindowMetrics\ScrollWidth") into theValue
if theValue is an integer then
put abs(theValue/15) into sSystemA["scrollbarWidth"]
end if
end if
break
end switch
## Set behaviors as needed
## These behaviors weren't set in original template
set the behavior of group "dgHeaderMask" of me to the long ID of button "Header Mask" of group "Behaviors" of stack _ResourceStack()
set the behavior of group "dgList" of me to the long ID of button "dgList Message Catcher" of group "Behaviors" of stack _ResourceStack()
## Developer could have set data before control opened
if the keys of sDataArray is empty then
_DeleteControls
_RestorePersistentData
end if
if the environment is not "mobile" then
set the traversalOn of scrollbar "dgScrollbar" of me to false ## take out of tabbing
set the traversalOn of scrollbar "dgHScrollbar" of me to false ## take out of tabbing
set the visible of scrollbar "dgScrollbar" of me to the dgProps["show vscrollbar"] of me is not false
if _ControlType() is "table" then
set the visible of group "dgHorizontalComponents" of me to the dgProps["show hscrollbar"] of me is not false
end if
set the borderWidth of scrollbar "dgScrollbar" of me to 0 ## For Windows 2000
set the borderWidth of scrollbar "dgHScrollbar" of group "dgHorizontalComponents" of me to 0 ## For Windows 2000
_SetScrollbarWidth
else
_CreateMobileScroller
end if
## Set props which didn't come with original Data Grid
if the dgProps["header divider color"] of me is not a color then
set the dgProps["header divider color"] of me to kHeaderDividerColor
end if
if the dgProps["header divider threeD color"] of me is not a color then
set the dgProps["header divider threeD color"] of me to kHeaderDividerThreeDColor
end if
if _ControlType() is "table" then
_table.CreateColumns
end if
_ResetTemplateFieldEditor
## Make sure rect is as it started
lock messages
set the rect of me to theMasterRect
unlock messages
put true into sInit
else
_CreateMobileScroller
end if
ResizeToFit
end _Initialize
private command _CreateMobileScroller
set the visible of scrollbar "dgScrollbar" of me to false
set the visible of scrollbar "dgHScrollbar" of me to false
if the dgProps["show vscrollbar"] of me is not false or \
(_ControlType() is "table" and \
the dgProps["show hscrollbar"] of me is not false) then
if sScrollerId is empty or sScrollerId is not among the lines of mobileControls() then
mobileControlCreate "scroller"
put the result into sScrollerId
end if
mobileControlSet sScrollerId, "canBounce", "true"
mobileControlSet sScrollerId, "pagingEnabled", "false"
mobileControlSet sScrollerId, "canScrollToTop", "true"
mobileControlSet sScrollerId, "delayTouches", "true"
mobileControlSet sScrollerId, "canCancelTouches", "true"
__PollVisibility
end if
end _CreateMobileScroller
command _SetScrollbarWidth pWidth
lock screen
if pWidth is not an integer then
if the dgProps["scrollbar width"] of me is an integer then
put the dgProps["scrollbar width"] of me into pWidth
else
if sSystemA["scrollbarWidth"] is an integer then
put sSystemA["scrollbarWidth"] into pWidth
else
if the platform is "MacOS" then
put kSBWidthMac into pWidth
else if the platform is "win32" then
put kSBWidthWin into pWidth
else
put kSBWidthLinux into pWidth
end if
end if
end if
end if
local theRectV, theRectH
put the rect of scrollbar "dgScrollbar" of me into theRectV
put the rect of scrollbar "dgHScrollbar" of me into theRectH
put item 3 of theRectV - pWidth into item 1 of theRectV
put item 4 of theRectH - pWidth into item 2 of theRectH
set the rect of scrollbar "dgScrollbar" of me to theRectV
set the rect of scrollbar "dgHScrollbar" of group "dgHorizontalComponents" of me to theRectH
unlock screen
end _SetScrollbarWidth
before deleteGroup
if the target is not me then pass deleteGroup
end deleteGroup
before resizeControl
if the target is not me then return empty
ResizeToFit
pass resizeControl
end resizeControl
before focusIn
## update the hilite when focus enters control
if sFocusLeftMe is not false then
_UpdateHiliteColor
end if
put false into sFocusLeftMe
pass focusIn
end focusIn
before openField
if sFocusLeftMe is not false then
_UpdateHiliteColor
end if
pass openField
end openField
before focusOut
## As of Rev 3.5 we don't know whether or not focus is leaving the data grid in focusOut
## We send a message in time and check the focusedobject in order to work around this.
## This is not ideal and leads to other issues as focus shifts around some UIs but it is all we have.
send "_CheckForFocusLeavingMe" to me in 0 milliseconds
pass focusOut
end focusOut
before closeField
send "_CheckForFocusLeavingMe" to me in 0 seconds
pass closeField
end closeField
before exitField
send "_CheckForFocusLeavingMe" to me in 0 seconds
pass exitField
end exitField
command _CheckForFocusLeavingMe
if not sControlIsOpen then return empty
if the long ID of me is not in the long ID of the focusedObject then
## focus left me
put true into sFocusLeftMe
_UpdateHiliteColor
end if
end _CheckForFocusLeavingMe
## Store data that will be sent when user reorders row
setprop dgDragReorderData pValue
put pValue into sDropStructure["drag drop data"]
end dgDragReorderData
getprop dgDragReorderData
return sDropStructure["drag drop data"]
end dgDragReorderData
setprop dgDragImageIndex pIndex
if _ControlType() is "form" then
local theControl
put the dgDataControlOfIndex[pIndex] of me into theControl
if theControl is not empty then
_CreateDragImageFromControl theControl
end if
else
_CreateDragImageFromIndex pIndex
end if
end dgDragImageIndex
setprop dgDragImageLine pLine
if _ControlType() is "form" then
local theControl
put the dgDataControlOfLine[pLine] of me into theControl
if theControl is not empty then
_CreateDragImageFromControl theControl
end if
else
_CreateDragImageFromIndex the dgIndexOfLine[pLine] of me
end if
end dgDragImageLine
private command _CreateDragImageFromControl pControl
if there is not a image "dgDragImage" of me then
lock screen
local msgsAreLocked
put the lockMessages into msgsAreLocked
lock messages
reset the templateImage
create image "dgDragImage" in me
set the lockMessages to msgsAreLocked
set the visible of it to false
unlock screen
end if
export snapshot from pControl to image "dgDragImage" of me as PNG
local theImageOffset
set the dragImage to the ID of image "dgDragImage" of me
put the clickH - the left of pControl & comma & \
the clickV - the top of pControl into theImageOffset
set the dragImageOffset to theImageOffset
end _CreateDragImageFromControl
private command _CreateDragImageFromIndex pIndex
local theControls, theRect, theVisibleRect, msgsAreLocked
put sTableObjectsA["columns"][ line 1 of the keys of sTableObjectsA["columns"] ]["row controls"] into theControls
repeat for each line theControl in theControls
if the dgIndex of theControl is pIndex then
put the rect of theControl into theRect
put _VisibleDataRect() into theVisibleRect
put item 1 of theVisibleRect into item 1 of theRect
put item 3 of theVisibleRect into item 3 of theRect
if there is not a image "dgDragImage" of me then
lock screen
put the lockMessages into msgsAreLocked
lock messages
reset the templateImage
create image "dgDragImage" in me
set the lockMessages to msgsAreLocked
set the visible of it to false
unlock screen
end if
export snapshot from rect theRect of this card to image "dgDragImage" of me as PNG
set the dragImage to the ID of image "dgDragImage" of me
local theImageOffset
put the clickH - item 1 of theRect & comma & \
the clickV - item 2 of theRect into theImageOffset
set the dragImageOffset to theImageOffset
exit repeat
end if
end repeat
end _CreateDragImageFromIndex
## Set to true to turn on drag indicator and announce
## if a successful drop occurs
setprop dgTrackDragReorder [pOriginatingIndex] pValue
if there is not a group "dgDropIndicator" of me then throw "Group Drag Indicator does not exist in list group:" && the long ID of me
if pValue is not sDropStructure["tracking"] then
if pValue then
put pOriginatingIndex into sDropStructure["originating index"]
set the topLeft of group "dgDropIndicator" of me to the topLeft of group "dgList" of me
dispatch "resizeControl" to group "dgDropIndicator" of me
put the rect of group "dgDropIndicator" of me into sDefaultDropIndicatorRect
insert script of button "dgTrackDragDrop" of me into front
set the dgTargetControl of group "dgDropIndicator" of me to the long ID of me
## initialize index mouse is over
dgDragMove the mouseH, the mouseV
else
remove script of button "dgTrackDragDrop" of me from front
set the visible of group "dgDropIndicator" of me to false
put empty into sDropStructure
if there is a image "dgDragImage" of me then
delete image "dgDragImage" of me
end if
end if
put pValue is true into sDropStructure["tracking"]
end if
end dgTrackDragReorder
on dgDragEnd
set the dgTrackDragReorder of me to false
end dgDragEnd
on dgDragDrop
## Cache before we clean up
local processTheDrop
put the visible of group "dgDropIndicator" of me into processTheDrop
local theDropStructure
put sDropStructure into theDropStructure
## If some other control displays a dialog during dragDrop, dragMove will still be sent
## if the mouse moves within the dialog. We don't want to process those any longer at this point.
set the dgTrackDragReorder of me to false
if processTheDrop then
local theStartLine, theDroppedAfterLine, theDroppedOnLine
put the dgLineOfIndex[ theDropStructure["originating index"] ] of me into theStartLine
put max(0, the dgLineOfIndex[ theDropStructure["dropped after index"] ] of me) into theDroppedAfterLine
put theDroppedAfterLine into theDroppedOnLine
if theDroppedAfterLine < theStartLine then add 1 to theDroppedOnLine
dispatch "DragReorderDrop" with theDropStructure["originating index"], \
theStartLine, theDroppedOnLine
end if
end dgDragDrop
## Sent from TrackDragDrop
on dgDragMove pMouseH,pMouseV
## Throttle calls to this
if sRunningActionsA["drag move"] then return empty
## Make sure data grid control will accept drop
if the dragSource contains the long ID of me and (the mouseControl is not empty and the long id of the mouseControl contains the long ID of me) then
set the dragAction to "move"
end if
put true into sRunningActionsA["drag move"]
try
_PositionDropIndicator pMouseH,pMouseV
## We can't send messages so hang out until mouseloc changes
repeat until (the mouseLoc is not pMouseH,pMouseV) or (mouse(1) is "up" and mouse(3) is "up")
## Throttle calls to redrawing
if not sRunningActionsA["v scroll"] then
_ListGroupDragReorderAutoScroll pMouseH,pMouseV
_PositionDropIndicator pMouseH, pMouseV
end if
end repeat
catch e
end try
put false into sRunningActionsA["drag move"]
end dgDragMove
private function _VisibleDataRect
local theRect
put the rect of group "dgListMask" of me into theRect
if _ControlType() is "table" then
if the visible of scrollbar "dgScrollbar" of me then
put the left of scrollbar "dgScrollbar" of me into item 3 of theRect
else
put the right of group "dgHeaderComponents" of me into item 3 of theRect
end if
end if
return theRect
end _VisibleDataRect
private command _PositionDropIndicator pMouseH, pMouseV
-----
local i,theX,theY
local index, theIndex
local showDropIndicator, theDropIndicatorOffset
local theControl, theControlIndex
local theControlsToCheck
local theCorralRect
local theEndControl
local theHeight
local theSequence
local theStartControl
local theTargetControl
-----
local msgsAreLocked
put the lockMessages into msgsAreLocked
set the wholeMatches to true
put false into showDropIndicator
if pMouseH,pMouseV is within _VisibleDataRect() then --the rect of group "dgListMask" of me then
put true into showDropIndicator
if the mouseControl is not empty then
if not (the long ID of the mouseControl contains the long ID of me) then
put false into showDropIndicator ## control over the list but not part of the list
else
put the dgDataControl of the mouseControl into theTargetControl
## Check for drags in empty columns of tables.
if theTargetControl is empty then
if the target is not the name of scrollbar "dgScrollbar" of me then
## Perhaps no column in clicked area or no mouse receiving controls in column
repeat for each line thePotentialControl in _ListOfVisibleControls()
local theRect
put the rect of thePotentialControl into theRect
if pMouseV >= item 2 of theRect and pMouseV <= item 4 of theRect then
put the dgIndex of thePotentialControl into theIndex
put thePotentialControl into theTargetControl
exit repeat
end if
end repeat
end if
## Still no control
## Assume we are below the last control
if theTargetControl is empty then
put the last line of _ListOfVisibleControls() into theTargetControl ## explicitly draw on only visible controls
end if
end if
if theTargetControl is not empty then
-- put true into showDropIndicator
## Determine offset of control in list
put _LineNoOfControlInListControls(theTargetControl, the dgColumn of theTargetControl) into theControlIndex
-- put "ControlIndex:" && theControlIndex
## Look for next/prev control that is not filtered out
## Direction we look depends on position of mouse
## relative to Y of control
put item 2 of the loc of theTargetControl into theY
## Look for start/end controls in our drop
if the dgAcceptsDrop of theTargetControl is false then
## Look for next control that accepts a drop
put line theControlIndex to -1 of sTableObjectsA["visible row controls"] into theControlsToCheck
repeat for each line theControl in theControlsToCheck
if the dgAcceptsDrop of theControl is false then next repeat
else
put theControl into theEndControl
exit repeat
end if
end repeat
## Look for preceding control that accepts a drop
repeat with i = theControlIndex down to 1
put line i of sTableObjectsA["visible row controls"] into theControl
if the dgAcceptsDrop of theControl is false then next repeat
else
put theControl into theStartControl
exit repeat
end if
end repeat
else
put theTargetControl into theStartControl
put theTargetControl into theEndControl
end if
## What is height of drop area as defined by start/end controls?
if theStartControl is empty and theEndControl is empty then
## No drop. Hide the drop indicator
put false into showDropIndicator
else
if theStartControl is empty then put theEndControl into theStartControl
else if theEndControl is empty then put theStartControl into theEndControl
put the bottom of theEndControl - the top of theStartControl into theHeight
if pMouseV < (the top of theStartControl + round(theHeight / 2)) then
## if start/end control are same OR the mouse is above theStartControl then use
## the top of control as reference
if theStartControl is theEndControl or pMouseV < the top of theStartControl then
put the top of theStartControl into theY
put the dgIndex of theStartControl into theIndex
put itemOffset(theIndex, sIndexSequencing) into theSequence
put max(item (theSequence - 1) of sIndexSequencing, 0) into sDropStructure["dropped after index"]
else
put the bottom of theStartControl into theY
put the dgIndex of theStartControl into sDropStructure["dropped after index"]
end if
else
## If start/end control are same OR the mouse below theEndControl then use
## bottom of control as reference
if theEndControl is theStartControl or pMouseV > the bottom of theEndControl then
put the bottom of theEndControl into theY
put the dgIndex of theEndControl into sDropStructure["dropped after index"]
else
put the top of theEndControl into theY
put the dgIndex of theEndControl into theIndex
put itemOffset(theIndex, sIndexSequencing) into theSequence
put max(item (theSequence - 1) of sIndexSequencing, 0) into sDropStructure["dropped after index"]
end if
end if
## Position drop indicator
put _VisibleDataRect() into theCorralRect
put (item 4 of sDefaultDropIndicatorRect - item 2 of sDefaultDropIndicatorRect) / 2 div 1 into theDropIndicatorOffset ## div 1 = floor
lock screen
lock messages
put item 1 of sDefaultDropIndicatorRect into theX
put min(item 4 of theCorralRect, max(item 2 of theCorralRect - theDropIndicatorOffset, theY)) into theY ## don't let outside of the List group
put theY - theDropIndicatorOffset into theY
set the topLeft of group "dgDropIndicator" of me to theX, theY
set the visible of group "dgDropIndicator" of me to true
unlock messages
dispatch "PositionDropIndicator" to group "dgDropIndicator" of me
unlock screen
end if
end if
end if ## mousecontrol is part of list group control
else
## mousecontrol is empty
end if
end if ## within rect of list
set the lockMessages to msgsAreLocked
if not showDropIndicator then
set the visible of group "dgDropIndicator" of me to false
end if
end _PositionDropIndicator
private function _LineNoOfControlInListControls pControl, pColumn
-----
local theLineNo = 0
local theListControl
local i
-----
if _ControlType() is "form" then
repeat for each line theListControl in sTableObjectsA["visible row controls"]
add 1 to i
## We use this technique so that the developer can have uListConrol return a child of the actual list control
## Useful when a record can have more than one possible view.
if pControl ends with theListControl then
put i into theLineNo
exit repeat
end if
end repeat
else
local theShortID
put the short ID of pControl into theShortID
repeat for each line theListControl in sTableObjectsA["columns"][ pColumn ]["row controls"]
add 1 to i
## We use this technique so that the developer can have uListConrol return a child of the actual list control
## Useful when a record can have more than one possible view.
if word 3 of theListControl is theShortID then
put i into theLineNo
exit repeat
end if
end repeat
end if
return theLineNo
end _LineNoOfControlInListControls
private command _ListGroupDragReorderAutoScroll pMouseH, pMouseV
local theMaskRect
put the rect of group "dgListMask" of me into theMaskRect
## Check that mouse is within vertical space of group
if pMouseH > item 1 of theMaskRect and pMouseH < item 3 of theMaskRect then
local theAvailHeight, theScroll, theHotZone, theDiff
put item 4 of theMaskRect - item 2 of theMaskRect into theAvailHeight
put round(theAvailHeight * .1) into theScroll
## Decide the zone where auto scrolling will occur
if the dgProps["fixed row height"] of me then
put round(sControlHeights / 2) into theHotZone
else
put 20 into theHotZone ## 20 is arbitrary number
end if
## First check above
put item 2 of theMaskRect - pMouseV into theDiff
if theDiff > 0 and theDiff <= theHotZone then
put theDiff * -1 into theDiff
-- put (theHotZone - theDiff) * -1 into theDiff ## This speeds up scrolling too much
else
put pMouseV - item 4 of theMaskRect into theDiff
-- put item 4 of theMaskRect - pMouseV into theDiff
if theDiff > 0 and theDiff <= theHotZone then
-- put (theHotZone - theDiff) into theDiff
else
put 0 into theDiff
end if
end if
if abs(theDiff) > 0 and abs(theDiff) <= theHotZone then
local theCurrentScroll
## Mouse is in a hot zone; auto scroll.
put round((theDiff * 5) / 100 * theScroll) into theScroll
put the dgVScroll of me into theCurrentScroll
put theCurrentScroll + theScroll into theScroll
_SetVScroll theScroll
end if
end if
end _ListGroupDragReorderAutoScroll
on scrollbarDrag pScrollValue
if the long ID of the target is the long ID of scrollbar "dgScrollbar" of me then
dgScrollbarDragV pScrollValue
else if the long ID of the target is the long ID of scrollbar "dgHScrollbar" of group "dgHorizontalComponents" of me then
dgScrollbarDragH pScrollValue
else
pass "scrollbarDrag"
end if
end scrollbarDrag
command dgScrollbarDragV pScrollValue
_ScrollListV pScrollValue
end dgScrollbarDragV
command dgScrollbarDragH pScrollValue
_ScrollListH pScrollValue
end dgScrollbarDragH
before arrowKey pDirection
dgArrowKey pDirection
pass arrowkey
-- if the result then pass arrowkey
end arrowKey
command dgArrowKey pDirection
## Look for cases where we pass arrowkey
if the selectedField is not empty and not the lockText of the selectedField then return true
if the dgProps["auto hilite"] of me is false then return true
## Don't let queue of key repeats build up or list might keep scrolling after user releases arrow key
## Mac needs 'autokey'. Windows needs 'keyDown'.
get flushEvents("autokey")
get flushEvents("keyDown")
local theSelectionChanged
put false into theSelectionChanged
lock screen
if sHilitedIndexes is not empty then
set the wholeMatches to true
local thePreviouslyHilitedIndexes
put sHilitedIndexes into thePreviouslyHilitedIndexes
switch pDirection
case "up"
local theItemNo
put itemOffset(item 1 of sHilitedIndexes, sIndexSequencing) into theItemNo
if _IsThisModifierSetActive("shift") and the dgProps["multiple lines"] of me then
if theItemNo > 1 then
local theNewIndex
put max(1, item (theItemNo - 1) of sIndexSequencing) into theNewIndex
put itemOffset(theNewIndex, thePreviouslyHilitedIndexes) into theItemNo
if theItemNo is 0 then
put comma & theNewIndex after thePreviouslyHilitedIndexes
set the dgHilitedIndexes of me to thePreviouslyHilitedIndexes
put true into theSelectionChanged
end if
end if
else
put max(1, item (theItemNo - 1) of sIndexSequencing) into theNewIndex
if theItemNo > 1 then
set the dgHilitedIndexes of me to theNewIndex
put true into theSelectionChanged
else if theItemNo is 1 and sHilitedIndexes is not theNewIndex then
## Case for multiple selections going all the way to top
set the dgHilitedIndexes of me to item 1 of sIndexSequencing
put true into theSelectionChanged
end if
end if
break
case "down"
put itemOffset(the last item of sHilitedIndexes, sIndexSequencing) into theItemNo
if _IsThisModifierSetActive("shift") and the dgProps["multiple lines"] of me then
if theItemNo > 0 and theItemNo < the number of items of sIndexSequencing then
put item (theItemNo + 1) of sIndexSequencing into theNewIndex
put itemOffset(theNewIndex, thePreviouslyHilitedIndexes) into theItemNo
if theItemNo is 0 then
put comma & theNewIndex after thePreviouslyHilitedIndexes
put _SortIndexesSequentially(thePreviouslyHilitedIndexes) into thePreviouslyHilitedIndexes
put thePreviouslyHilitedIndexes into sHilitedIndexes
ScrollIndexIntoView theNewIndex
_HiliteIndexesInVisibleControls
put true into theSelectionChanged
end if
end if
else
local theIndexCount
put the number of items of sIndexSequencing into theIndexCount
put item (theItemNo + 1) of sIndexSequencing into theNewIndex
if theItemNo > 0 and theItemNo < theIndexCount then
set the dgHilitedIndexes of me to theNewIndex
put true into theSelectionChanged
else if theItemNo is theIndexCount and sHilitedIndexes is not theNewIndex then
## Case for multiple selections going all the way to bottom
set the dgHilitedIndexes of me to the last item of sIndexSequencing
put true into theSelectionChanged
end if
end if
break
end switch
else if the dgNumberOfRecords of me > 0 then
set the dgHilitedIndexes of me to 1
end if
if theSelectionChanged then _SelectionChanged thePreviouslyHilitedIndexes
unlock screen
return false
end dgArrowKey
## Scrolls the group vertically when using the scroll wheel
before rawKeyDown pKeyNum
## exit immediately if an editable field is the target and action isn't scroll wheel.
set the wholeMatches to true
if word 1 of the target is "field" and not the lockText of the target and pKeyNum is not among the items of "65308,65309,65310,65311" then pass rawkeydown
-- 65308 - Mouse wheel down
-- 65309 - Mouse wheel up
-- 65310 - Mouse wheel right
-- 65311 - Mouse wheel left
-- 65365 - page up
-- 65366 - page down
-- 65360 - home
-- 65367 - end
## Note: Messages are locked when setting thumbpostion and we call scrolling code directly.
## This is done so that scrolling works when scrollbars are hidden.
switch pKeyNum
case "65360"
## home
if the visible of scrollbar "dgScrollbar" of me or the dgProps["scroll when vScrollbar is hidden"] of me then
_SetVScroll 0
end if
break
case "65367"
## end
if the visible of scrollbar "dgScrollbar" of me or the dgProps["scroll when vScrollbar is hidden"] of me then
_SetVScroll the endValue of scrollbar "dgScrollbar" of me
end if
break
case "65365"
## scroll page up
if the visible of scrollbar "dgScrollbar" of me or the dgProps["scroll when vScrollbar is hidden"] of me then
_SetVScroll the thumbPosition of scrollbar "dgScrollbar" of me - \
the pageIncrement of scrollbar "dgScrollbar" of me
end if
break
case "65366"
## scroll page down
if the visible of scrollbar "dgScrollbar" of me or the dgProps["scroll when vScrollbar is hidden"] of me then
_SetVScroll the thumbPosition of scrollbar "dgScrollbar" of me + \
the pageIncrement of scrollbar "dgScrollbar" of me
end if
break
case "65309" # scroll up
## mouse wheel up
if the visible of scrollbar "dgScrollbar" of me or the dgProps["scroll when vScrollbar is hidden"] of me then
local theAvailHeight
put the height of group "dgListMask" of me into theAvailHeight
local theScroll
put round(theAvailHeight * .1) into theScroll
_SetVScroll round(the thumbPosition of scrollbar "dgScrollbar" of me) - theScroll
end if
break
case "65308" # scroll down
## mouse wheel down
if the visible of scrollbar "dgScrollbar" of me or the dgProps["scroll when vScrollbar is hidden"] of me then
put the height of group "dgListMask" of me into theAvailHeight
put round(theAvailHeight * .1) into theScroll
_SetVScroll round(the thumbPosition of scrollbar "dgScrollbar" of me) + theScroll
end if
break
case "65310"
## mouse wheel right
if _ControlType() is "table" and (the visible of group "dgHorizontalComponents" of me or the dgProps["scroll when hScrollbar is hidden"] of me) then
local theAvailWidth
put the width of group "dgList" of me into theAvailWidth
put round(theAvailWidth * .1) into theScroll
_SetHScroll round(the thumbPosition of scrollbar "dgHScrollbar" of group "dgHorizontalComponents" of me) + theScroll
end if
break
case "65311"
## mouse wheel left
if _ControlType() is "table" and (the visible of group "dgHorizontalComponents" of me or the dgProps["scroll when hScrollbar is hidden"] of me) then
put the width of group "dgList" of me into theAvailWidth
put round(theAvailWidth * .1) into theScroll
_SetHScroll round(the thumbPosition of scrollbar "dgHScrollbar" of group "dgHorizontalComponents" of me) - theScroll
end if
break
default
pass rawKeyDown
end SWITCH
end rawKeyDown
before mouseDown pMouseBtnNum
// Mikey-2015-05-19: [[ Bug 15387 ]] Don't send dgMouseDown on mobile on mouseUp
if the environment is "mobile" then exit mouseDown
dgMouseDown pMouseBtnNum
pass mousedown
end mouseDown
// Mikey-2015-05-19: [[ Bug 15387 ]] Use touchStart for mobile
before touchStart
dgMouseDown 1
pass touchStart
end touchStart
getprop dgClickLine
local theIndex
put the dgClickIndex of me into theIndex
if theIndex > 0 then return the dgLineOfIndex[theIndex] of me
else return empty
end dgClickLine
getprop dgClickIndex
## figure out the index clicked on
local theIndex, theControl
put empty into theIndex
put _RowControlClickedOn() into theControl
if theControl is not empty then
put the dgIndex of theControl into theIndex
end if
return theIndex
end dgClickIndex
getprop dgClickedInDataView
## Note that Rev doesn't report scrollbars as mousecontrol if thumb is not
## showing. Hence the checks for visibility and click not within of vertical scrollbar
## (dglist overlaps with rect of vertical scrollbar)
local theClickLoc
put the clickLoc into theClickLoc
return theClickLoc is within the rect of group "dgListMask" of me \
and (not the visible of scrollbar "dgScrollbar" of me \
or (the visible of scrollbar "dgScrollbar" of me and theClickLoc is not within the rect of scrollbar "dgScrollbar" of me))
end dgClickedInDataView
private function _RowControlClickedOn
local theControl
## figure out the index clicked on
put the dgDataControl of the target into theControl
local theY, theRect
## Make sure user clicked in valid area.
if theControl is empty and the dgClickedInDataView of me then
## Perhaps no column in clicked area or no mouse receiving controls in column
put the clickV into theY
repeat for each line thePotentialControl in _ListOfVisibleControls()
put the rect of thePotentialControl into theRect
if theY >= item 2 of theRect and theY <= item 4 of theRect then
put thePotentialControl into theControl
exit repeat
end if
end repeat
end if
return theControl
end _RowControlClickedOn
command dgMouseDown pMouseBtnNum
## figure out the index clicked on
local theIndex, theControl
put empty into theIndex
put _RowControlClickedOn() into theControl
if theControl is not empty then
put the dgIndex of theControl into theIndex
end if
## Bring focus into control. Do this before any possible exit points.
if theIndex is not empty then
## Clicked on a control. Bring focus into control but away from scrollbar.
if the long ID of me is not in the long ID of the focusedObject or word 1 of the target is "scrollbar" or \
(sFieldEditor is not empty and sFieldEditor is the long ID of the focusedObject) then
focus on graphic "dgBackground" of me
end if
else
## clicked in space but no on list control
focus on graphic "dgBackground" of me
end if
if the dgProps["auto hilite"] of me is false then return empty
local theSelectionChanged
put false into theSelectionChanged
local unlockTheScreen
put true into unlockTheScreen
lock screen
set the wholeMatches to true
## Close field editor. Note: I don't think the target can ever be sFieldEditor
if sFieldEditor is not empty and the long ID of the target is not sFieldEditor then
DeleteFieldEditor true
end if
## No do what we need to do
if theIndex is not empty then
local theHilitedIndexes, thePreviouslyHilitedIndexes
put sHilitedIndexes into theHilitedIndexes
put sHilitedIndexes into thePreviouslyHilitedIndexes
if pMouseBtnNum is 1 then
// Mikey-2015-05-19: [[ Bug 15240 ]] for mobile, if "multiple lines", then every tap selects/deselects a line
if (_IsThisModifierSetActive("command") or the environment is "mobile") and the dgProps["multiple lines"] of me then
## Add or remove hilite
local theItemNo
put itemOffset(theIndex, theHilitedIndexes) into theItemNo
if theItemNo > 0 then
delete item theItemNo of theHilitedIndexes
else
put theIndex into item (the number of items of theHilitedIndexes + 1) of theHilitedIndexes
ScrollIndexIntoView theIndex
end if
put _SortIndexesSequentially(theHilitedIndexes) into theHilitedIndexes
## At this point we want to hilite controls but not scroll them
put theHilitedIndexes into sHilitedIndexes
_HiliteIndexesInVisibleControls
put true into theSelectionChanged
## Update reference for shift clicking
if theHilitedIndexes is empty then
put empty into sFirstIndexClickedWithShiftKeyDown
else if the number of items of theHilitedIndexes is 1 then
put theIndex into sFirstIndexClickedWithShiftKeyDown
end if
else if _IsThisModifierSetActive("shift") and the dgProps["multiple lines"] of me then
if theHilitedIndexes is empty then put theIndex into theHilitedIndexes
if sFirstIndexClickedWithShiftKeyDown is empty then
## If no first index has been logged then index becomes first index
put theIndex into sFirstIndexClickedWithShiftKeyDown
end if
local theIndexItemNo, theShiftKeyIndexItemNo
put itemOffset(theIndex, sIndexSequencing) into theIndexItemNo
put itemOffset(sFirstIndexClickedWithShiftKeyDown, sIndexSequencing) into theShiftKeyIndexItemNo
if theIndexItemNo < theShiftKeyIndexItemNo then
put item theIndexItemNo to theShiftKeyIndexItemNo of sIndexSequencing into theHilitedIndexes
else if theIndexItemNo > theShiftKeyIndexItemNo then
put item theShiftKeyIndexItemNo to theIndexItemNo of sIndexSequencing into theHilitedIndexes
else
put theIndex into theHilitedIndexes
end if
put _SortIndexesSequentially(theHilitedIndexes) into theHilitedIndexes
put theHilitedIndexes into sHilitedIndexes
_HiliteIndexesInVisibleControls
put true into theSelectionChanged
else
## If clicking on a selected control then delay deselecting until mouseUp.
## This allows for drag/drop of multi controls.
## Only applies if not modifier is down.
if the dgProps["multiple lines"] of me and theIndex is among the items of sHilitedIndexes and _IsThisModifierSetActive("") then
put true into sDeselectOnMouseUp
else
unlock screen ## selectionChanged will be sent. Unlock so UI can update.
_SelectTargetControl theControl ## pass in since tables might not have control clicked on
put false into unlockTheScreen ## Don't unlock screen at end of handler.
end if
end if
else if pMouseBtnNum is 3 then
## right-click only changes selection if clicking on index that isn't highlighted
if theIndex is not among the items of theHilitedIndexes then
## Same behavior as mouseclick 1
## single click always inserts index into first index var
put theIndex into sFirstIndexClickedWithShiftKeyDown
put theIndex into sHilitedIndexes
_HiliteIndexesInVisibleControls
put true into theSelectionChanged
end if
end if
## moved to top in 1.0.0 b4
-- ## Clicked on a control. Bring focus into control but away from scrollbar.
-- if the long id of me is not in the long id of the focusedobject or word 1 of the target is "scrollbar" or \
-- (sFieldEditor is not empty and sFieldEditor is the long id of the focusedObject) then
-- focus on graphic "dgBackground" of me
-- end if
else
## moved to top in 1.0.0 b4
-- ## clicked in space but no on list control
-- focus on graphic "dgBackground" of me
end if
if unlockTheScreen then unlock screen
if theSelectionChanged then _SelectionChanged thePreviouslyHilitedIndexes
end dgMouseDown
before mouseUp pMouseBtnNum
// Mikey-2015-05-19: [[ Bug 15387 ]] Don't send dgMouseUp on mobile before mouseUp
if the environment is "mobile" then exit mouseUp
dgMouseUp pMouseBtnNum
pass mouseUp
end mouseUp
// Mikey-2015-05-19: [[ Bug 15387 ]] Use touchEnd on mobile
before touchEnd
dgMouseUp 1
pass touchEnd
end touchEnd
on dgMouseUp pMouseBtnNum
if sDeselectOnMouseUp then
_SelectTargetControl
put false into sDeselectOnMouseUp
end if
end dgMouseUp
before mouseRelease pMouseBtnNum
dgMouseRelease pMouseBtnNum
pass mouseRelease
end mouseRelease
on dgMouseRelease pMouseBtnNum
put false into sDeselectOnMouseUp
end dgMouseRelease
--> Commands (Data Manipulation)
command SelectAll
local thePreviouslyHilitedIndexes, theOrigValue, theSelectionWasChanged
put sHilitedIndexes into thePreviouslyHilitedIndexes
put the dgProps["scroll selections into view"] of me is not false into theOrigValue
set the dgProps["scroll selections into view"] of me to false
try
local theError
set the dgHilitedIndexes of me to sIndexSequencing
put the result into theSelectionWasChanged
catch e
put e into theError
end try
set the dgProps["scroll selections into view"] of me to theOrigValue
if theError is not empty then throw theError
if theSelectionWasChanged then
_SelectionChanged thePreviouslyHilitedIndexes
end if
end SelectAll
function GetDataOfIndex pIndex, pKey
if pKey is not empty or pKey is an array then
return sDataArray[pIndex][pKey]
else
return sDataArray[pIndex]
end if
end GetDataOfIndex
command SetDataOfIndex pIndex, pKey, pValue
repeat with i = 2 to the paramcount
put param(i) into pKey
if pKey is not empty or pKey is an array then
put param(i+1) into sDataArray[pIndex][pKey]
else
put param(i+1) into sDataArray[pIndex]
end if
add 1 to i
end repeat
_StorePersistentData
return empty
end SetDataOfIndex
function GetDataOfLine pLine, pKey
set the wholeMatches to true
return GetDataOfIndex(item pLine of sIndexSequencing, pKey)
end GetDataOfLine
command SetDataOfLine pLine, pKey, pValue
set the wholematches to true
local theIndex
put item pLine of sIndexSequencing into theIndex
repeat with i = 2 to the paramcount
put param(i) into pKey
if pKey is not empty or pKey is an array then
put param(i+1) into sDataArray[theIndex][pKey]
else
put param(i+1) into sDataArray[theIndex]
end if
add 1 to i
end repeat
_StorePersistentData
return empty
end SetDataOfLine
private command _DataCanBeRepresentedAsText pBoolean
local msgsAreLocked
put the lockMessages into msgsAreLocked
lock messages
set the dgProps["data can be represented as text"] of me to pBoolean is true
set the lockMessages to msgsAreLocked
end _DataCanBeRepresentedAsText
command EditCell pColumn, pLineNo
local theIndex
put the dgIndexOfLine[pLineNo] of me into theIndex
EditCellOfIndex pColumn, theIndex
if the result is not empty then
return "no control exists for line column"
else
return empty
end if
end EditCell
command EditCellOfIndex pColumn, pIndex
lock screen
ScrollIndexIntoView pIndex
local theControl
put ColumnControlOfIndex(pColumn, pIndex) into theControl
if _ControlType() is "table" then _table.ScrollColumnIntoView pColumn
if theControl is not empty then
dispatch "EditValue" to theControl with pColumn
unlock screen
return empty
else
unlock screen
return "no control exists for index column"
end if
end EditCellOfIndex
command EditKey pKey, pLineNo
local theIndex
put the dgIndexOfLine[pLineNo] of me into theIndex
EditKeyOfIndex pKey, theIndex
if the result is not empty then
return "no control exists for line"
else
return empty
end if
end EditKey
command EditKeyOfIndex pKey, pIndex
lock screen
ScrollIndexIntoView pIndex
local theControl
put the dgDataControlOfIndex[pIndex] of me into theControl
if theControl is not empty then
dispatch "EditValue" to theControl with pKey
unlock screen
return empty
else
unlock screen
return "no control exists for index"
end if
end EditKeyOfIndex
## Use to add data to the data array
command AddData pDataArray, pSequence
local theError
local theIndex
set the wholeMatches to true
_DataCanBeRepresentedAsText false
put item 2 of the extents of sDataArray + 1 into theIndex
put pDataArray into sDataArray[theIndex]
## Add to list or setting sequence won't work well
put theIndex into item (the number of items of sIndexSequencing + 1) of sIndexSequencing
if pSequence is not empty then
_SetSequenceOfIndex theIndex, pSequence
put the result into theError
end if
if theError is empty then
_StorePersistentData
_ProcessNewIndexData theIndex
_RedrawList
else
## Reset
delete item (itemOffset(theIndex, sIndexSequencing)) of sIndexSequencing
delete local sDataArray[theIndex]
end if
if theError is empty then
return theIndex
else
return theError
end if
end AddData
command AddLine pText, pColumns, pLineNo
-----
local theResult
-----
switch _ControlType()
case "table"
_table.AddLine pText, pColumns, pLineNo
break
case "form"
default
_list.AddLine pText, pColumns, pLineNo
end switch
put the result into theResult
if theResult is an integer then
## Return line number
set the wholeMatches to true
return itemOffset(theResult, sIndexSequencing)
else
return theResult
end if
end AddLine
command DeleteLine pLine
DeleteLines pLine
return the result
end DeleteLine
command DeleteLines pLines
-----
local theIndexes
local theLine
-----
repeat for each item theLine in pLines
put the dgIndexOfLine [theLine] of me & comma after theIndexes
end repeat
delete the last char of theIndexes
DeleteIndexes theIndexes
return the result
end DeleteLines
command DeleteIndex pIndex
DeleteIndexes pIndex
return the result
end DeleteIndex
command DeleteIndexes pIndexes
-----
local theIndex
local theItemNo
local theLineNo
-----
lock screen
set the wholeMatches to true
## Clear out any instances of this index
repeat for each item theIndex in pIndexes
put itemOffset(theIndex, sHilitedIndexes) into theItemNo
if theItemNo > 0 then
delete item theItemNo of sHilitedIndexes
end if
## Clear controls when cached
if the dgProps["cache controls"] of me then
if there is a sControlOfIndexA[theIndex] then
## So that all updates happen on refresh
delete sControlOfIndexA[theIndex]
put lineOffset(sControlOfIndexA[theIndex], sTableObjectsA["all row controls"]) into theLineNo
if theLineNo > 0 then
delete line theLineNo of sTableObjectsA["all row controls"]
subtract 1 from sTableObjectsA["row control count"]
end if
put lineOffset(sControlOfIndexA[theIndex], sTableObjectsA["visible row controls"]) into theLineNo
if theLineNo > 0 then
delete line theLineNo of sTableObjectsA["visible row controls"]
end if
end if
end if
put itemOffset(theIndex, sIndexSequencing) into theItemNo
if theItemNo > 0 then
delete item theItemNo of sIndexSequencing
## Update Formatted Height and UI if already calculated
if sFormattedHeight is not empty then
if the dgProps["fixed row height"] of me then
subtract sControlHeights from sFormattedHeight
else
subtract sControlHeights[theIndex] from sFormattedHeight
end if
end if
end if
delete local sDataArray[theIndex]
end repeat
_StorePersistentData
if sFormattedHeight is not empty then
_ConfigureScrollbar
_AutoHideVScrollbar ## only works for fixed height
end if
## Count and position has changed. Update alternating rows.
_DrawAlternatingRows
if the keys of sDataArray is not empty then
_RedrawList
else
_ResetData
end if
unlock screen
return empty
end DeleteIndexes
--> Commands (Sorting)
command SortDataByKey pKey, pType, pDirection, pCaseSensitive
-----
local msgsAreLocked
local theIndex
local theData
local theDo
local theLine
-----
if pType is not among the items of kSortTypes then put "text" into pType
if pDirection is not "descending" then put "ascending" into pDirection
if pKey is empty then
sort items of sIndexSequencing numeric ascending
else
## so we get a stable sort
repeat for each item theIndex in sIndexSequencing
-- repeat for each key theIndex in sDataArray
put theIndex & tab & line 1 of sDataArray[theIndex][pKey] & cr after theData
end repeat
delete the last char of theData
set the itemDelimiter to tab
set the caseSensitive to pCaseSensitive is true
if pType is "system datetime" then
set the useSystemDate to true
delete word 1 of pType
end if
put "sort lines of theData" && pType && pDirection && "by item 2 to -1 of each" into theDo
do theDo
put empty into sIndexSequencing
repeat for each line theLine in theData
put item 1 of theLine & comma after sIndexSequencing
end repeat
delete the last char of sIndexSequencing
end if
_StorePersistentSequence
lock screen
_ResetIndexesOnControls
_RedrawList
unlock screen
return empty
end SortDataByKey
## Reverses order of current sequence of data
command ReverseSort pColumn
lock screen
if sIndexSequencing is not empty then
local theNewSequence
repeat for each item theIndex in sIndexSequencing
put comma & theIndex before theNewSequence
end repeat
delete the first char of theNewSequence
put theNewSequence into sIndexSequencing
_ResetIndexesOnControls
_RedrawList
end if
if pColumn is not empty then
HiliteAndStoreSortByColumn pColumn
end if
unlock screen
return empty
end ReverseSort
command HiliteAndStoreSortByColumn pColumn
local msgsAreLocked
put the lockMessages into msgsAreLocked
unlock messages
lock screen
local theOldSortKey
put the dgProps["sort by column"] of me into theOldSortKey
if theOldSortKey is not empty and there is a sTableObjectsA["columns"][ theOldSortKey ]["header"]["group"] then
set the dgHilite of sTableObjectsA["columns"][ theOldSortKey ]["header"]["group"] to false
dispatch "LayoutControl" to sTableObjectsA["columns"][ theOldSortKey ]["header"]["group"] \
with the rect of sTableObjectsA["columns"][ theOldSortKey ]["header"]["group"]
end if
if pColumn is not empty and there is a sTableObjectsA["columns"][ pColumn ]["header"]["group"] then
set the dgHilite of sTableObjectsA["columns"][ pColumn ]["header"]["group"] to true
dispatch "LayoutControl" to sTableObjectsA["columns"][ pColumn ]["header"]["group"] \
with the rect of sTableObjectsA["columns"][ pColumn ]["header"]["group"]
end if
lock messages
set the dgProps["sort by column"] of me to pColumn
unlock screen
set the lockMessages to msgsAreLocked
end HiliteAndStoreSortByColumn
## Used internally to dispatch the "SortDataGridColumn" message
private command _SortByColumn pColumn
lock screen
dispatch "SortDataGridColumn" to me with pColumn
if it is not "handled" then
SortByColumn pColumn
end if
unlock screen
end _SortByColumn
command SortByColumn pColumn
if _ControlType() is not "table" then _ThrowError kErrPropDoesntExist, "only tables can be sorted by columns"
local theColPropsA
put the dgProps["column properties"] of me into theColPropsA
if pColumn is not empty and pColumn is not among the keys of theColPropsA then
_ThrowError kErrInvalidProperty, "column '" & pColumn & "' does not exist"
end if
lock screen
## sort and hilite
SortDataByKey pColumn, theColPropsA[pColumn]["sort type"], \
theColPropsA[pColumn]["sort direction"], theColPropsA[pColumn]["sort is case sensitive"]
HiliteAndStoreSortByColumn pColumn
unlock screen
return empty
end SortByColumn
--> Commands (Control)
local sResizingToFit
local sResendResizeToFit
command ResizeToFit
-----
local theError
local theLockLoc
local theOffset
local theRect
-----
## Throttle just in case developer tries to call this from different timers
if sResizingToFit then
put true into sResendResizeToFit
return empty
end if
put true into sResizingToFit
lock screen
put the lockloc of me into theLockLoc
set the lockloc of me to true
local msgsAreLocked
put the lockMessages into msgsAreLocked
set the lockMessages to true
try ## Try so we don't leave group locked
## Clear cache
put empty into sControlsRequiredToFillSpace
put _WorkingGroupRect(the long ID of me) into theRect
set the rect of button "dgEventCatcher" of me to theRect
set the rect of graphic "dgBackground" of me to theRect
## Account for table elements
if _ControlType() is "table" then
_table.LayoutDataArea
else
if the environment is not "mobile" then
if the visible of scrollbar "dgScrollbar" of me then
subtract the width of scrollbar "dgScrollbar" of me from item 3 of theRect
end if
if the visible of scrollbar "dgScrollbar" of me then
set the rect of scrollbar "dgScrollbar" of me to item 3 of theRect, \
item 2 of theRect, item 3 of theRect + the width of scrollbar "dgScrollbar" of me, \
item 4 of theRect - the dgProps["scrollbar corner offset"] of me
else
set the rect of scrollbar "dgScrollbar" of me to item 3 of theRect - the width of scrollbar "dgScrollbar" of me, \
item 2 of theRect, item 3 of theRect, \
item 4 of theRect - the dgProps["scrollbar corner offset"] of me
end if
else if __HasMobileScroller() then
mobileControlSet sScrollerId, "rect", theRect
end if
set the rect of group "dgListMask" of me to theRect
set the rect of group "dgAlternatingRowsMask" of me to theRect
set the topLeft of group "dgList" of me to item 1 to 2 of theRect ## Shift all children of group along with group
set the rect of group "dgList" of me to theRect
end if
## Redo calculations
if the dgProps["cache controls"] of me then
_ResizeCachedControls
else if sFormattedHeight is empty or not the dgProps["fixed row height"] of me then
# Only recalculate if not fixed height or formatted height hasn't been calculated
# since teal-time drawing adjusts rect every time anyway.
_CalculateFormattedHeight
else
_AutoHideVScrollbar ## only works for fixed height
end if
_ConfigureScrollbar
_ConfigureHScrollbar
_RedrawList
catch e
put e into theError
-- put e
finally
set the lockloc of me to theLockLoc
end try
set the lockMessages to msgsAreLocked
unlock screen
put false into sResizingToFit
if theError is not empty then throw theError
if sResendResizeToFit then
send "ResizeToFit" to me in 0 seconds
put false into sResendResizeToFit
end if
end ResizeToFit
private command _DrawList
lock screen
local weHaveSomethingToDraw
put the keys of sDataArray is not empty into weHaveSomethingToDraw
if weHaveSomethingToDraw and sFormattedHeight is empty then
if the dgProps["cache controls"] of me then
_CacheControls
else
_CalculateFormattedHeight
end if
end if
## Update column control cache each time drawing is specifically called
if _ControlType() is "table" then
_table.CacheCustomTemplateUsage
end if
if weHaveSomethingToDraw then
_DrawListWithProperties empty, empty, true
_DrawAlternatingRows
_ShowAlternatingRows
end if
unlock screen
end _DrawList
command ResetList
dgResetList
return empty
end ResetList
/**
* \brief Allows developer to intercept ResetList and manually call code to reset.
*
* \return empty
*/
command dgResetList
lock screen
## For cases where user copied/pasted
if not sInit then _Initialize
local theOrigVScroll, theOrigHScroll
put _GetVScrollPercent() into theOrigVScroll
put _GetHScrollPercent() into theOrigHScroll
_ResetScrollsToZero
_DeleteControls
_ResetInternalCaches
if _ControlType() is "table" then
_table.CreateColumns
end if
ResizeToFit
_DrawAlternatingRows
_ShowAlternatingRows
_SetHScrollPercent theOrigHScroll
_SetVScrollPercent theOrigVScroll
unlock screen
return empty
end dgResetList
command RefreshList
if the keys of sDataArray is not empty then
if the dgProps["cache controls"] of me then
lock screen
_LayoutCachedControls
_RedrawList
unlock screen
else
_ResetIndexesOnControls
_RedrawList
end if
_HiliteIndexesInVisibleControls
else
_ResetData
end if
return empty
end RefreshList
on RefreshIndex pIndex
_RefreshIndexes pIndex
end RefreshIndex
command RefreshLine pLine
local theIndex
put the dgIndexOfLine [pLine] of me into theIndex
if theIndex > 0 then _RefreshIndexes theIndex
end RefreshLine
private command _ResetIndexesOnControls
switch _ControlType()
case "table"
lock messages
repeat for each line theColumn in the dgProps["columns"] of me
repeat for each line theControl in sTableObjectsA["columns"][theColumn]["row controls"]
set the dgIndex of theControl to empty
end repeat
end repeat
unlock messages
break
case "form"
default
if not the dgProps["cache controls"] of me then
lock messages
repeat for each line theControl in sTableObjectsA["all row controls"]
set the dgIndex of theControl to empty
end repeat
unlock messages
end if
end switch
end _ResetIndexesOnControls
private command _ResetControlsOfIndex pIndex
switch _ControlType()
case "table"
lock messages
repeat for each line theColumn in the dgProps["columns"] of me
repeat for each line theControl in sTableObjectsA["columns"][theColumn]["row controls"]
if the dgIndex of theControl is pIndex then
set the dgIndex of theControl to empty
end if
end repeat
end repeat
unlock messages
break
case "form"
default
## Cached controls aren't drawing new data into the same controls so
## we don't reset indexes on them.
if not the dgProps["cache controls"] of me then
lock messages
repeat for each line theControl in sTableObjectsA["all row controls"]
if the dgIndex of theControl is pIndex then
set the dgIndex of theControl to empty
end if
end repeat
unlock messages
end if
end switch
end _ResetControlsOfIndex
private command _RedrawList pVScrollPercent
-----
local thePercent
-----
if the keys of sDataArray is not empty then
if pVScrollPercent is empty then
put _GetVScrollPercent() into pVScrollPercent
end if
local theVScroll
put round(pVScrollPercent * (the endValue of scrollbar "dgScrollbar" of me - the thumbSize of scrollbar "dgScrollbar" of me)) into theVScroll
if sFormattedHeight is empty then
if the dgProps["cache controls"] of me then
_CacheControls
else
_CalculateFormattedHeight
end if
end if
_ScrollListV theVScroll, true
_ShowAlternatingRows
else
_ShowAlternatingRows
end if
return empty
end _RedrawList
command ScrollLineIntoView pLine
set the wholeMatches to true
ScrollIndexIntoView item pLine of sIndexSequencing
end ScrollLineIntoView
command ScrollIndexIntoView pIndex
local theError
## Work off of a 0 based rect, not actual position on card
local theMaskHeight, theOffset, theMaskRect
put the height of group "dgListMask" of me into theMaskHeight
put the dgVScroll of me into theOffset -- round needed for engine bug
put "0," & theOffset & ",0," & theMaskHeight + theOffset into theMaskRect
local theSequence
put the dgLineOfIndex[pIndex] of me into theSequence
if theSequence is 0 then put "index not found" into theError
local theTopOfControl, theBottomOfControl, theFormattedHeight
if theError is empty then
## Determine top and bottom of control
if the dgProps["fixed row height"] of me then
put (theSequence - 1) * sControlHeights into theTopOfControl
put theSequence * sControlHeights into theBottomOfControl
else
## Random sized Controls
repeat for each item theIndex in sIndexSequencing
add sControlHeights[theIndex] to theFormattedHeight
if pIndex is theIndex then
put theFormattedHeight - sControlHeights[theIndex] into theTopOfControl
put theFormattedHeight into theBottomOfControl
exit repeat
end if
end repeat
end if
## If index is off the top then scroll to top of group
## else if index is off the bottom then scroll to the bottom
## We lock messages so no scrollbarDrag message is sent. scrollbarDrag may use a slight delay when
## drawing so that fast scrolling doesn't cue up redraws. We bypass the message
## and call _ScrollListV directly so that screen is updated immediately regardless of how
## scrollbarDrag is finally implemented.
-- ======================
local scrollTheList, theNewVScroll, theControlIsAtLeastAsTallAsMask
put false into scrollTheList
if theBottomOfControl <= item 2 of theMaskRect or theTopOfControl < item 2 of theMaskRect then
## control is off the top of view OR top edge is clipped off
put theTopOfControl into theNewVScroll
put true into scrollTheList
else if theTopOfControl >= item 4 of theMaskRect or theBottomOfControl > item 4 of theMaskRect then
## control is off the bottom of view or bottom edge is clipped off
put theBottomOfControl - theMaskHeight into theNewVScroll
put true into scrollTheList
end if
if scrollTheList then
## If as tall as mask group then scroll top into view.
## Otherwise follow regular rules
put theBottomOfControl - theTopOfControl >= theMaskHeight into theControlIsAtLeastAsTallAsMask
if theControlIsAtLeastAsTallAsMask then
put theTopOfControl into theNewVScroll
end if
if the dgProps["animate selections"] of me and sPendingMsgsA["UpdateScrollAnimation"] is empty then
StartScrollAnimation theNewVScroll
else
cancel sPendingMsgsA["UpdateScrollAnimation"]
put empty into sPendingMsgsA["UpdateScrollAnimation"]
put false into sIsAnimating
_SetVScroll theNewVScroll
end if
end if
end if
return theError
end ScrollIndexIntoView
## See dgRectOfIndex in order to get rect of a control in the data grid.
command ScrollRectIntoView pRect, pPadding
-----
local theItemNo
local theMaskRect
local theScrollToOffset, theVScroll
-----
if pPadding is an integer then
put pPadding & comma & pPadding & comma & pPadding into item 2 of pPadding
else if pPadding is not empty and pPadding is not a rect then
_ThrowError kErrInvalidRect, pPadding && "is not a valid margins value"
else if pPadding is empty then
put 0,0,0,0 into pPadding
end if
## Mask rect is rect of this group with vscroll taken into account
put the rect of group "dgListMask" of me into theMaskRect
local theCurrentVScroll
put the dgVScroll of me into theCurrentVScroll
## left,right are ignored right now
add item 1 of pPadding to item 1 of theMaskRect
add item 2 of pPadding to item 2 of theMaskRect
subtract item 3 of pPadding from item 3 of theMaskRect
subtract item 4 of pPadding from item 4 of theMaskRect
## If mask height is less than rect height than we focus on top of pRect.
## Otherwise we focus on bottom of pRect.
if item 4 of theMaskRect - item 2 of theMaskRect < item 4 of pRect - item 2 of pRect then
put 2 into theItemNo
put item 4 of theMaskRect - item 2 of theMaskRect into theScrollToOffset
else
put 4 into theItemNo
put 0 into theScrollToOffset
end if
-- Debugging
-- put "theMaskRect:" && theMaskRect & cr & \
-- "pRect:" && pRect & cr & \
-- "theItemNo:" && theItemNo & cr & \
-- "theScrollToOffset:" && theScrollToOffset & cr & \
-- "theCurrentVScroll:" && theCurrentVScroll
if _RectIsAtLeastAsTallAsMask(pRect, theMaskRect) then
if _RectCoversMask(pRect, theMaskRect) then
## Rect covers entire visible area. Do nothing.
else
## If rect top or bottom is visible then do nothing. Otherwise scroll top in.
if _TopIsVisible(pRect, theMaskRect) or _BottomIsVisible(pRect, theMaskRect) then
## Nothing
else
## Scroll up to top of control
put theCurrentVScroll - abs(item 2 of theMaskRect - item 2 of pRect) into theVScroll
end if
end if
else if _TopIsClipped(pRect, theMaskRect) then
## Scroll up to top of control
put theCurrentVScroll - abs(item 2 of theMaskRect - item 2 of pRect) into theVScroll
else if _BottomIsClipped(pRect, theMaskRect) then
## scroll down to bottom of control
put theCurrentVScroll - (item 4 of theMaskRect - item theItemNo of pRect) into theVScroll
add theScrollToOffset to theVScroll
else if _TopAndBottomAreClipped(pRect, theMaskRect) then
if item 2 of pRect >= item 4 of theMaskRect then
## scroll down so bottom to bottom of control
put theCurrentVScroll - (item 4 of theMaskRect - item theItemNo of pRect) into theVScroll
add theScrollToOffset to theVScroll
else
## scroll up to top of control
put theCurrentVScroll - abs(item 2 of theMaskRect - item 2 of pRect) into theVScroll
end if
end if
if theVScroll is not empty then
if the dgProps["animate selections"] of me then
StartScrollAnimation theVScroll
else
set the dgVScroll of me to theVScroll
end if
end if
end ScrollRectIntoView
command ResetControl
lock screen
try
## So we don't confuse the engine
if the long ID of me is in the long ID of the focusedObject then focus on graphic "dgBackground" of me
_DeleteControls
_ResetData
if _ControlType() is "table" then
_table.RegenerateColumns
end if
catch e
put e
end try
unlock screen
return empty
end ResetControl
-- Resets all controls in the data grid
private command _ResetAllControls
lock screen
local theControls
if _ControlType() is "table" then
repeat for each key theColumn in sTableObjectsA["columns"]
if sTableObjectsA["columns"][theColumn]["row controls"] is not empty then
put sTableObjectsA["columns"][theColumn]["row controls"] & cr after theControls
end if
end repeat
delete the last char of theControls
else
put sTableObjectsA["all row controls"] into theControls
end if
local theCleansedControls
## Make sure controls exist
repeat for each line theControl in theControls
if there is a theControl then
put theControl & cr after theCleansedControls
end if
end repeat
_ResetControls theCleansedControls
put empty into sTableObjectsA["current"]
local msgsAreLocked
put the lockMessages into msgsAreLocked
lock messages
if __HasMobileScroller() then
mobileControlSet sScrollerId, "vScroll", 0
end if
set the thumbPosition of scrollbar "dgScrollbar" of me to 0
set the lockMessages to msgsAreLocked
unlock screen
end _ResetAllControls
private command _ResetScrollbarsAndRows
## This will call scrollbardrag. We set all structures before this happens.
if __HasMobileScroller() then
mobileControlSet sScrollerId, "vScroll", 0
end if
set the thumbPosition of scrollbar "dgScrollbar" of me to 0
if _ControlType() is "table" then
if __HasMobileScroller() then
mobileControlSet sScrollerId, "hScroll", 0
end if
set the thumbPosition of scrollbar "dgHScrollbar" of group "dgHorizontalComponents" of me to 0
end if
_ConfigureScrollbar
_ConfigureHScrollbar
if the dgProps["fixed row height"] of me then
_AutoHideVScrollbar ## only works for fixed height
end if
_DrawAlternatingRows
_ShowAlternatingRows
end _ResetScrollbarsAndRows
-- Send ResetControl message to any controls that aren't visible.
-- Reset dgIndex
private command _ResetControls pControls
local msgsAreLocked
put the lockMessages into msgsAreLocked
lock messages
## Hide any controls in "all row controls" that aren't part of "visible list controls"
repeat for each line theControl in pControls
if the visible of theControl then
dispatch "ResetData" to theControl
set the visible of theControl to false
set the dgIndex of theControl to empty
end if
end repeat
set the lockMessages to msgsAreLocked
end _ResetControls
private command _ResetData
## In case developer redraws while editor is open
DeleteFieldEditor true
lock screen
## So we don't confuse the engine
if the long ID of me is in the long ID of the focusedObject then focus on graphic "dgBackground" of me
## Time intensive start
-- _ResetAllControls
_DeleteDataControls ## Replaced with above in 1.0.2 build 6. No more errors when deleting control running script!
put empty into sDataArray
## time intensive end
put empty into sIndexSequencing
_StorePersistentData
_ResetInternalCaches
_DataCanBeRepresentedAsText true
## This will call scrollbardrag. We set all structures before this happens.
if __HasMobileScroller() then
mobileControlSet sScrollerId, "vScroll", 0
end if
set the thumbPosition of scrollbar "dgScrollbar" of me to 0
if _ControlType() is "table" then
if __HasMobileScroller() then
mobileControlSet sScrollerId, "hScroll", 0
end if
set the thumbPosition of scrollbar "dgHScrollbar" of group "dgHorizontalComponents" of me to 0
end if
_ConfigureScrollbar
_ConfigureHScrollbar
if the dgProps["fixed row height"] of me then
_AutoHideVScrollbar ## only works for fixed height
end if
_DrawAlternatingRows
_ShowAlternatingRows
unlock screen
end _ResetData
private command _ResetInternalCaches
put empty into sControlOfIndexA
put empty into sControlHeights
put empty into sFormattedHeight
put empty into sHilitedIndexes
put empty into sControlsRequiredToFillSpace
put empty into sFirstIndexClickedWithShiftKeyDown
put empty into sDeselectOnMouseUp
end _ResetInternalCaches
--> Commands (Find)
## pKey can be a string or an array keyed index.
function GetKeyValuesOfIndexes pIndexes, pDelimiter, pKey --, ...
local theIndex,theValues
if pDelimiter is empty then put comma into pDelimiter
local theParamCount, theDelimLength
put the paramCount into theParamCount
put length(pDelimiter) into theDelimLength
repeat for each item theIndex in pIndexes
repeat with i = 3 to theParamCount
put sDataArray[theIndex][param(i)] & pDelimiter after theValues
end repeat
delete char -theDelimLength to -1 of theValues
put cr after theValues
end repeat
delete the last char of theValues
return theValues
end GetKeyValuesOfIndexes
## pSearchA is array-valued index for accessing sDataArray
## pSearchA[1] = key_1
## pSearchA[2] = key_2
command FindIndex pKeyIndexA, pSearchString --, ...
-----
local foundAMatch, theFoundIndex
local i
local theIndex
-----
repeat for each key theIndex in sDataArray
## Developer can pass in multiple search strings to perform an AND search
repeat with i = 1 to the paramCount step 2
if sDataArray[theIndex][param(i)] is param(i+1) then
put true into foundAMatch
else
put false into foundAMatch
end if
## AND search didn't pan out. Move on to next index.
if not foundAMatch then exit repeat
end repeat
if foundAMatch then
put theIndex into theFoundIndex
exit repeat
end if
end repeat
return max(0, theFoundIndex)
end FindIndex
command FindLine pKeyIndexA, pSearchString
-----
local theIndex
-----
FindIndex pKeyIndexA, pSearchString
put the result into theIndex
if theIndex > 0 then
return the dgLineOfIndex[theIndex] of me
else
return 0
end if
end FindLine
--> Type: Template Handlers
private command _ToggleVScrollBarVisibility pBoolean
lock screen
set the visible of scrollbar "dgScrollbar" of me to pBoolean
switch _ControlType()
case "table"
local theOrigHScroll
put _GetHScrollPercent() into theOrigHScroll
_ResetHScrollToZero
_AutoHideHScrollbar
_table.LayoutDataArea
_table.RepositionHeaders
_ConfigureHScrollbar
RefreshList
_SetHScrollPercent theOrigHScroll
break
case "form"
default
local theRect
put the rect of group "dgList" of me into theRect
if the visible of scrollbar "dgScrollbar" of me then
put the left of scrollbar "dgScrollbar" of me into item 3 of theRect
else
put the right of scrollbar "dgScrollbar" of me into item 3 of theRect
end if
set the rect of group "dgListMask" of me to theRect
set the rect of group "dgList" of me to theRect
set the rect of group "dgAlternatingRowsMask" of me to theRect
if not the dgProps["fixed row height"] of me then
_CalculateFormattedHeight
end if
RefreshList
end switch
unlock screen
end _ToggleVScrollBarVisibility
private command _ToggleHScrollBarVisibility pBoolean
lock screen
## todo: can we only perform actions if visible of scrollbar is different than pBoolean?
set the visible of group "dgHorizontalComponents" of me to pBoolean
switch _ControlType()
case "table"
local theOrigVScroll
put _GetVScrollPercent() into theOrigVScroll
_ResetVScrollToZero
_table.LayoutDataArea
local theSetting
put the visible of scrollbar "dgScrollbar" of me into theSetting
_AutoHideVScrollbar
if the visible of scrollbar "dgScrollbar" of me is not theSetting then
_table.LayoutDataArea
end if
_ShowAlternatingRows
_ConfigureScrollbar
RefreshList
_SetVScrollPercent theOrigVScroll
break
case "form"
default
end switch
unlock screen
end _ToggleHScrollBarVisibility
private command _DrawListWithProperties pStartingSequence, pSetVScrollTo, pForceRefresh
lock screen
## For cases where user copied/pasted
if not sInit then _Initialize
DeleteFieldEditor
local theControl
put the long ID of the focusedObject into theControl
local msgsAreLocked, theStart
put the lockMessages into msgsAreLocked
put the milliseconds into theStart
if pStartingSequence is not an integer or pStartingSequence < 1 then put 1 into pStartingSequence
if pSetVScrollTo is not an integer then put 0 into pSetVScrollTo
## Store sequence that visible controls start drawing from
put pStartingSequence into sTableObjectsA["base sequence for visible controls"]
switch _ControlType()
case "table"
_table.DrawWithProperties pSetVScrollTo, pForceRefresh
break
case "form"
default
_list.DrawWithProperties pSetVScrollTo, pForceRefresh
end switch
## Make sure focus stays with us
if the long ID of me is in theControl then
lock messages
if there is not a theControl then
focus on graphic "dgBackground" of me
else
focus on theControl
end if
unlock messages
end if
-- put "time spent in" && param(0) & ":" && the milliseconds - theStart & cr after msg
unlock screen
set the lockMessages to msgsAreLocked
-- put "time spent in" && param(0) & ":" && the milliseconds - theStart & cr after msg
end _DrawListWithProperties
private command _DeleteControls
local i,theControl,msgsAreLocked
lock screen
switch _ControlType()
case "table"
_table.DeleteColumnControls
break
case "form"
default
end switch
_DeleteDataControls
_ResetScrollsToZero
## In case one gets left around
if there is a field kFieldEditorName of group "dgListMask" of me then
put the lockMessages into msgsAreLocked
lock messages
delete field kFieldEditorName of group "dgListMask" of me
set the lockMessages to msgsAreLocked
end if
unlock screen
end _DeleteControls
private command _DeleteDataControls
lock screen
switch _ControlType()
case "table"
_table.DeleteDataControls
break
case "form"
default
_list.DeleteControls
end switch
put empty into sTableObjectsA["current"]
put 0 into sTableObjectsA["row control count"]
local msgsAreLocked
put the lockMessages into msgsAreLocked
lock messages
if __HasMobileScroller() then
mobileControlSet sScrollerId, "vScroll", 0
end if
set the thumbPosition of scrollbar "dgScrollbar" of me to 0
set the lockMessages to msgsAreLocked
unlock screen
end _DeleteDataControls
private command _CalculateFormattedHeight
put empty into sControlHeights
put 0 into sFormattedHeight
if item 2 of line 1 of the extents of sDataArray < 1 then
put kDefaultRowHeight into sControlHeights
return empty
end if
lock screen
switch _ControlType()
case "table"
_table.CalculateFormattedHeight
break
case "form"
default
_list.CalculateFormattedHeight
end switch
_ConfigureScrollbar
_AutoHideVScrollbar ## only works for fixed height
unlock screen
end _CalculateFormattedHeight
## Makes sure that enough controls exist to fill up the visible space
## Returns true if the number of controls required to display all records increased.
private command _FillListWithJustEnoughControls
lock screen
switch _ControlType()
case "table"
_table.FillListWithJustEnoughControls
break
case "form"
default
_list.FillListWithJustEnoughControls
end switch
local theControlCountChanged
put the result into theControlCountChanged
unlock screen
return theControlCountChanged
end _FillListWithJustEnoughControls
private command _HiliteIndexesInVisibleControls
switch _ControlType()
case "table"
_table.HiliteIndexesInVisibleControls
break
case "form"
default
_list.HiliteIndexesInVisibleControls
end switch
end _HiliteIndexesInVisibleControls
private command _UpdateHiliteColor
lock screen
if _ControlType() is "table" then
_table.LayoutRowHilites ## changes colors
end if
_HiliteIndexesInVisibleControls
unlock screen
end _UpdateHiliteColor
--> Type: List
private function _list.GetText pIncludeKeys
-----
local theIndex
local theKey
local theKeys
local theText
-----
put the keys of sDataArray[item 1 of sIndexSequencing] into theKeys
sort lines of theKeys
if pIncludeKeys then
put theKeys into theText
replace cr with tab in theText
put cr after theText
end if
repeat for each item theIndex in sIndexSequencing
repeat for each line theKey in theKeys
put sDataArray[theIndex][theKey] & tab after theText
end repeat
put cr into the last char of theText
end repeat
delete the last char of theText
return theText
end _list.GetText
private command _list.SetText pText, pKeys
-----
local theColNum
local theDataA
local theItem
local theLine
local theSequencing
-----
lock screen
set the itemDelimiter to tab
if pKeys is not empty then
## Developer specified item to key mapping
local theColCount, theColLookupA
put the number of lines of pKeys into theColCount
put 0 into theColNum
repeat for each line theColumn in pKeys
add 1 to theColNum
put theColumn into theColLookupA[theColNum]
end repeat
local theRow
repeat for each line theLine in pText
add 1 to theRow
put 0 into theColNum
put theRow & comma after theSequencing
if theLine is empty then
## Fill in empty records for empty lines
repeat for each line theColumn in pKeys
put empty into theDataA[theRow][theColumn]
end repeat
else
repeat for each item theItem in theLine
add 1 to theColNum
put theItem into theDataA[theRow][ theColLookupA[theColNum] ]
if theColNum is theColCount then exit repeat
end repeat
end if
end repeat
else
## No columns provided. We just create columns named "Label COL_NUM"
repeat for each line theLine in pText
add 1 to theRow
put 0 into theColNum
put theRow & comma after theSequencing
if theLine is empty then
## Fill in empty value for one key
put empty into theDataA[theRow][ "Label 1"]
else
repeat for each item theItem in theLine
add 1 to theColNum
put theItem into theDataA[theRow][ "Label" && theColNum ]
end repeat
end if
end repeat
end if
delete the last char of theSequencing
set the dgData [theSequencing] of me to theDataA
unlock screen
return empty
end _list.SetText
private command _list.AddLine pText, pKeys, pLineNo
-----
local theColNum
local theDataA
local theItem
local theLine,theResult
-----
lock screen
set the itemDelimiter to tab
if pKeys is not empty then
## Developer specified mapping of data to keys
local theColCount, theColLookupA
put the number of lines of pKeys into theColCount
put 0 into theColNum
repeat for each line theColumn in pKeys
add 1 to theColNum
put theColumn into theColLookupA[theColNum]
end repeat
repeat for each line theLine in pText
put 0 into theColNum
repeat for each item theItem in theLine
add 1 to theColNum
put theItem into theDataA[ theColLookupA[theColNum] ]
if theColNum is theColCount then exit repeat
end repeat
AddData theDataA, pLineNo
put the result into theResult
if pLineNo is not empty then add 1 to pLineNo
end repeat
else
## No columns provided. We just create columns named "Label COL_NUM"
repeat for each line theLine in pText
put 0 into theColNum
repeat for each item theItem in theLine
add 1 to theColNum
put theItem into theDataA[ "Label" && theColNum ]
end repeat
AddData theDataA, pLineNo
put the result into theResult
if pLineNo is not empty then add 1 to pLineNo
end repeat
end if
unlock screen
return theResult
end _list.AddLine
private command _list.DrawWithProperties pSetVScrollTo, pForceRefresh
-----
local theError
-----
lock messages
set the vScroll of group "dgList" of me to 0
unlock messages
## Easier to read code
if the dgProps["cache controls"] of me then
_list.DrawCachedControlList pForceRefresh
else
_list.DrawControlsInRealTime pForceRefresh
end if
# Update VScroll every time
lock messages
set the vScroll of group "dgList" of me to pSetVScrollTo
unlock messages
return theError
end _list.DrawWithProperties
private command _list.DeleteControls
-----
local i
local msgsAreLocked
local theControl
-----
put the lockMessages into msgsAreLocked
lock messages ## for speed
repeat for each line theControl in sTableObjectsA["all row controls"]
if there is a control theControl then
delete theControl
end if
end repeat
## Any extra cleanup
repeat until there is not a (group 1 of group "dgList" of me)
delete group 1 of group "dgList" of me
end repeat
repeat until there is not a control 1 of group "dgList" of me
delete control 1 of group "dgList" of me
end repeat
put empty into sTableObjectsA["all row controls"]
put empty into sTableObjectsA["visible row controls"]
set the lockMessages to msgsAreLocked
end _list.DeleteControls
private command _list.FillListWithJustEnoughControls
local controlCountChanged,i
local theControl,theCurrentControlCount,theMsgsAreLocked,theRequiredControlCount
local theTemplateGroup
local msgsAreLocked
put the lockMessages into msgsAreLocked
put false into controlCountChanged
put the dgProps["row template"] of me into theTemplateGroup
## Determine required control count
put _ControlsRequiredToFillSpace() into theRequiredControlCount
## Make sure we have enough controls to fill visible space
put sTableObjectsA["row control count"] into theCurrentControlCount
if theRequiredControlCount > theCurrentControlCount then
if sTableObjectsA["all row controls"] is not empty then put cr after sTableObjectsA["all row controls"]
## Create enough controls
lock messages ## for speed
repeat with i = theCurrentControlCount + 1 to theRequiredControlCount
copy theTemplateGroup to group "dgList" of me
put it into theControl
set the name of theControl to the short name of theControl && format("%04d", i)
put "control id" && word 3 of theControl && "of me" & cr after sTableObjectsA["all row controls"]
## take over geometry
set the lockloc of theControl to true
end repeat
unlock messages
delete the last char of sTableObjectsA["all row controls"]
put the number of lines of sTableObjectsA["all row controls"] into sTableObjectsA["row control count"]
put true into controlCountChanged
else if theRequiredControlCount < theCurrentControlCount then
## To many controls. That is okay. They just hang around invisible.
else
## We have just enough controls
end if
set the lockMessages to msgsAreLocked
return controlCountChanged
end _list.FillListWithJustEnoughControls
private command _list.UpdateAlternatingRowColors
lock screen
local theRow1Color, theRow2Color, theControl, theIndex
put _GetEffectiveColor("row color") into theRow1Color
put _GetEffectiveColor("alternate row color") into theRow2Color
set the wholeMatches to true
repeat for each line theControl in sTableObjectsA["visible row controls"]
put the dgDataControl of theControl into theControl
if there is a graphic "Background" of theControl then
put the dgIndex of theControl into theIndex
## don't color hilited lines
if theIndex is among the items of sHilitedIndexes then next repeat
local theLine
put itemOffset(theIndex, sIndexSequencing) into theLine
if theLine mod 2 is kAlternatingRowModValue then
set the backgroundColor of graphic "Background" of theControl to theRow2Color
else
set the backgroundColor of graphic "Background" of theControl to theRow1Color
end if
end if
end repeat
unlock screen
return empty
end _list.UpdateAlternatingRowColors
-- pControls is "all list controls" for a form or column row controls for a table
private function _GenerateReorderedControlList pControls, pIndexes
local theControl,theControlIndexesA,theControlsWithoutAHome,theIndex,theList
set the wholeMatches to true
## Separate controls based on whether or not they have an index
repeat for each line theControl in pControls
put the dgIndex of theControl into theIndex
if theIndex is among the items of pIndexes then
put theControl into theControlIndexesA[theIndex]
else
put theControl & cr after theControlsWithoutAHome
end if
end repeat
delete the last char of theControlsWithoutAHome
## Now order everything
repeat for each item theIndex in pIndexes
if theControlIndexesA[theIndex] is not empty then
put theControlIndexesA[theIndex] & cr after theList
else
put line 1 of theControlsWithoutAHome & cr after theList
delete line 1 of theControlsWithoutAHome
end if
end repeat
put theControlsWithoutAHome after theList
if the last char of theList is cr then delete the last char of theList
return theList
end _GenerateReorderedControlList
private command _list.DrawControlsInRealTime pForceRefresh
-----
local controlCountWasModified
local i
local msgsAreLocked
local noRedrawNeeded
local theControl, theControlIndex
local theEffectiveControl
local theIndex
local theIndexesInSequence
local theListGroupRect
local theMaxControlNumber
local theRect
local theRowColor
local theSequence
local theTopLeft
-----
## Get geometry properties
put _WorkingGroupRect(the long ID of group "dgList" of me) into theListGroupRect
put item 1 to 2 of theListGroupRect into theTopLeft
put 0 into theControlIndex
## Make sure there are enough controls
_FillListWithJustEnoughControls
put the result into controlCountWasModified
## We use sequencing to draw, not indexes
set the wholeMatches to true
put item sTableObjectsA["base sequence for visible controls"] to -1 of sIndexSequencing into theIndexesInSequence
put _ControlsRequiredToFillSpace() into theMaxControlNumber
## filter the list of sequences
put item 1 to theMaxControlNumber of theIndexesInSequence into theIndexesInSequence
## Get lookup table for indexes that already have controls with correct data
local theMasterControlList
put _GenerateReorderedControlList(sTableObjectsA["all row controls"], theIndexesInSequence) into theMasterControlList
put the lockMessages into msgsAreLocked
put not controlCountWasModified and sTableObjectsA["current"]["indexes"] is theIndexesInSequence into noRedrawNeeded
-- put theIndexesInSequence && the milliseconds & cr into msg
if not noRedrawNeeded or pForceRefresh then
put empty into sTableObjectsA["visible row controls"]
local theRow1Color, theRow2Color, controlHeightIsFixed
put _GetEffectiveColor("row color") into theRow1Color
put _GetEffectiveColor("alternate row color") into theRow2Color
put sTableObjectsA["base sequence for visible controls"] - 1 into theSequence
put the dgProps["fixed row height"] of me into controlHeightIsFixed
repeat for each item theIndex in theIndexesInSequence
## Get control reference
add 1 to theControlIndex
add 1 to theSequence
## This will speed things up and keep us from experiencing visual lag
lock messages
put line theControlIndex of theMasterControlList into theControl
if there is not a theControl then _ThrowError kErrCantFindObject, "control not found when drawing form:" && theControl
unlock messages
set the visible of theControl to true
put theControl & cr after sTableObjectsA["visible row controls"]
put the dgDataControl of theControl into theEffectiveControl
lock messages
## Set geometry
if controlHeightIsFixed then
put theTopLeft & comma & item 3 of theListGroupRect & comma & item 2 of theTopLeft + sControlHeights into theRect
else
put theTopLeft & comma & item 3 of theListGroupRect & comma & item 2 of theTopLeft + the height of theControl into theRect
end if
## Set row color
if there is a graphic "Background" of theEffectiveControl then
if theSequence mod 2 is kAlternatingRowModValue then
set the backgroundColor of graphic "Background" of theEffectiveControl to theRow2Color
else
set the backgroundColor of graphic "Background" of theEffectiveControl to theRow1Color
end if
end if
## If control index is not the index we are working on then
## Load new data
local theCurrentIndex
put the dgIndex of theControl into theCurrentIndex
if theCurrentIndex is not theIndex then
## Allow developer to do something if unloading control
if theCurrentIndex is not empty then
unlock messages
dispatch "PreFillInData" to theControl ## standardized and documented in 1.0.2 build 6
-- dispatch "ResetDataGridControl" to theControl
lock messages
end if
set the dgIndex of theControl to theIndex
local theDataA
if sDataArray[theIndex] is NULL then
unlock messages
GetDataForLine theSequence, theDataA
dispatch "FillInData" to theControl with theDataA
lock messages
else
unlock messages
dispatch "FillInData" to theControl with sDataArray[theIndex]
lock messages
end if
else
-- put "not drawing index:" && theIndex & cr after msg
end if
## Set the rect AFTER filling in data in case filling in data causes the group to resize
unlock messages
set the topLeft of theControl to theTopLeft ## So developer can always count on topleft of controls in template code
lock messages
set the rect of theControl to theRect
unlock messages
dispatch "LayoutControl" to theControl with theRect
## Resize to fit height
if not controlHeightIsFixed then
lock messages
put item 2 of theRect + the formattedHeight of theControl into item 4 of theRect
set the rect of theControl to theRect
unlock messages
end if
put the bottom of theControl into item 2 of theTopLeft
## Hilited index?
if theIndex is among the items of sHilitedIndexes then
_HiliteControl theEffectiveControl, true
else
_HiliteControl theEffectiveControl, false
end if
end repeat
## Store current sequences in list
put theIndexesInSequence into sTableObjectsA["current"]["indexes"]
end if
## Filter control list and reset controls that aren't part of visible list
put line (the number of lines of sTableObjectsA["visible row controls"] + 1) to -1 of theMasterControlList into theMasterControlList
_ResetControls theMasterControlList
return empty
end _list.DrawControlsInRealTime
private command _list.DrawCachedControlList pForceRefresh
-----
local isVisible
local msgsAreLocked
local noRedrawNeeded
local theControl
local theFirstControlHeight
local theIndex
local theIndexesInSequence
local theListGroupRect, theListGroupWidth
local theOldListControls
local theRowColor
local theSequence
local theTopLeft
-----
put false into noRedrawNeeded
put empty into theFirstControlHeight
put the lockMessages into msgsAreLocked
## Get geometry properties
put _WorkingGroupRect(the long ID of group "dgList" of me) into theListGroupRect
put item 1 to 2 of theListGroupRect into theTopLeft
put item 3 of theListGroupRect - item 1 of theListGroupRect into theListGroupWidth
## We use sequencing to draw, not indexes
set the wholeMatches to true
put item sTableObjectsA["base sequence for visible controls"] to -1 of sIndexSequencing into theIndexesInSequence
## Do we need to redraw?
put line 1 of sTableObjectsA["visible row controls"] into theControl
if there is a theControl then
put the dgIndex of theControl is item 1 of theIndexesInSequence into noRedrawNeeded
end if
if not noRedrawNeeded or pForceRefresh then
-- put "calling " & param(0) & cr after msg ## important log
## Cache currently visible controls
put sTableObjectsA["visible row controls"] into theOldListControls
put empty into sTableObjectsA["visible row controls"]
put empty into sTableObjectsA["current"]["indexes"]
local theRow1Color, theRow2Color
put _GetEffectiveColor("row color") into theRow1Color
put _GetEffectiveColor("alternate row color") into theRow2Color
put sTableObjectsA["base sequence for visible controls"] - 1 into theSequence
## This will speed things up and keep us from experiencing visual lag
lock messages
-- put "theIndexesInSequence:" && theIndexesInSequence & cr after msg ## important log
repeat for each item theIndex in theIndexesInSequence
add 1 to theSequence
put theIndex & comma after sTableObjectsA["current"]["indexes"]
## Get control reference
-- put "control (" & theIndex & "):" && theControl & cr after msg ## important log
put sControlOfIndexA[theIndex] into theControl
put theControl & cr after sTableObjectsA["visible row controls"]
unlock messages
local theEffectiveControl
put the dgDataControl of theControl into theEffectiveControl
lock messages
## Set row color
if there is a graphic "Background" of theEffectiveControl then
if theSequence mod 2 is kAlternatingRowModValue then
set the backgroundColor of graphic "Background" of theEffectiveControl to theRow2Color
else
set the backgroundColor of graphic "Background" of theEffectiveControl to theRow1Color
end if
end if
unlock messages