Jump to content

Need help with explorer-style drag & drop


Recommended Posts

Hi everyone.

I'm trying to create a program to store links. To keep the stored links organized I would like to have the option to create groups and drag links to them just like you can drag files to folders in the windows explorer.

Posted Image

My GUI:

Posted Image

Unfortunately I can't find a way for autoit to recognize the listview entry the mouse is hovering over when the button is released.

-@Drag_id etc only recognize the listview control, not the individual entries.

-Hottracking does recognize them but does not work during a drag&drop operation

-Calculating the entry from the mouse x/y coordinates is rather error-prone at ca 13 pixels height per group and gets worse if the program should be usable on different resolutions.

I found the following code that seems to be close to what I'm lookin for but lack the C++ knowledge to costumize the code to my needs.

#include <GuiConstants.au3>

;by wiredbits 
;Treeview HitTest
;mostly beginer stuff, I need to go and read all of Autoit functions now:P
;using beta version 1.99
;few examples (simple) of  Treeview Hittest
;right mouse button (secondary) selection of Treeview item
;drag and drop child items between parents
;drag file onto treeview and if a hit add to treeview
;context menu cut, copy, paste, and delete a treeview item
;**********************************************************************************************
Const $TVGN_NEXT = 0x1
CONST $TVGN_PREVIOUS=   2
Const $TVGN_CHILD = 0x4
CONST $TVGN_FIRSTVISIBLE =    0x0005
Const $TVGN_CARET = 0x9
Const $TVGN_ROOT=   0
Const $TV_FIRST = 0x1100
Const $TVM_DELETEITEM = ($TV_FIRST + 1)
CONST $TVM_GETNEXTITEM = ($TV_FIRST + 10)
Const $TVM_SORTCHILDREN = ($TV_FIRST + 19)
CONST $TVM_SELECTITEM = ($TV_FIRST + 11)
CONST $TVM_SETINSERTMARK=      ($TV_FIRST + 26)
CONST $TVM_HITTEST= ($TV_FIRST+17)
CONST $TVM_CREATEDRAGIMAGE= ($TV_FIRST+18);i really need to read up on this, might be better than draging a control
CONST $TVGN_DROPHILITE= 8
CONST $TVM_GETBKCOLOR =($TV_FIRST+31)
CONST $TVM_GETTEXTCOLOR= ($TV_FIRST+32)
Const $TVM_SETITEM= ($TV_FIRST+13)

CONST $TVGN_PARENT= 3
;*********************************************************************************************
 CONST $TVHT_NOWHERE=1
 CONST $TVHT_ONITEMICON=2
 CONST $TVHT_ONITEMLABEL=4
 CONST $TVHT_ONITEMINDENT=8
 CONST $TVHT_ONITEMBUTTON=16
 CONST $TVHT_ONITEMRIGHT=32
 CONST $TVHT_ONITEMSTATEICON=64
 CONST $TVHT_ABOVE= 256
 CONST $TVHT_BELOW=512
 CONST $TVHT_TORIGHT=   1024
 CONST $TVHT_TOLEFT=    2048
 CONST $TEST=BitOR($TVHT_ONITEMICON,$TVHT_ONITEMLABEL,$TVHT_ONITEMSTATEICON,$TVHT_ONITEMINDENT,$TVHT_ONITEMBUTTON,$TVHT_ONITEMRIGHT)
;**********************************************************************************************
 CONST $WM_VSCROLL =277
 CONST $WM_HSCROLL= 276
 CONST $SBM_GETPOS= 225
 CONST $SB_LINEUP=0
 CONST $SB_LINEDOWN=1
 CONST $SB_LINELEFT=    0
 CONST $SB_LINERIGHT=   1
 CONST $SB_LEFT=6 
 CONST $SB_RIGHT=   7
;***************************************************************************************************

***
CONST $NUM_PARS=6
CONST $NUM_KIDS=6

CONST $PAR_NUMPARS= 0
CONST $PAR_CTRLID=  1
CONST $PAR_NAME =   2

CONST $KID_NUMKIDS= 0
CONST $KID_PARID=   1
CONST $KID_PARINDEX=2
CONST $KID_CTRLID=  3
CONST $KID_NAME=    4
;***************************************************************************************************

********
CONST $DR_MONITORDRAG=  1
CONST $DR_ISDRAG=       2
CONST $DR_CHECKSCROLL=  4
CONST $ED_CUT=1
CONST $ED_COPY=2
;***************************************************************************************************

********
Dim $parents[$NUM_PARS][3]
Dim $kids[$NUM_KIDS*$NUM_PARS][5]
$winHandle = GuiCreate("Treeview Hitest Examples", 348, 450, 200, 5, $WS_OVERLAPPEDWINDOW,$WS_EX_ACCEPTFILES) 
GUISetFont(10,400)
$ClassTreeview = GUICtrlCreateTreeView(24, 40, 300, 385)
GUICtrlSetState(-1,$GUI_DROPACCEPTED); to allow drag and dropping
;i remember when i first saw the dummy control...thought i would never use them
;then i saw some examples and thought..dummy...LOL
$killdrag= GUICtrlCreateDummy()
$kidDummy= GUICtrlCreateDummy()
$parDummy= GUICtrlCreateDummy()
$parmenu = GUICtrlCreateContextMenu ($parDummy)
$contexPDelete=GUICtrlCreateMenuitem ("Delete", $parmenu)
$contexPPaste=GUICtrlCreateMenuitem ("Paste Item", $parmenu)

