#include <WinAPIMisc.au3>
#include <GUITreeView.au3>
#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>
#include <WinAPISysWin.au3>
Opt("GUICloseOnESC", 0)
Opt("GUIOnEventMode", 1)
$sTitle = "Treeview Drag & Drop Editing"
;Required global constants:
Global $bTreeDrag = False, $bTreeEdit = False, $hDragItem, $hTreeDragImage, $fWhere
$hGui = GUICreate($sTitle, 400, 300, -1, -1, -1, -1)
$label = GUICtrlCreateLabel("Drag and drop separate items or branches to move them." & _
@LF & "To start edit selected item, LMB on item or press Enter." & _
@LF & "To end editing, LMB outside item (apply) or Esc (cancel) / Enter (apply)." & _
@LF & "To insert new item press Insert, to delete existing item press Delete.", 30, 10, 340, 60)
$cTree = GUICtrlCreateTreeView(50,75,300,200,$TVS_HASBUTTONS+$TVS_HASLINES+$TVS_LINESATROOT+$TVS_EDITLABELS+$TVS_CHECKBOXES)
GUICtrlSetState(-1, $GUI_DROPACCEPTED)
$cTreeItemsStart = GUICtrlCreateDummy()
$cTreeItem_1 = GUICtrlCreateTreeViewItem("item 1", $cTree)
$cTreeItem_1a = GUICtrlCreateTreeViewItem("item 1a", $cTreeItem_1)
$cTreeItem_1b = GUICtrlCreateTreeViewItem("item 1b", $cTreeItem_1)
$cTreeItem_2 = GUICtrlCreateTreeViewItem("item 2", $cTree)
$cTreeItem_2a = GUICtrlCreateTreeViewItem("item 2a", $cTreeItem_2)
$cTreeItem_3 = GUICtrlCreateTreeViewItem("item 3", $cTree)
$cTreeItem_3a = GUICtrlCreateTreeViewItem("item 3a", $cTreeItem_3)
$cTreeItem_3a1 = GUICtrlCreateTreeViewItem("item 3a1", $cTreeItem_3a)
$cTreeItem_4 = GUICtrlCreateTreeViewItem("item 4", $cTree)
$cTreeItemsEnd = GUICtrlCreateDummy()
;treeview with images test:
$hImgList = _GUIImageList_Create (16, 16)
For $ii = 1 To $cTreeItemsEnd-$cTreeItemsStart
_GUIImageList_AddIcon ($hImgList, "shell32.dll", 60+$ii*2)
Next
_GUICtrlTreeView_SetNormalImageList(GUICtrlGetHandle($cTree), $hImgList)
$a = 0
For $i = $cTreeItemsStart+1 To $cTreeItemsEnd-1
_GUICtrlTreeView_SetImageIndex($cTree, _GUICtrlTreeView_GetItemHandle($cTree, $i), $a)
_GUICtrlTreeView_SetSelectedImageIndex($cTree, _GUICtrlTreeView_GetItemHandle($cTree, $i), $a)
$a += 1
Next
$label2 = GUICtrlCreateLabel("", 50, 280, 300, 15)
GUISetOnEvent($GUI_EVENT_CLOSE, "SysEvents")
GUISetOnEvent($GUI_EVENT_MOUSEMOVE, "SysEvents")
GUISetOnEvent($GUI_EVENT_PRIMARYUP, "SysEvents")
GUIRegisterMsg($WM_NOTIFY, "On_WM_NOTIFY")
GUISetState()
While 1
Sleep(200)
;add Enter, Esc, Delete and Insert key functionality to treeview edit:
TreeKeyboardFunc($cTree)
WEnd
Func SysEvents()
Local $hTree = GUICtrlGetHandle($cTree)
Switch @GUI_CtrlId
Case $GUI_EVENT_CLOSE
Exit
Case $GUI_EVENT_PRIMARYUP
If $bTreeDrag Then
_WinAPI_InvalidateRect($hTree)
$bTreeDrag = False
_GUIImageList_Destroy($hTreeDragImage) ;delete drag image
_SendMessage($hTree, $TVM_SELECTITEM, $TVGN_DROPHILITE, 0) ;remove DropTarget
_SendMessage($hTree, $TVM_SETINSERTMARK, 0, 0) ;remove InsertMark
If (TreeItemFromPoint($hTree) = $hDragItem) Then ContinueCase
;move item:
$hItem = TreeItemCopy($hTree, $hDragItem, TreeItemFromPoint($hTree), $fWhere)
If $hItem <> 0 Then
_GUICtrlTreeView_SelectItem($hTree, $hItem)
_SendMessage($hTree, $TVM_DELETEITEM, 0, $hDragItem, 0, "wparam", "handle", "hwnd")
EndIf
EndIf
Case $GUI_EVENT_MOUSEMOVE
If $bTreeDrag = False Then ContinueCase
$tPos = _WinAPI_GetMousePos()
$Hwnd = _WinAPI_WindowFromPoint($tPos)
;cancel drag in progress and cleanup if moved outside treeview:
If ($Hwnd <> $hTree) Then
$bTreeDrag = False
_WinAPI_InvalidateRect($hTree)
_GUIImageList_Destroy($hTreeDragImage) ;delete drag image
_SendMessage($hTree, $TVM_SELECTITEM, $TVGN_DROPHILITE, 0) ;remove DropTarget
_SendMessage($hTree, $TVM_SETINSERTMARK, 0, 0) ;remove InsertMark
ContinueCase
EndIf
$hItemHover = TreeItemFromPoint($hTree)
If $hItemHover = 0 Then
;meh
Else
$aRect = __GUICtrlTreeView_DisplayRect($hTree, $hItemHover)
$iTreeY = _WinAPI_GetMousePosY(True, $hTree)
Switch $iTreeY
Case $aRect[1] To $aRect[1]+Int(($aRect[3]-$aRect[1])/4)
_SendMessage($hTree, $TVM_SELECTITEM, $TVGN_DROPHILITE, 0) ;remove DropTarget
_SendMessage($hTree, $TVM_SETINSERTMARK, 0, $hItemHover) ;add InsertMark before item
$fWhere = -1
Case 1+$aRect[1]+Int(($aRect[3]-$aRect[1])/3) To $aRect[1]+Int(($aRect[3]-$aRect[1])*2/3)
_SendMessage($hTree, $TVM_SETINSERTMARK, 0, 0) ;remove InsertMark
_SendMessage($hTree, $TVM_SELECTITEM, $TVGN_DROPHILITE, $hItemHover) ;add DropTarget
$fWhere = 0
Case 1+$aRect[1]+Int(($aRect[3]-$aRect[1])*2/3) To $aRect[3]
_SendMessage($hTree, $TVM_SELECTITEM, $TVGN_DROPHILITE, 0) ;remove DropTarget
_SendMessage($hTree, $TVM_SETINSERTMARK, 1, $hItemHover) ;add InsertMark after item
$fWhere = 1
EndSwitch
EndIf
DrawDragImage($hTree, $hTreeDragImage)
EndSwitch
EndFunc
; TreeItemFromPoint()
; Returns handle of tree item under mouse:
Func TreeItemFromPoint($hWnd)
Local $tMPos = _WinAPI_GetMousePos(True, $hWnd)
Return _GUICtrlTreeView_HitTestItem($hWnd, DllStructGetData($tMPos, 1), DllStructGetData($tMPos, 2))
EndFunc
; TreeItemCopy()
; Copies tree item $hItemSource and all its children to an item $hItemTarget, depending on $fDirection
; $fDirection:
; -1 = before $hItemTarget
; 0 = inside $hItemTarget
; 1 = after $hItemTarget
Func TreeItemCopy($hWnd, $hItemSource, $hItemTarget, $fDirection)
;making sure parent can't be dropped onto one of its descendants:
$hTest = $hItemTarget
Do
$hTest = _GUICtrlTreeView_GetParentHandle($hWnd, $hTest)
If $hTest = $hItemSource Then Return 0
Until $hTest = 0
;create new item at determined position
$sText = _GUICtrlTreeView_GetText($hWnd, $hItemSource)
$hParent = _GUICtrlTreeView_GetParentHandle($hWnd, $hItemTarget)
Switch $fDirection
Case -1
$hPrev = _GUICtrlTreeView_GetPrevSibling($hWnd, $hItemTarget)
If $hPrev = 0 Then
$hNew = _GUICtrlTreeView_AddFirst($hWnd, $hItemTarget, $sText)
Else
$hNew = _GUICtrlTreeView_InsertItem($hWnd, $sText, $hParent, $hPrev)
EndIf
Case 0
$hNew = _GUICtrlTreeView_InsertItem($hWnd, $sText, $hItemTarget)
Case 1
$hNew = _GUICtrlTreeView_InsertItem($hWnd, $sText, $hParent, $hItemTarget)
Case Else
Return 0
EndSwitch
;save item state and checkbox image if there is such
_GUICtrlTreeView_SetState($hWnd, $hNew, _GUICtrlTreeView_GetState($hWnd, $hItemSource))
If _GUICtrlTreeView_GetStateImageList($hWnd) <> 0 Then
_GUICtrlTreeView_SetStateImageIndex($hWnd, $hNew, _GUICtrlTreeView_GetStateImageIndex($hWnd, $hItemSource))
EndIf
;save icon/selected image indexes
If _GUICtrlTreeView_GetNormalImageList($hWnd) <> 0 Then
_GUICtrlTreeView_SetImageIndex($hWnd, $hNew, _GUICtrlTreeView_GetImageIndex($hWnd, $hItemSource))
_GUICtrlTreeView_SetSelectedImageIndex($hWnd, $hNew, _GUICtrlTreeView_GetSelectedImageIndex($hWnd, $hItemSource))
EndIf
;recurse through descendants:
$iChildCount = _GUICtrlTreeView_GetChildCount($hWnd, $hItemSource)
If $iChildCount > 0 Then
For $i = 0 To $iChildCount-1
$hRecSource = _GUICtrlTreeView_GetItemByIndex($hWnd, $hItemSource, $i)
TreeItemCopy($hWnd, $hRecSource, $hNew, 0)
Next
EndIf
Return $hNew
EndFunc
Func On_WM_NOTIFY($hWnd, $Msg, $wParam, $lParam)
;wparam = cid, lparam = pnmh
If $wParam = $cTree Then
Local $tNMHDR = DllStructCreate("hwnd hTree;uint_ptr;int code", $lParam)
Local $code = DllStructGetData($tNMHDR, "code")
Local $hTree = HWnd(DllStructGetData($tNMHDR, "hTree"))
Switch $code
Case $TVN_BEGINDRAGA, $TVN_BEGINDRAGW
$bTreeDrag = True
$hDragItem = TreeItemFromPoint($hTree)
;~ _GUICtrlTreeView_SelectItem($hTree, $hDragItem)
_GUICtrlTreeView_SetSelected($hTree, _GUICtrlTreeView_GetSelection($hTree), False)
$hTreeDragImage = TreeCreateDragImage($hTree, $hDragItem)
DrawDragImage($hTree, $hTreeDragImage)
Case $TVN_BEGINLABELEDITA, $TVN_BEGINLABELEDITW
$bTreeEdit = True
;~ $hTreeEdit = _SendMessage($hTree, $TVM_GETEDITCONTROL, 0, 0)
Case $TVN_ENDLABELEDITA, $TVN_ENDLABELEDITW
$bTreeEdit = False
Return 1
Case $TVN_SELCHANGEDA, $TVN_SELCHANGEDW
;~ ;Local $hSel = _GUICtrlTreeView_GetSelection($hTree)
;~ Local $tNMTREEVIEW = DllStructCreate($tagNMTREEVIEW, $lParam)
;~ Local $hSel = DllStructGetData($tNMTREEVIEW, "NewhItem")
;~ Local $sTxt = "Currently selected: " & _GUICtrlTreeView_GetText($hTree, $hSel) & " (item handle " & $hSel & ")"
;~ GUICtrlSetData($label2, $sTxt)
Case Else
EndSwitch
;
EndIf
EndFunc
Func KeyPressed($iHexKey)
Local $aRet = DllCall('user32.dll', "int", "GetAsyncKeyState", "int", $iHexKey)
;~ If BitAND($aRet[0], 0x8000) Or BitAND($aRet[0], 1) Then Return 1
If BitAND($aRet[0], 1) Then Return 1
Return 0
EndFunc
Func TreeKeyboardFunc($cID)
Local $hWnd = GUICtrlGetHandle($cID)
If $bTreeDrag Then Return
If $bTreeEdit Then
If KeyPressed(0x0d) Then _SendMessage($hWnd, $TVM_ENDEDITLABELNOW, 0, 0) ;enter
If KeyPressed(0x1b) Then _SendMessage($hWnd, $TVM_ENDEDITLABELNOW, 1, 0) ;esc
EndIf
Local $aRet = DllCall('user32.dll', 'hwnd', 'GetFocus')
If $aRet[0] = $hWnd Then
If KeyPressed(0x2d) Then _GUICtrlTreeView_Add($hWnd, _GUICtrlTreeView_GetSelection($hWnd), "New Item") ;insert
If KeyPressed(0x2e) Then _GUICtrlTreeView_Delete($hWnd, _GUICtrlTreeView_GetSelection($hWnd)) ;delete
If KeyPressed(0x0d) Then _SendMessage($hWnd, $TVM_EDITLABELA, 0, _GUICtrlTreeView_GetSelection($hWnd)) ;enter
EndIf
EndFunc
Func TreeCreateDragImage($hWnd, $hItem)
;if treeview has imagelist, use image from it
If _GUICtrlTreeView_GetNormalImageList($hWnd) <> 0 Then Return _GUICtrlTreeView_CreateDragImage($hWnd, $hItem)
;if not, create a bitmap of dragitem's text rectangle and put it into imagelist.
Local $aItemRect = __GUICtrlTreeView_DisplayRect($hWnd, $hItem, True)
Local $iImgW = $aItemRect[2]-$aItemRect[0]
Local $iImgH = $aItemRect[3]-$aItemRect[1]
Local $hTreeDC = _WinAPI_GetDC($hWnd)
Local $hMemDC = _WinAPI_CreateCompatibleDC($hTreeDC)
Local $hMemBmp = _WinAPI_CreateCompatibleBitmap($hTreeDC, $iImgW, $iImgH)
Local $hMemBmpOld = _WinAPI_SelectObject($hMemDC, $hMemBmp)
_WinAPI_BitBlt($hMemDC, 0, 0, $iImgW, $iImgH, $hTreeDC, $aItemRect[0], $aItemRect[1], $SRCCOPY)
_WinAPI_SelectObject($hMemDC, $hMemBmpOld)
_WinAPI_ReleaseDC($hWnd, $hTreeDC)
_WinAPI_DeleteDC($hMemDC)
Local $hImgList = _GUIImageList_Create($iImgW, $iImgH, 6)
_GUIImageList_Add($hImgList, $hMemBmp)
_WinAPI_DeleteObject($hMemBmp)
Return $hImgList
EndFunc
; Draw drag image
; by Gary Frost (gafrost) (?)
Func DrawDragImage(ByRef $hControl, ByRef $aDrag)
Local $tPoint, $hDC
$hDC = _WinAPI_GetWindowDC($hControl)
$tPoint = _WinAPI_GetMousePos(True, $hControl)
_WinAPI_InvalidateRect($hControl)
_GUIImageList_Draw($aDrag, 0, $hDC, DllStructGetData($tPoint, "X")-10, DllStructGetData($tPoint, "Y")-8)
_WinAPI_ReleaseDC($hControl, $hDC)
EndFunc ;==>DrawDragImage
Func __GUICtrlTreeView_DisplayRect($hWnd, $hItem, $bTextOnly = False)
Local $tRECT = DllStructCreate("int_ptr Left;int_ptr Top;int_ptr Right;int_ptr Bottom")
DllStructSetData($tRECT, "Left", $hItem)
_SendMessage($hWnd, $TVM_GETITEMRECT, $bTextOnly, $tRECT, 0, "wparam", "struct*")
Local $aRect[4]
$aRect[0] = DllStructGetData($tRECT, "Left")
$aRect[1] = DllStructGetData($tRECT, "Top")
$aRect[2] = DllStructGetData($tRECT, "Right")
$aRect[3] = DllStructGetData($tRECT, "Bottom")
If @AutoItX64 Then
Local $aRect_ = $aRect
$aRect[0] = _WinAPI_LoDWord($aRect_[0])
$aRect[1] = _WinAPI_HiDWord($aRect_[0])
$aRect[2] = _WinAPI_LoDWord($aRect_[1])
$aRect[3] = _WinAPI_HiDWord($aRect_[1])
EndIf
Return $aRect
EndFunc ;==>__GUICtrlTreeView_DisplayRect