;Title: TreeViewX ; TreeViewX extends standard TreeView control to support moving, deleting & inserting. ;---------------------------------------------------------------------------------------- ; Function: TVX ; Initialisation function. Mandatory to call before you show the TreeView. ; ; Parameters: ; pTree - AHK name of the TreeView control ; pSub - Subroutine for TreeViewX, the same rules as in g. ; pOptions - String containing space delimited options for setting up TreeViewX ; pUserData - Base name of the array holding user data. ; This array is indexed using tree view item handles. ; ; Options: ; HasRoot - TreeViewX has root item - the one containing all other items. ; Root item can't be moved, edited or delited, and items can not ; be moved or created outside of it. This option need to be set ; after root is already added to the menu, as TreeViewX need to ; know the root menu handle. ; ; CollapseOnMove - When moving item out of of its container, this option makes container collapse ; EditOnInsert - Automaticaly enters edit mode upon insertion of new item ; ; Example: ;> ;> TVX("MyTree", "Handler", "HasRoot CollapseOnMove") ;> TVX( pTree, pSub, pOptions="", pUserData="" ) { global if InStr(pOptions, "HasRoot") { TVX_HasRoot := 1 TVX_root := TV_GetNext() } if InStr(pOptions, "CollapseOnMove") TVX_CollapseOnMove := 1 if InStr(pOptions, "EditOnInsert") TVX_EditOnInsert := 1 TVX_userData := pUserData TVX_sub := pSub GuiControl, +AltSubmit -ReadOnly +gTVX_OnEvent, %pTree% } ;---------------------------------------------------------------------------------------- ; Function: Walk ; Walk the menu and rise events ; ; Parameters: ; root - menu to iterate, can be simple item also ; label - event handler ; event_type - event argument 1 - Event type ; event_param - event argument 2 - Item upon which event is rised ; ; ; Type Param ; ; + - Iteration start, root handle ; M - Menu item, menu handle ; I - Item, item handle ; E - End of menu menu handle (pseudo item) ; - - Iteration end root handle (pseudo item) ; TVX_Walk(root, label, ByRef event_type, ByRef event_param){ local n, t, p, c, pref, bSetEnd, lastParent, rootsParent, tmp ; start event for menus event_type := "+" event_param := root GoSub %label% if !TV_GetChild(root) return ; this will be exit condition. If we come to roots parent, stop walking. rootsParent := TV_GetParent(root) lastParent := root c := root loop { c := TV_GetNext(c, "Full") TV_GetText(tmp, c) ; Check if this item is submenu. If so, set the lastParent if ( TV_GetChild(c) ){ lastParent := c event_type := "M" } else event_type := "I" ; not a submenu, it is normal item event_param := c GoSub %label% ; Check if c is the last item in the current submenu ; Do so by taking the next item and checking its parent. ; If the parent is different then "lastParent" current item is ; at the end of the its submenu. n := TV_GetNext(c, "FULL") if (n) { p := TV_GetParent(n) if ( p != lastParent){ t := lastParent lastParent := p } else continue ; It is the last child Loop { ; rise "E" (end of menu) event event_type := "E" event_param := t GoSub %label% t := TV_GetParent(t) if (t = rootsParent) { ; rise "-" (end of walk) event event_type := "-" event_param := t GoSub %label% return } if (p = t) break } } else Loop { ;this is the end of the complite menu, so close all open submenus, if any if (lastParent = root) { event_type := "-" event_param := root GoSub %label% return } event_type := "E" event_param := lastParent GoSub %label% lastParent := TV_GetParent(lastParent) } } } ;---------------------------------------------------------------------------------------------- ; Function: Move ; Moves tree view item up or down ; ; Parameters: ; item - Handle of the item to move ; direction - "u" or "d" (Up & Down) ; ; Returns: ; Handle of the item ; ; Remarks: ; Item to be moved is copied to the new place then source item is deleted. This ; creates new handle for the moved item. New handle will be returned by the function. ; TVX_Move(item, direction){ local newc, newp, t, p, n p := TV_GetPrev(item) n := TV_GetNext(item) if (TVX_HasRoot) { if TV_GetNext()=item return if (direction="u") { if (p = 0 && TV_GetParent(item)=TV_GetNext()) ;don't let item go above root { TV_Modify(item) TVX_sel:=item return } } } ; Do so by coping an item bellow calculated item and deleting the old one. ; Return handle of new item ; newc - calculated child after which "item" should be created. ; newp - ... and its parent ; if moving down if (direction = "d") { ; handle end of submenu if !n { newc := TV_GetParent(item) ; check the end of the entire list if (TVX_HasRoot && newc = TVX_root) return if TVX_CollapseOnMove TV_Modify(newc, "-Expand") newp := TV_GetParent(newc) } ; somewhere in the middle else { ; if submenu, go into it t := TV_Get(n, "E") if (t = n) { newp := n newc := "First" } ; not a submenu else { newc := n newp := TV_GetParent(n) } } } ; if moving up if (direction = "u") { ;going up - handle start of the submenu if !p { t := TV_GetParent(item) if TVX_CollapseOnMove TV_Modify(t, "-Expand") newc := TV_GetPrev(t) ; handle start of the menu again if !newc { newp := TV_GetParent(t) newc := "First" } else newp := TV_GetParent(newc) } ; somewhere in the middle else { ; if submenu is expanded, go into it t := TV_Get(p, "E") if (t = p) { newc := "First" newp := t } else { t := TV_GetPrev(p) ;check the top of the list if !t { newc := "First" newp := TV_GetParent(p) } else { newc := t newp := TV_GetParent(newc) } } } } newc := TVX_CopyItem(newc, newp, item) TV_Delete(item) return newc } ;--------------------------------------------------------------------------------------------- ; TVX_Walk event handler wrapped in the function ; ; Function that copies menu item to the destination item. ; Handle of destination item is specified in the global variable TVX_copyDest. ; TVX_CopyProc(iType, item) { local c, txt static lastParent TV_GetText(txt, item) if iType in + { lastParent := TVX_copyDest TV_Modify(TVX_copyDest, "", txt) if TVX_userData { %TVX_userData%%TVX_copyDest% := %TVX_userData%%item% %TVX_userData%%item% := "" } } if iType in I,M { c := TV_Add(txt, lastParent) if iType = M lastParent := c if TVX_userData { %TVX_userData%%c% := %TVX_userData%%item% %TVX_userData%%item% := "" } } if iType = E lastParent := TV_GetParent(lastParent) } ;---------------------------------------------- _TVX_CopyProc: TVX_CopyProc(TVX_itemType, TVX_param) return ;----------------------------------------------------------------------------------------------- ; Create new item after the child "destc" with parent "destp" and copy the "source" item into it ; TVX_CopyItem(destc, destp, source){ global ;create the holder and call the copy function TVX_copyDest := TV_Add("", destp , destc ) TVX_Walk(source, "_TVX_CopyProc", TVX_itemType, TVX_param) return TVX_copyDest } ;---------------------------------------------------------------------------------------------- ; Used to control moving ; TVX_OnItemSelect(pItemId){ global if (TVX_bSelfSelect) { TVX_bSelfSelect := false return true } TVX_prevSel := TVX_sel TVX_sel := pItemId if GetKeyState("Shift") && (TVX_lastKey=38 || TVX_lastKey=40) if (pItemId != TVX_root) { TVX_sel := TVX_Move( TVX_prevSel, TVX_lastKey=40 ? "d" : "u") TVX_prevSel := pItemId TVX_bSelfSelect := true TV_Modify(TVX_sel, "Select Bold") return true } return false } ;---------------------------------------------------------------------------------------------- TVX_OnKeyPress(pKey){ local tp, sel TVX_lastKey := pKey if (TVX_bSelfPress) { TVX_bSelfPress := false return true } ;delete if pKey = 46 { ; use GetSelection instead Editor_sel since if key is pressed and hold ; TVX_OnSelect handler may not be called before delete to set the TVX_sel sel := TV_GetSelection() if (TVX_HasRoot && sel = TVX_root) return false ; is shift delete is pressed return - some problems with this combination if (GetKeyState("Shift")) return false TV_Delete(sel) return true } ;insert if pKey = 45 { tp := TV_GetParent(TVX_sel) if (TVX_sel = TVX_root) tp := TVX_root tp := TV_Add("__ new item __", tp, "Bold " . TVX_sel) if GetKeyState("Shift") { TV_Add("__ new item __", tp, "Bold First ") TV_Modify(tp,"Expand", "__ new group __") } if (TVX_EditOnInsert) { TVX_bSelfPress := TVX_bSelfSelect := true TV_Modify(tp, "Select") Send, {F2} } return true } return false } ;---------------------------------------------------------------------------------------------- ; g soubroutine for Tree View ; TVX_OnEvent: if (A_GuiEvent="S") if TVX_OnItemSelect(A_EventInfo) return if (A_GuiEvent="K") if TVX_OnKeyPress(A_EventInfo) return ;if not the Xtended property send event to the caller gosub %TVX_sub% return