$kidMenu = GUICtrlCreateContextMenu  ($kidDummy)
$contexCut=GUICtrlCreateMenuitem ("Cut", $kidMenu)
$contexCopy=GUICtrlCreateMenuitem ("Copy", $kidMenu)
$contexPaste=GUICtrlCreateMenuitem ("Paste", $kidMenu)
GUICtrlSetState(-1,$GUI_DISABLE)
$contextDeleteItem=GUICtrlCreateMenuitem ("Delete", $kidMenu)
GuiSetState(@SW_SHOW ,$winhandle)

;should make the following local
$savex=0
$savey=0
$droptime=0
$dropflag=0
$hfromparent=-1
$fromkidID=-1
$editflag=0
SetUpTreeview()
 Main()
 Exit
 Func Main()
 Local $admsg,$msg,$hitem,$x
While 1
    $admsg = GuiGetMsg(1)
    $msg=$admsg[0]
  Select
    Case $msg=$killdrag
        $droptime=0
        $dropflag=0
;secondary mouse selection
    Case $msg=$GUI_EVENT_SECONDARYDOWN 
            $savex=$admsg[3]
            $savey=$admsg[4];save mouse positions
;force user to click on a treeview item label to get context menu...could give an optional menu if no hit
        $hitem=TV_Hittest($ClassTreeview,$savex,$savey,$TVHT_ONITEMRIGHT,0)
        If $hitem Then
            $x=GUICtrlSendMsg($ClassTreeView,$TVM_GETNEXTITEM,$TVGN_CARET,0);get current
            If $x<>$hitem Then GUICtrlSendMsg($ClassTreeView,$TVM_SELECTITEM,$TVGN_CARET,$hitem);select hit item if not already
            TV_DoContextMenu($ClassTreeView,$hitem)
        EndIf
    Case $msg=$GUI_EVENT_MOUSEMOVE
        If BitAND($dropflag,$DR_MONITORDRAG) Then
            If TV_CheckIfDrag($ClassTreeview) Then
                $hitem=GUICtrlSendMsg($ClassTreeView,$TVM_GETNEXTITEM,$TVGN_CARET,0);on return focus is always on child...in this example
                $hitem=GUICtrlSendMsg($ClassTreeView,$TVM_GETNEXTITEM,$TVGN_PARENT,$hitem)
                GUICtrlSendMsg($ClassTreeView,$TVM_SORTCHILDREN ,0,$hitem);wParam (3rd parameter) a bool to recurse or not
                GUICtrlSendMsg($ClassTreeView,$WM_HSCROLL,$SB_LEFT ,0);force treeview to left
            EndIf
        EndIf
     Case $msg=$contexCut
        TV_Cut($ClassTreeView)
     Case $msg=$contexCopy
        TV_Copy($ClassTreeView)
     Case $msg=$contexPaste Or $msg=$contexPPaste
        TV_Paste($ClassTreeView,$savex,$savey)
     Case $msg=$contextDeleteItem Or $msg=$contexPDelete
        TV_DeleteItem($ClassTreeview)
    case $msg=$GUI_EVENT_DROPPED
        TV_DropFIle($ClassTreeview)
    Case $msg=$GUI_EVENT_CLOSE 
        ExitLoop
    Case $msg>$parents[0][$PAR_CTRLID];could check if a child ID then set flag 
        $dropflag=BitOR($dropflag,$DR_MONITORDRAG)
  EndSelect
WEnd
EndFunc

Func TV_DoContextMenu($Treeview,$hitem)
 Local $hpar
    $hpar=GUICtrlSendMsg($TreeView,$TVM_GETNEXTITEM,$TVGN_PARENT,$hitem)
    If $hitem Then 
        If $fromkidID=-1  Or $hpar=$hfromparent Or $hitem=$hfromparent Then
            GUICtrlSetState($contexPaste,$GUI_DISABLE)
            GUICtrlSetState($contexPPaste,$GUI_DISABLE)
        Else
            GUICtrlSetState($contexPaste,$GUI_ENABLE)
            GUICtrlSetState($contexPPaste,$GUI_ENABLE)
        EndIf
        If $hpar Then 
             ShowMenu($winHandle,$kidMenu,$Treeview)  
        Else 
             ShowMenu($winHandle,$parMenu,$Treeview)  
        EndIf   
    EndIf
EndFunc

Func TV_CheckIfDrag($TreeView)
 Local $id,$hitem,$droplabel=0
 CONST $DRAGBUTTON=2;primary button
 CONST $CTRLID=4
  $mouse = GUIGetCursorInfo($winHandle)
   If NOT  @error then 
    If $mouse[$DRAGBUTTON] And $mouse[$CTRLID] = $TreeView  Then
        if $droptime=0 Then
            $droptime=TimerInit()
        ElseIf TimerDiff($droptime)>70 Then
        $hitem=GUICtrlSendMsg($TreeView,$TVM_GETNEXTITEM,$TVGN_CARET,0)
        $hitem=GUICtrlSendMsg($TreeView,$TVM_GETNEXTITEM,$TVGN_PARENT,$hitem);returns 0 if hitem is a parent
            If $hitem Then;only move a kid
                $ctrlmsg=GUICtrlRead($TreeView,1)
                $droplabel= GuiCtrlCreateLabel($ctrlmsg[0],$mouse[0],$mouse[1],200,16,-1) 
