09-08-2008, 02:09 PM
This is for tree view control. For listbox would be difficult because it does not have some messages such as TVN_BEGINDRAG, TVM_HITTEST etc.
Drag, TvMoveItem and TvGetItemText can be used anywhere, not only with this dialog.
drag tree view item.qml (Size: 5.21 KB / Downloads: 481)
Function dlg_drag_test
Function drag_test_proc
Function Drag
Function TvMoveItem
Function TvGetItemText
Drag, TvMoveItem and TvGetItemText can be used anywhere, not only with this dialog.

Function dlg_drag_test
\Dialog_Editor
function# hDlg message wParam lParam
if(hDlg) goto messages
if(!ShowDialog("dlg_drag_test" &dlg_drag_test)) ret
;note: this dialog is Unicode and therefore received W versions of messages. But the function can work with ANSI dialogs too.
;BEGIN DIALOG
;1 "" 0x90C80A44 0x100 0 0 223 135 "Dialog"
;1 Button 0x54030001 0x4 120 116 48 14 "OK"
;2 Button 0x54030000 0x4 170 116 48 14 "Cancel"
;3 SysTreeView32 0x54030000 0x0 0 0 116 110 ""
;END DIALOG
;DIALOG EDITOR: "" 0x2030002 "" "" ""
ret
;messages
sel message
,case WM_INITDIALOG
,int i htv=id(3 hDlg)
,str s ss="one[]two[]three[]βββ"
,foreach(s ss) i+1; TvAdd htv 0 s i
,
,case WM_DESTROY
,case WM_COMMAND goto messages2
,case WM_NOTIFY goto messages3
ret
;messages2
sel wParam
,case IDOK
,;gett text of all
,htv=id(3 hDlg)
,int hi=SendMessage(htv TVM_GETNEXTITEM TVGN_ROOT 0)
,rep
,,if(!hi) break
,,TvGetItemText htv hi s
,,ss.addline(s)
,,hi=SendMessage(htv TVM_GETNEXTITEM TVGN_NEXT hi)
,out ss
,
,case IDCANCEL
ret 1
;messages3
NMHDR* nh=+lParam
sel nh.idFrom
,case 3
,NMTREEVIEW* nt=+nh
,if(nh.code=TVN_SELCHANGEDW or nh.code=TVN_SELCHANGED)
,,i=nt.itemNew.lParam ;;was set by TvAdd
,,out i
,else if(nh.code=TVN_BEGINDRAGW or nh.code=TVN_BEGINDRAG)
,,type TVDRAG49 htv hidrag
,,TVDRAG49 td.htv=nh.hwndFrom; td.hidrag=nt.itemNew.hItem
,,Drag(hDlg &drag_test_proc &td)
,,SendMessage td.htv TVM_SELECTITEM TVGN_DROPHILITE 0
Function drag_test_proc
;/dlg_drag_test
function button TVDRAG49&td
TVHITTESTINFO ht
xm ht.pt; ScreenToClient(td.htv &ht.pt)
int hidrop=SendMessage(td.htv TVM_HITTEST 0 &ht)
int candrop=hidrop or ht.flags&TVHT_NOWHERE
if(button)
,SendMessage td.htv TVM_SELECTITEM TVGN_DROPHILITE 0
,if(!candrop) ret
,ret TvMoveItem(td.htv td.hidrag hidrop GetMod=2)
else
,SendMessage td.htv TVM_SELECTITEM TVGN_DROPHILITE hidrop
,if(!candrop) ret 3
,ret iif(GetMod=2 2 1)
;instead of TVM_SELECTITEM could use TVM_SETINSERTMARK, but then need more calculations
Function Drag
;/
function hwnd proc param
;A simple drag function. Sets cursor, etc.
;Returns when dragging is finished.
;On drop, returns proc's return value. If cancelled, returns 0.
;hwnd - drag source window. It should be the window where drad/drop operation started. Can be child.
;proc:
,;Address of a function that will be called while dragging (many times) and when dropped.
,;It for example can reorder items in a list box.
,;It also sets cursor.
,;The function must be:
,
,;function button param
,
,;button - mouse button: 0 while dragging, 1 left up, 2 right up.
,;param - param passed to Drag().
,
,;On move, it must return cursor handle, or 0 if sets cursor itself, or 1-3 to use standard cursors: 1 move, 2 copy, 3 no operation.
,;On button up, it can return any value. Drag() returns it.
MSG m; int r; int mb
int hm=GetModuleHandle("ole32")
int cMove(LoadCursor(hm +2)) cCopy(LoadCursor(hm +3)) cNo(LoadCursor(hm +1))
SetCapture(hwnd);
rep
,if(GetCapture()!=hwnd || GetMessage(&m, 0, 0, 0)<=0) break
,if(m.message==WM_KEYDOWN && m.wParam==VK_ESCAPE) ReleaseCapture();
,mb=0;
,sel(m.message)
,,case WM_MOUSEMOVE:
,,r=call(proc 0 param)
,,if(r)
,,,if(r>=1 and r<=3) int* pc=&cMove; r=pc[r-1]
,,,SetCursor(r);
,,continue;
,,case WM_LBUTTONUP: mb=MK_LBUTTON
,,case WM_RBUTTONUP: mb=MK_RBUTTON
,
,if(mb)
,,ReleaseCapture();
,,ret call(proc mb param);
,DispatchMessage(&m);
Function TvMoveItem
;/
function# htv hi hito copy
;Moves or copies treeview control item hi to the place of hito.
;If successful, returns new item handle (on move too, because the item must be deleted and new item created).
;Does not copy Vista-specific properties. If you use them, set them again.
;If hito is 0, moves/copies to the end.
if(hi=hito) ret hi
;get all properties of hi, except Vista properties
TVINSERTSTRUCTW is
TVITEMW& t=is.item
t.hItem=hi; t.mask=TVIF_IMAGE|TVIF_SELECTEDIMAGE|TVIF_PARAM|TVIF_STATE|TVIF_TEXT
t.stateMask=TVIS_BOLD|TVIS_CUT|TVIS_DROPHILITED|TVIS_EXPANDED|TVIS_EXPANDEDONCE|TVIS_EXPANDPARTIAL|TVIS_SELECTED|TVIS_OVERLAYMASK|TVIS_STATEIMAGEMASK|TVIS_USERMASK
BSTR b; t.pszText=b.alloc(300); t.cchTextMax=300
if(!SendMessage(htv TVM_GETITEMW 0 &t)) ret
int selected=t.state&TVIS_SELECTED
;insert new item with these properties
if(copy) t.mask&=~TVIF_STATE
else
,int hparent(GetParent(htv)) wp(SubclassWindow(hparent &DefWindowProcW)) ;;subclass parent window to prevent receiving select and delete messages
if(hito) is.hInsertAfter=SendMessage(htv TVM_GETNEXTITEM TVGN_PREVIOUS hito); if(!is.hInsertAfter) is.hInsertAfter=TVI_FIRST
else is.hInsertAfter=TVI_LAST
int hinew=SendMessage(htv TVM_INSERTITEMW 0 &is)
;delete hi
if(hinew and !copy)
,if(selected) SendMessage htv TVM_SELECTITEM TVGN_CARET hinew
,SendMessage(htv TVM_DELETEITEM 0 hi)
;unsubclass
if(wp) SubclassWindow(hparent wp)
ret hinew
Function TvGetItemText