I have a project where using a data grid form really simplifies things, however, it’s critical that the user can re-order the list in arbitrary way. To do this I needed to add drag and drop to the data grid.

First I wrote rolled my own:

There two main limitations with this code are that it will only work for a data grid form (not table) and only if the cache controls property is true.

local sDragImage,sControlIndexMap,sOriginalIndexes

on dragStart
   local tControl,tItem
   set the dragData["private"] to "dgDragIndex"&&the dgHilitedIndex of me
   put the dgDataControlOfIndex[the dgHilitedIndex of me] of me into tControl
   lock screen
   import snapshot from tControl
   put the long id of the last image into sDragImage
   set the visible of sDragImage to false
   set the dragImage to the short id of sDragImage
   put the dgIndexes of me into sOriginalIndexes
   delete variable sControlIndexMap
   repeat for each item tItem in the dgIndexes of me
      put tItem into sControlIndexMap[the dgDataControlOfIndex[tItem] of me]
   end repeat
   set the allowableDragActions to "move"
   pass dragStart
end dragStart

on dragMove pX,pY
   local tDragIndex,tNewIndexes,tOverIndex
   if word 1 of the dragData["private"] = "dgDragIndex" then
      unlock screen
      lock cursor -- refresh bug workaround on setting the dgIndexes the dragAction seems to get set to none
      put word 2 of the dragData["private"] into tDragIndex
      set the dragAction to "move"
      if pY > the bottom of me-20 then
         if item 2 of the dgVisibleLines of me <  the dgNumberOfLines of me or the scroll of me is not the dgFormattedHeight of me then 
            set the dgVscroll of me to min(the dgVscroll of me + 20, the dgFormattedHeight of me)
         end if
      else if  pY < the top of me+20 then
         if item 1 of the dgVisibleLines of me >  1 or the scroll of me is not 0 then 
            set the dgVscroll of me to max(the dgVscroll of me - 20,0)
         end if
      end if
      repeat with X=1 to the number of groups of group "dgList" of me
         if the visible of group X of group "dgList" and the short name of the owner of group X of group "dgList" is "dgList" then
            if (pY >= the top of group X of group "dgList" of me) and (pY < (the top of group X of group "dgList" of me+(the bottom of group X of group "dgList" of me-the top of group X of group "dgList" of me) div 2)) then
               -- place above index
               put sControlIndexMap[the long id of group X of group "dgList" of me] into tOverIndex
               --put "over"&&tOverIndex
               if tDragIndex = tOverIndex then 
                  put sOriginalIndexes into tNewIndexes
               else
                  put sOriginalIndexes into tNewIndexes
                  delete item itemOffset(tDragIndex,tNewIndexes) of tNewIndexes
                  put tDragIndex&"," before item itemOffset(tOverIndex,tNewIndexes) of tNewIndexes
               end if
               set the dgIndexes of me to tNewIndexes
               put tNewIndexes into sOriginalIndexes
            else if (pY <= the bottom of group X of group "dgList" of me) and (pY > (the top of group X of group "dgList" of me+(the bottom of group X of group "dgList" of me-the top of group X of group "dgList" of me) div 2)) then
               -- place below index
               put sControlIndexMap[the long id of group X of group "dgList" of me] into tOverIndex
               --put "over"&&tOverIndex
               if tDragIndex = tOverIndex then 
                  put sOriginalIndexes into tNewIndexes
               else
                  put sOriginalIndexes into tNewIndexes
                  delete item itemOffset(tDragIndex,tNewIndexes) of tNewIndexes
                  put ","&tDragIndex after item itemOffset(tOverIndex,tNewIndexes) of tNewIndexes
               end if
               set the dgIndexes of me to tNewIndexes
               put tNewIndexes into sOriginalIndexes
            end if
         end if
      end repeat
   end if
   pass dragMove
end dragMove

on dragEnd
   -- clean up
   if sDragImage <> "" then
      delete sDragImage
      put "" into sDragImage
   end if
   pass dragEnd
end dragEnd

Then I had a poke around the data grid behavior script and found undocumented support for drag and drop. So here’s the new script that does not have the limitations of the above and is obviously far less verbose:

on dragStart
   local tIndex
   if (the dgHeader of the target is empty) then
      put the dgIndex of the dgDataControl of the target into tIndex
      set the dgDragImageIndex of me to tIndex
      set the dragData["private"] to empty
      set the dgTrackDragReorder[tIndex] of me to true
   end if
end dragStart

on DragReorderDrop pOriginatingIndex, pStartLine, pDroppedOnLine
   if (pStartLine is not pDroppedOnLine) then
      SetLineOfIndex pOriginatingIndex, pDroppedOnLine
      send "RefreshList" to me in 0 secs
   end if
end DragReorderDrop

on dragMove
   set the dragaction to "move"
end dragMove
 

Comments are closed.