;               $droplabel= GUICtrlCreateIcon("shell32.dll",175,$mouse[0],$mouse[1])
                $id=TV_DoDrag($TreeView,$droplabel)
                GUICtrlDelete($droplabel)
                GUICtrlSendToDummy ($killdrag);msg comes after any select item from drag
                Return $id
            EndIf
        EndIf
    EndIf
  EndIf
EndFunc

;drag a control around treeview until primary mouse button is released, if child was draged into
;different parrent group then create new child and delete old child.
;orginally in a msg loop....trying it this way for now
;On Entry: Treeview control ID, control ID to drag 
;On Exit: new child control ID else 0
Func TV_DoDrag($TreeView,$dragctrl)
 Local $msg,$i,$x,$curkid,$hscroll,$vscroll,$hparent,$hitem,$hpar
 Local $left,$top,$width,$height,$dtime,$isdrag
 CONST $DRAGFINISHED=2;$GUI_EVENT_PRIMARYUP;could use varables instead then use either button to drag
 $hitem=GUICtrlSendMsg($TreeView,$TVM_GETNEXTITEM,$TVGN_CARET,0)
 $hparent=GUICtrlSendMsg($TreeView,$TVM_GETNEXTITEM,$TVGN_PARENT,$hitem);returns 0 if hitem is a parent
 MsgBox(0, "", $hitem)
 If NOT $hparent Then $hparent=$hitem
 $hitem=0
 $x=ControlGetPos("","",$TreeView)
 If NOT @error Then
  $left=$x[0]
  $top=$x[1]
  $width=$x[2]
  $height=$x[3]
  $curkid=GUICtrlRead($TreeView,1)
  GUISetState(@SW_LOCK,$winhandle)
  $isdrag=1
    Do
      $amsg=GUIGetMsg() ;cuts down on cpu cycles
      $msg = GUIGetCursorInfo($winHandle)
     If NOT @error Then
      If $dtime=0 And $msg[$DRAGFINISHED]=0 Then $dtime=TimerInit();button release wait time
        $vscroll=-1
        $hscroll=-1
        Select
        Case $msg[1]<$top   
            $msg[1]=$top
            $vscroll=$SB_LINEUP 
        Case $msg[1]>$top+$height
            $msg[1]=$top+$height
            $vscroll=$SB_LINEDOWN 
        EndSelect
        Select
        Case $msg[0]<$left;x
            $hscroll=$SB_LINELEFT
            $msg[0]=$left
        Case $msg[0]>$left+$width
            $hscroll=$SB_LINERIGHT 
            $msg[0]=$left+$width
        EndSelect
        GUISetState(@SW_UNLOCK,$winhandle)
        If $hscroll<>-1 or $vscroll<>-1 Then
            GUICtrlSetState($dragctrl,$GUI_HIDE)
            If $hscroll<>-1 Then  GUICtrlSendMsg($TreeView,$WM_HSCROLL,$hscroll,0)
            If $vscroll<>-1 Then GUICtrlSendMsg($TreeView,$WM_VSCROLL,$vscroll,0) 
            GUICtrlSetState($dragctrl,$GUI_SHOW)
        EndIf
         GuiCtrlSetPos( $dragctrl, $msg[0],  $msg[1])
         GUISetState(@SW_LOCK,$winhandle);windows updates scroll values during this unlock
         $hitem=TV_Hittest($Treeview, $msg[0],  $msg[1],$TVHT_ONITEMRIGHT,0)
         If $hitem Then
            GUICtrlSendMsg($Treeview,$TVM_SELECTITEM ,$TVGN_DROPHILITE,$hitem)
         Else
            GUICtrlSendMsg($Treeview,$TVM_SELECTITEM ,$TVGN_DROPHILITE,0)
        EndIf
        $isdrag= $msg[$DRAGFINISHED]
         If NOT $isdrag  And $droptime=0 then $droptime=TimerInit()
     EndIf
    Until NOT $isdrag And TimerDiff($dtime)>30
    GUISetState(@SW_UNLOCK,$winhandle)
    GUICtrlSendMsg($Treeview,$TVM_SELECTITEM ,$TVGN_DROPHILITE,0)
    GUICtrlSetState($dragctrl,$GUI_HIDE) 
    $hitem=TV_Hittest($Treeview, $msg[0],  $msg[1],$TVHT_ONITEMRIGHT,0)
    If  $hitem=0 Then Return 0; not a hit
;the folowing does not support sub items...accurately, might play with this later
    $hpar=GUICtrlSendMsg($TreeView,$TVM_GETNEXTITEM,$TVGN_PARENT,$hitem)
    If $hpar=0 Then $hpar=$hitem
    If $hpar=$hparent Then Return 0;dropped on current parent group
    If ($curkid[1])=$fromkidID Then $fromkidID=-1;kill paste
    GUICtrlDelete($curkid[1])
    If $hpar Then GUICtrlSendMsg($TreeView,$TVM_SELECTITEM,$TVGN_CARET,$hpar);focus so can get control ID
    $hpar=GUICtrlRead($TreeView);get control id
;   $hpar=GetparentID($hpar);get parent ID without useing above two lines of code 
;housekeeping: if you are using arrays to track kids and parents adjust here
;as in...delete/add or update arrays
    $hitem=GUICtrlCreateTreeViewItem($curkid[0],$hpar)
    If $hitem Then  GUICtrlSetState($hitem,$GUI_FOCUS)
 EndIf
 Return $hitem;return new child's control id if any
EndFunc

;On Entry: Treeview control ID
;On Exit: new control ID else 0
Func TV_DropFIle($Treeview)
 Local $mouse,$hitem,$hpar,$id
   $tmp=@GUI_DRAGFILE
;just playing here, do not want path in treeview
   $tmp=Stringmid($tmp, StringInStr($tmp, '\',0, -1)+1,-1)
   If $tmp="" Then  $tmp=@GUI_DRAGFILE;drive was dropped
;
  $id=0
 GUISetState(@SW_RESTORE ,$winhandle);make sure GUI has focus or will get an error
  $mouse = GUIGetCursorInfo($winHandle)
        If NOT  @error Then
            $hitem=TV_Hittest($Treeview,$mouse[0],$mouse[1],$TVHT_ONITEMRIGHT,0)
            If $hitem Then
                $hpar=GUICtrlSendMsg($TreeView,$TVM_GETNEXTITEM,$TVGN_PARENT,$hitem)
                If $hpar=0 Then $hpar=$hitem 
                GUICtrlSendMsg($TreeView,$TVM_SELECTITEM,$TVGN_CARET,$hpar)
                $id=GUICtrlRead($Treeview) 
                $id=GUICtrlCreateTreeViewItem($tmp,$id) 
                If $id Then
                    GUICtrlSetState($id,$GUI_FOCUS);show new kid and expand parent if not
                    GUICtrlSendMsg($TreeView,$TVM_SORTCHILDREN ,0,$hpar);wParam (3rd parameter) a bool to recurse or not
                    GUICtrlSendMsg($TreeView,$WM_HSCROLL,$SB_LEFT ,0) 
                EndIf
            EndIf
        EndIf
  Return $id
EndFunc

Func TV_Cut($Treeview)
    TV_SetEdit($Treeview,$ED_CUT)
EndFunc

Func TV_Copy($Treeview)
    TV_SetEdit($Treeview,$ED_COPY)
EndFunc

Func TV_SetEdit($Treeview,$edflag)
 Local $hitem,$hpar
    $fromkidID=-1
    $editflag=0
    $hitem=GUICtrlSendMsg($TreeView,$TVM_GETNEXTITEM,$TVGN_CARET,0)
    $hpar=GUICtrlSendMsg($TreeView,$TVM_GETNEXTITEM,$TVGN_PARENT,$hitem);returns 0 if hitem is a parent
    If $hpar Then; if a parent then hitem is a child...no cut or copying a parent
        $hitem=GUICtrlRead($TreeView)
        $fromkidID=$hitem
        $hfromparent=$hpar
        $editflag=$edflag
    EndIf
EndFunc

;paste item into current parent group
;On Entry: Treeviw control 
;On Exit new item contril ID else 0
Func TV_Paste($Treeview,$x,$y)
 Local $hitem,$hpar,$curkid,$parid,$id
    $id=0
    If $fromkidID=-1 Then Return 0
    $hitem=TV_Hittest($Treeview,$x,$y,$TVHT_ONITEMRIGHT,0)
    If NOT $hitem Then  return 0
    $hpar=GUICtrlSendMsg($TreeView,$TVM_GETNEXTITEM,$TVGN_PARENT,$hitem) 
    If NOT $hpar Then $hpar=$hitem
    If $hpar=$hfromparent Then Return 0
    GUICtrlSendMsg($TreeView,$TVM_SELECTITEM,$TVGN_CARET,$hpar)
    $parid=GUICtrlRead($TreeView);get control id
    $curkid=GUICtrlRead($fromkidID,1);kid info
    $id=GUICtrlCreateTreeViewItem($curkid[0],$parid)
    If $id Then GUICtrlSetState($id,$GUI_FOCUS)
    GUICtrlSendMsg($TreeView,$TVM_SORTCHILDREN ,0,$hpar) 
    If $editflag=$ED_CUT Then 
        GUICtrlDelete($fromkidID)
        $editflag=0
        $fromkidID=-1
    EndIf
    Return $id
EndFunc

;delete current item
Func TV_DeleteItem($Treeview)
 Local $id
 $id=GUICtrlRead($TreeView,1)
 If NOT @error Then
 If MsgBox(36,"Delete Item","Delete " &$id[0]&" ?")=7 Then Return
;if tracking with arrays then update here
 If $id[1]=$fromkidID Then 
     $fromkidID=-1
     GUICtrlSetState($contexPaste,$GUI_DISABLE); to allow drag and dropping
 EndIf   
 GUICtrlDelete($id[1]);if a parent really should loop through all childern and delete them first:P
 EndIf
EndFunc

;just test to see if mouse positions passed will hit a treeview item if it does then set focus 
;On Entry: control id of treeview,  mouse x and y positions to test, and optional exclude hit area and no foucs
;on Eixt:  handle to control if a hit...else 0
;should be easy to modify and use with listviews, which i have yet to play with
Func TV_Hittest($TreeView,$x,$y,$nohit=0,$focus=1)
 Local $i,$hitinfo,$hit,$tpos
 $i=0
;get top and left positions of treeview control
 $tpos=ControlGetPos("","",$TreeView)
 If NOT @error Then
    $x=$x-$tpos[0] ;left offset
    $y=$y-$tpos[1];$top offset 
    $hitinfo=DllStructCreate("int;int;uint;uint");not sure if uint or ptr should go here...will look it up..32 bits is 32 bits
    If NOT @error Then 
        DllStructSetData($hitinfo,1,$x)
        DllStructSetData($hitinfo,2,$y)
        DllStructSetData($hitinfo,3,0)
        DllStructSetData($hitinfo,4,0)
        GUICtrlSendMsg($TreeView,$TVM_HITTEST,0,DllStructGetPtr($hitinfo))
        $hit=DllStructGetData ($hitinfo,3);flags returned
        $i= DllStructGetData ($hitinfo,4);handle
        $hitinfo=0;DllStructDelete($hitinfo); seems no DllStructDelete in beta version 1.99
        If BitAND($hit,$nohit) Then Return 0
        If  BitAND($hit,$TEST)=0 Then return 0 
        If $i And $focus<>0 Then MsgBox(0, "", $hit)
;~          GUICtrlSendMsg($TreeView,$TVM_SELECTITEM,$TVGN_CARET,$i) 
    EndIf
EndIf
 Return $i;return control handle if any
EndFunc

;return parent control ID that matches handle passed
;On Enry: handle to parent treeviewitem  control
;on Exit: control ID else 0
Func GetparentID($hpar)
 Local $i,$hitem
  For $i=0 To $parents[0][0]-1
    $hitem=GUICtrlGetHandle($parents[$i][$PAR_CTRLID]);could use kid array 
    If $hitem=$hpar Then Return $parents[$i][$PAR_CTRLID]
    Next;i
    Return 0
EndFunc

;fill arrays in case someone wants to play with code
Func SetUpTreeview()
 Local $i,$x,$parent,$kid,$parid,$cnt=0,$y
  $parent="Parent-"
  $kid="Kid-"
  For $i=0 To $NUM_PARS-1
      $parents[$i][$PAR_NAME]=$parent &$i+1
      $parid=GUICtrlCreateTreeViewItem($parents[$i][$PAR_NAME], $ClassTreeview)
      $parents[$i][$PAR_CTRLID]=$parid
    For $x=0 To $NUM_KIDS-1
        $kids[$cnt][$KID_NAME]=$parent&$i+1 & "-" &$kid &$x+1
        $kids[$cnt][$KID_CTRLID]=GUICtrlCreateTreeViewItem($kids[$cnt][$KID_NAME],$parid)
        $kids[$cnt][$KID_PARID]=$parid
        $kids[$cnt][$KID_PARINDEX]=$i
        $cnt=$cnt+1
    Next;x
    GUICtrlSetState($parid,$GUI_EXPAND)
Next;i
$parents[0][0]=$i
$kids[0][0]=$cnt
EndFunc

;***************************************************************************************************

***
;copied from help file, who ever wrote these thanks much!
;modified to suit my needs
;***************************************************************************************************

**
;Show a menu in a given GUI window which belongs to a given GUI ctrl
;On Entry: window handle, context menu ID and 
;optional control ID this menu belongs to, if control is not under cursor then exit without calling menu popup
;On Exit: nada
Func ShowMenu($hWnd,$nContextID,$ifunderID=0)
    Local $hMenu = GUICtrlGetHandle($nContextID)
    CONST $TPM_RIGHTBUTTON= 2
    CONST $TPM_NONOTIFY= 128
    CONST $TPM_RETURNCMD =256;returns menu selection (if any) and does not send msg evenet
    GUISetState(@SW_RESTORE,$winhandle);in case called then user went outside menu or window area
    $arPos =GUIGetCursorInfo($hWnd) 
    If NOT @error Then
    If $ifunderID And  $arpos[4]<>$ifunderID Then Return
        Local $x = $arPos[0]+8
        Local $y = $arPos[1]+8
        ClientToScreen($hWnd, $x, $y) 
        GUISetState(@SW_LOCK,$winhandle) 
        DllCall("user32.dll", "int", "TrackPopupMenuEx", "hwnd", $hMenu, "int",$TPM_RIGHTBUTTON, "int", $x, "int", $y, "hwnd", $hWnd, "ptr", 0)
        GUISetState(@SW_UNLOCK,$winhandle)
    EndIf
EndFunc

; Convert the client (GUI) coordinates to screen (desktop) coordinates
Func ClientToScreen($hWnd, ByRef $x, ByRef $y)
    Local $stPoint = DllStructCreate("int;int")
    DllStructSetData($stPoint, 1, $x)
    DllStructSetData($stPoint, 2, $y)
    DllCall("user32.dll", "int", "ClientToScreen", "hwnd", $hWnd, "ptr", DllStructGetPtr($stPoint))
    $x = DllStructGetData($stPoint, 1)
    $y = DllStructGetData($stPoint, 2)
   ; release Struct not really needed as it is a local 
    $stPoint = 0
EndFunc

I would be thankful for nudges in the right direction :) .

Thanks in advance, E.

Link to comment
Share on other sites

Once again - Hi Ebenezer,

When you say links, you are talking shortcuts right - not Html links?

One of my programs Context Options has an unusual ability with .lnk files, which I think unique and may be of some help to you. Other than that, I'm not very versed in C++, so can't help you there!

Hope this may help, and once again thanks for the other help!

I'll keep pondering what you ask ... you never know, I might surprise myself!

Make sure brain is in gear before opening mouth!
Remember, what is not said, can be just as important as what is said.

Spoiler

What is the Secret Key? Life is like a Donut

If I put effort into communication, I expect you to read properly & fully, or just not comment.
Ignoring those who try to divert conversation with irrelevancies.
If I'm intent on insulting you or being rude, I will be obvious, not ambiguous about it.
I'm only big and bad, to those who have an over-active imagination.

I may have the Artistic Liesense ;) to disagree with you. TheSaint's Toolbox (be advised many downloads are not working due to ISP screwup with my storage)

userbar.png

Link to comment
Share on other sites

Thanks for the hint.

Unfortunately I was somewhat vague. The program is essentially a hash filter. It does not store links as such.

I just created two panes - in the right listview there is the hash and filename data. To the left is a listview with the possible categories.

What I would like to do is to drag an entry from the right pane to the left pane. When this happens, autoit should write the hash and filename to an inifile under the section [selected category].

Then, when someone selects an category autioit will get the hashes from the ini-file and write them back to the right listview.

Sounds rather simplicistic, but I can't figure out a way to see on what category the hash was dropped (well short of creating a button for every category which would be a real design and portability nightmare :( ).

Still hoping for some inspiration :)

Intended GUI:

Posted Image

My code so far:

#include <constants.au3>
#include <GUIConstants.au3>
#include <GuiListView.au3>

Opt("GUIOnEventMode", 1)
Opt( "TrayOnEventMode", 1)
Opt("TrayAutoPause", 0)
Opt("TrayMenuMode", 1)

$Inifile = "Config.Ini"
$Datadump = "Hashesarchive.Ini"

    #region - GUI

$MainWindow = GUICreate("Testing222", (@DesktopWidth-40), (@DesktopHeight-105), 20, 20, -1, $WS_EX_TOPMOST)

    #region - Link Storage
   
; Context Menu
    Dim $vCategories_Array[3]
   
    $Storage_Categories = GUICtrlCreateListView("Categories", 30, 50, 100, (@DesktopHeight-185))
    GUICtrlSetStyle(-1, BitOr($LVS_REPORT, $LVS_SINGLESEL, $LVS_SHOWSELALWAYS), $LVS_EX_FULLROWSELECT)
    $vCategories_Array[0] =  GUICtrlCreateListViewItem("- Show Clipboard", $Storage_Categories)
    $vCategories_Array[1] =  GUICtrlCreateListViewItem("- Show All Saved", $Storage_Categories)
    $vCategories_Array[2] =  GUICtrlCreateListViewItem("General", $Storage_Categories)
    
    $vCategories_Names_Array = IniReadSection($Inifile, "Categories")
    If @error <> 1 Then
        ReDim $vCategories_Array[(3+$vCategories_Names_Array[0][0])]
        For $i = 3 To $vCategories_Names_Array[0][0]+2
            $vCategories_Array[$i] = GUICtrlCreateListViewItem($vCategories_Names_Array[($i-2)][0], $Storage_Categories)
        Next
    EndIf
   
;Categories Context Menu
    $Con_Storage_Categories = GUICtrlCreateContextMenu($Storage_Categories)
    $Con_Storage_Categories_Create = GUICtrlCreateMenuitem("New Group", $Con_Storage_Categories)
    $Con_Storage_Categories_Delete = GUICtrlCreateMenuitem("Delete Group", $Con_Storage_Categories)
   
;Main Linklist
    $NewItems_Storage = GUICtrlCreateListView("Filename|Filesize|Hash", 150, 50, (@DesktopWidth-220), (@DesktopHeight-185), $LVS_SHOWSELALWAYS)
    _GUICtrlListViewSetColumnWidth($NewItems_Storage, 1, 85)
    _GUICtrlListViewSetColumnWidth($NewItems_Storage, 2, 200)
    _GUICtrlListViewSetColumnWidth($NewItems_Storage, 0, (@DesktopWidth-585))
   
;Linklist ContextMenu
    $Context_NewItems = GUICtrlCreateContextMenu($NewItems_Storage)
    $Con_NewItems_Download = GUICtrlCreateMenuitem("Download Selected", $Context_NewItems)
    $Con_NewItems_Filter = GUICtrlCreateMenuitem("Filter Selected", $Context_NewItems)
   
#endregion
   
#endregion
   
   
   #region - Event Triggers
   
   GUISetOnEvent($GUI_EVENT_MINIMIZE, "trayLClick")
   TraySetOnEvent($TRAY_EVENT_PRIMARYDOUBLE, "trayLClick")
   GUISetOnEvent($GUI_EVENT_CLOSE, "CLOSEClicked")
   GUICtrlSetOnEvent($Con_NewItems_Download, "DownloadMultiple")
   GUICtrlSetOnEvent($Con_NewItems_Filter, "FilterMultiple")
   GUICtrlSetOnEvent($Con_Storage_Categories_Create, "CreateGroup")
   GUICtrlSetOnEvent($Con_Storage_Categories_Delete, "GetSelectedCategory")
   
   #endregion
   
   #region - Clipboard Hook
   
   Global Const $WM_DRAWCLIPBOARD = 0x0308
   Global Const $WM_CHANGECBCHAIN = 0x030D
   Global $origHWND
   
   $origHWND = DLLCall("user32.dll","hwnd","SetClipboardViewer","hwnd",$MainWindow)
   $origHWND = $origHWND[0]
   
   GUIRegisterMsg($WM_DRAWCLIPBOARD,"OnClipBoardChange")
   GUIRegisterMsg($WM_CHANGECBCHAIN,"OnClipBoardViewerChange")
   
   #endregion
   
   
   While 1
    Sleep(50)
   WEnd   
   
   #region - Transfer to Edonkey
   
   Func ListView_DoubleClick()
    $vItem = _GUICtrlListViewGetSelectedIndices($NewItems_Storage)
   
    If $vItem <> -1 Then
        $Name = _GUICtrlListViewGetItemText($NewItems_Storage, $vItem, 0)
        $Size = _GUICtrlListViewGetItemText($NewItems_Storage, $vItem, 1)
        $Hash = _GUICtrlListViewGetItemText($NewItems_Storage, $vItem, 2)
        $Link = "ed2k://|file|"&$Name&"|"&$Size&"|"&$Hash&"|"
        RunWait("rundll32.exe url.dll,FileProtocolHandler " & $Link, @WorkingDir)
        IniWrite($Datadump, "Filters", $Hash, $Size)
        _GUICtrlListViewDeleteItemsSelected($NewItems_Storage)
    EndIf
    
   EndFunc ;==>ListView_DoubleClick
   
   Func DownloadMultiple()
    
    $vNumberOfSelected = _GUICtrlListViewGetSelectedCount($NewItems_Storage)
    
    If $vNumberOfSelected <> 0 AND $vNumberOfSelected <> -1 Then
        
        WinSetState($MainWindow, -1, @SW_HIDE)
        ToolTip("Transferring Links", (@DesktopWidth/2), (@DesktopHeight/2), "Please Wait", 1, 2)
        
        Dim $vIndex[$vNumberOfSelected]
        Dim $vDowns[$vNumberOfSelected][3]
        
        $vIndex = _GUICtrlListViewGetSelectedIndices($NewItems_Storage, 1, $MainWindow)
;erst holen     
        For $i = 1 To $vNumberOfSelected
            $Name = _GUICtrlListViewGetItemText($NewItems_Storage, $vIndex[$i], 0, $MainWindow)
            $Size = _GUICtrlListViewGetItemText($NewItems_Storage, $vIndex[$i], 1, $MainWindow)
            $Hash = _GUICtrlListViewGetItemText($NewItems_Storage, $vIndex[$i], 2, $MainWindow)
            $Link = "ed2k://|file|"&$Name&"|"&$Size&"|"&$Hash&"|"
            $vDowns[($i-1)][0] = $Link
            $vDowns[($i-1)][1] = $Hash
            $vDowns[($i-1)][2] = $Size
            
        Next
    EndIf
    
;dann übertragen
    For $i = 1 To $vNumberOfSelected
        RunWait("rundll32.exe url.dll,FileProtocolHandler " & $vDowns[($i-1)][0], @WorkingDir)
        Sleep(1000)
        IniWrite($Datadump, "Filters", $vDowns[($i-1)][1], $vDowns[($i-1)][2])
    Next

    _GUICtrlListViewDeleteItemsSelected($NewItems_Storage, $MainWindow)
    ToolTip("")
    WinSetState($MainWindow, "", @SW_SHOW)
    WinActivate($MainWindow)
    WinWaitActive($MainWindow)
    
   EndFunc
   
   #endregion
   
   
   
   
   
   
   
   #region - Management Functions
   
func trayLClick()

    If BitAND(WinGetState($MainWindow), 2) Then
        guiSetState( @SW_HIDE, $MainWindow)
    Else
          guiSetState( @SW_SHOW, $MainWindow)
    EndIf
      
endfunc
   
Func CLOSEClicked()
; send notification that we no longer will be in clipboard hook queue
    DLLCall("user32.dll","int","ChangeClipboardChain","hwnd",$MainWindow,"hwnd",$origHWND)
    Exit
EndFunc

Func FilterMultiple()
    $vNumberOfSelected = _GUICtrlListViewGetSelectedCount($NewItems_Storage)
    
    If $vNumberOfSelected <> 0 AND $vNumberOfSelected <> -1 Then
        Dim $vIndex[$vNumberOfSelected]
        
        $vIndex = _GUICtrlListViewGetSelectedIndices($NewItems_Storage, 1)
        
        For $i = 1 To UBound($vIndex)-1
            $Name = _GUICtrlListViewGetItemText($NewItems_Storage, $vIndex[$i], 0)
            $Size = _GUICtrlListViewGetItemText($NewItems_Storage, $vIndex[$i], 1)
            $Hash = _GUICtrlListViewGetItemText($NewItems_Storage, $vIndex[$i], 2)
            IniWrite($Datadump, "Filters", $Hash, $Size)
        Next
        
        _GUICtrlListViewDeleteItemsSelected($NewItems_Storage)
    EndIf
EndFunc

   #endregion
   

   
   #region - Clipboard Management
   
Func OnClipBoardChange($hWnd, $Msg, $wParam, $lParam)
; do what you need when clipboard changes
    ProcessClipboard()
; send notification about clipboard change to next clipviewer
    dllcall("user32.dll","int","SendMessage","hWnd",$origHWND,"int",$WM_DRAWCLIPBOARD,"int",$wParam,"int",$lParam)
EndFunc
   
Func ProcessClipboard()
    
    $Temp = ClipGet()
    $NumberofItems = NumberOfResults($Temp, "ed2k://")
    
    If $NumberofItems > 0 Then
        _GUICtrlListViewDeleteAllItems($NewItems_Storage)
    
        For $i = 1 To $NumberofItems
            $ItemStart = StringInStr($Temp, "ed2k://", 1, $i)
            $Name = SucheBegriff($Temp, $ItemStart, "|", 2, "|", 1)
            $Size = SucheBegriff($Temp, $ItemStart, "|", 3, "|", 1)
            $Hash = SucheBegriff($Temp, $ItemStart, "|", 4, "|", 1)
            $Link = "ed2k://|file|"&$Name&"|"&$Size&"|"&$Hash&"|"
            
            If IniRead($Datadump, "Filters", $Hash, -1) = -1 Then
                GUICtrlCreateListViewItem($Name & "|" & $Size & "|" & $Hash, $NewItems_Storage)
            EndIf
        Next
        trayLClick()
    EndIf
    
EndFunc
   
Func OnClipBoardViewerChange($hWnd, $Msg, $wParam, $lParam)
; if our remembered previous clipviewer is removed then we must remember new next clipviewer
; else send notification about clipviewr change to next clipviewer
    If $wParam = $origHWND Then
        $origHWND = $lParam
    Else
        dllcall("user32.dll","int","SendMessage","hWnd",$origHWND,"int",$WM_CHANGECBCHAIN,"hwnd",$wParam,"hwnd",$lParam)
    EndIf
EndFunc
   
   #endregion
   
   
   
   
   
   #region - Category Management for Tab1
   
   Func ProcessDropEvent()
    MsgBox(0, "From", @GUI_DragId)
    MsgBox(0, "To", @GUI_DropId)
    MsgBox(0, "To", @GUI_DragFile)
   EndFunc
   
   Func GetSelectedCategory()
    $vTemp = GuiGetCursorInfo($MainWindow)
    MsgBox(0, "", $vTemp[4])
  ;~    $vCoordinatesMain = ControlGetPos("", "", $MainWindow)
  ;~    $vCoordinates = ControlGetPos("", "", $MainWindow)
   EndFunc
    
   Func CreateGroup()
    $vName = InputBox("Create New Group", "Please enter a name for the new group")
    
    If $vName <> "" Then
        ReDim $vCategories_Array[(UBound($vCategories_Array)+1)]
        $vCategories_Array[(UBound($vCategories_Array)-1)] = GUICtrlCreateListViewItem($vName, $Storage_Categories)
        IniWrite($Inifile, "Categories", $vName, -1)
    EndIf
   EndFunc
   
   
   #endregion
   
   
   
   
   
   
   
   
   
   #region - Search Functions
   
   Func NumberOfResults($StringToSearch, $vSuchbegriff_Start)                       ;Wie viele Items auf der Seite. Wird unten gebraucht, damit der Array in seinen Grenzen arbeitet
   For $y = 1 to 2500
    $pos = StringInStr ($StringToSearch, $vSuchbegriff_Start, 1, $y)
         If $pos = 0 Then ; StringInStr() failed
             ExitLoop
         EndIf
     Next
   Return($y-1)
   EndFunc
   
   Func SucheBegriff($Searchedstring_Temp, $vStartpos, $vSuchbegriff_Start, $StartCount, $vSuchbegriff_Stopp, $StoppCount)
    
   #CS 
    Suchen nach dem xten ($count) jeweiligen Wert im String (Searchedstring)  
   #CE
   
    $Grenze_links = _Searchfromplace($Searchedstring_Temp, $vSuchbegriff_Start, $vStartpos, $StartCount) + StringLen($vSuchbegriff_Start)
    $Grenze_rechts = _Searchfromplace($Searchedstring_Temp, $vSuchbegriff_Stopp, $Grenze_links, $StoppCount)
    $Lenghtcount = $Grenze_rechts - $Grenze_links
    
    Return(StringMid($Searchedstring_Temp, $Grenze_links, $Lenghtcount))
   EndFunc
   
   Func _Searchfromplace($Searchedstring_Temp, $Searchstring, $start, $Count)
    
   #CS  
        Sucht das xte Auftreten eines Terms nach der angegebenen Position und gibt die Position im Gesamtstring aus.
        OK
   #CE
    $Searchedstring_Temp_Lenght = StringLen($Searchedstring_Temp)
    
    $Searchedstring_Temp = StringTrimLeft ( $Searchedstring_Temp, $start )
        
    $Add_to_count = ($Searchedstring_Temp_Lenght - (StringLen($Searchedstring_Temp)))
    $Position_Searchstring = StringInStr($Searchedstring_Temp, $Searchstring, 1, $Count)
    Return($Position_Searchstring + $Add_to_count)
   EndFunc
   
   #endregion
Link to comment
Share on other sites

  • 3 months later...

Unfortunately I was somewhat vague. The program is essentially a hash filter. It does not store links as such.

I just created two panes - in the right listview there is the hash and filename data. To the left is a listview with the possible categories.

What I would like to do is to drag an entry from the right pane to the left pane. When this happens, autoit should write the hash and filename to an inifile under the section [selected category].

Then, when someone selects an category autioit will get the hashes from the ini-file and write them back to the right listview.

Sounds rather simplicistic, but I can't figure out a way to see on what category the hash was dropped (well short of creating a button for every category which would be a real design and portability nightmare :P ).

Still hoping for some inspiration :)

I'm in the same boat. So far, I can now make an infinite tree from scratch by using Drag & Drop, but can't determine the TreeViewItem under the mouse cursor at any given time.

I need to figure out how to get the Location of a TreeViewItem

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...