Sources PureBasic
Sources PureBasicConsultez toutes les sources
Nombre d'auteurs : 41, nombre de sources : 88, dernière mise à jour : 13 août 2011
Encore un petit code pour gérer le Drag'n drop. Cette fois, il s'agit de permettre à l'utilisateur d'organiser et de trier manuellement les éléments d'un TreeGadget par glisser/déposer.
Ca peut être utile si l'un de vos programmes nécessite une gestion de liste hiérarchique par l'utilisateur. Personnellement, je vais m'en servir pour permettre aux utilisateurs de DropUpLoad d'organiser et de gérer la liste des serveurs FTP. Ca pourrait servir à gérer une liste de raccourcis, une liste de fichiers, etc.
Voir également cette solution qui bien que moins complète a l'avantage d'être multi-plateforme.
; Drag'nDrop manual sort for TreeGadget
; By Zapman
;
; This demo code shows how to implemente a drag'n drop ability for TreeGadget
; in order to allow the user to sort manually the gadget content by draging
; it elements.
;
Procedure
GetFolderIconHandle()
*
sfi.SHFILEINFO =
AllocateMemory(SizeOf(SHFILEINFO))
If
SHGetFileInfo_("aa.txt"
,#FILE_ATTRIBUTE_DIRECTORY
,*
sfi, SizeOf(SHFILEINFO), #SHGFI_ICON
|
#SHGFI_SMALLICON
|
#SHGFI_USEFILEATTRIBUTES
)
hFolderIcon =
*
sfi\hIcon
EndIf
FreeMemory(*
sfi)
ProcedureReturn
hFolderIcon
EndProcedure
Procedure
GetTreeItemIndexFromHandle(IHandle,TreeGadgetID)
; By Timo 'fr34k' Harter and Zapman
dItem =
0
hItem =
SendMessage_(TreeGadgetID, #TVM_GETNEXTITEM
, #TVGN_ROOT
, 0
)
While
IHandle And
hItem And
hItem <>
IHandle
hItem2 =
SendMessage_(TreeGadgetID, #TVM_GETNEXTITEM
, #TVGN_CHILD
, hItem)
Repeat
If
hItem2 =
#Null
: hItem2 =
SendMessage_(TreeGadgetID, #TVM_GETNEXTITEM
, #TVGN_NEXT
, hItem): EndIf
If
hItem2 =
#Null
: hItem =
SendMessage_(TreeGadgetID, #TVM_GETNEXTITEM
, #TVGN_PARENT
, hItem): EndIf
Until
hItem2 <>
#Null
hItem =
hItem2
dItem +
1
Wend
ProcedureReturn
dItem
EndProcedure
;
Procedure
HighLightTreeItem(TreeGadgetID,hItem,HighLight)
; By Timo 'fr34k' Harter and Zapman
If
HighLight : HighLight =
#TVIS_DROPHILITED
: EndIf
; to be sure that te right value is used
; We'll send a #TVM_SETITEM message. We only need to change the
; item state, so #TVIF_STATE is enough for the mask.
pitem.TV_ITEM
pitem\mask =
#TVIF_STATE
pitem\hItem =
hItem
; 'stateMask' determines, what will be changed, and 'state' sets the actual value,
; so here, we set the TVIS_DROPHILITED state flag to HighLight.
pitem\state =
HighLight
pitem\stateMask =
#TVIS_DROPHILITED
Result =
SendMessage_(TreeGadgetID, #TVM_SETITEM
, 0
, @pitem)
; a redraw is neccesary here to avoid problems.
RedrawWindow_(TreeGadgetID, 0
, 0
, #RDW_UPDATENOW
)
ProcedureReturn
Result
EndProcedure
;
Procedure
GetTreeItemIconIndex(TreeGadget,hitem)
; by Zapman
tvitem.TV_ITEM\mask=
#TVIF_IMAGE
tvitem\hitem=
hitem
If
SendMessage_(GadgetID(TreeGadget), #TVM_GETITEM
,0
,@tvitem) ; get the icon index from the item
ProcedureReturn
tvitem\iImage
Else
ProcedureReturn
-
1
EndIf
EndProcedure
;
Procedure
SetTreeItemIconIndex(TreeGadget,hitem,iconeIndex)
; by Zapman
tvitem.TV_ITEM\mask=
#TVIF_IMAGE
|
#TVIF_SELECTEDIMAGE
tvitem\hitem=
hitem
tvitem\iImage=
iconeIndex
tvitem\iSelectedImage =
iconeIndex
result =
SendMessage_(GadgetID(TreeGadget), #TVM_SETITEM
,0
,@tvitem) ; set the icon index from the item
ProcedureReturn
result
EndProcedure
;
Procedure
InvertTreeGadgetItems(TreeGadget,p1,p2)
t1$=
GetGadgetItemText(TreeGadget,p1)
t2$=
GetGadgetItemText(TreeGadget,p2)
SetGadgetItemText(TreeGadget,p1,t2$)
SetGadgetItemText(TreeGadget,p2,t1$)
iconindex1 =
GetTreeItemIconIndex(TreeGadget,GadgetItemID(TreeGadget,p1)); get the icon from the first item
iconindex2 =
GetTreeItemIconIndex(TreeGadget,GadgetItemID(TreeGadget,p2)); get the icon from the second item
SetTreeItemIconIndex(TreeGadget,GadgetItemID(TreeGadget,p1),iconindex2); set the icon for the first item
SetTreeItemIconIndex(TreeGadget,GadgetItemID(TreeGadget,p2),iconindex1); set the icon for the second item
EndProcedure
;
;
Global
DD_TreeGadget
Procedure
DD_TreeCallback(Window, Message, wParam, lParam)
; By Timo 'fr34k' Harter for ListView Gadget
; Adapted to TreeView by Zapman
Shared
OldTreeItem,TreeIsDraging,DraggedItemsList$,DragImageList
result =
#PB_ProcessPureBasicEvents
; The first message we need is #TVN_BEGINDRAG. This is a so called
; Notification message. This means, that you don't get a message called
; #TVN_BEGINDRAG, but you get a #WM_NOTIFY message, with further information,
; that tells you, that it is #TVN_BEGINDRAG
If
Message =
#WM_NOTIFY
; The lparam paramenter contains a pointer to a NMHDR structure. There is
; the information about the Message
*
nmhdr.NMHDR =
lParam
; The 'hwndfrom' member tells you, which Gadget actually sent the message
; This must be always checked to be sure, it is the right gadget.
; We allow only our own Gadgets:
If
*
nmhdr\hwndfrom =
GadgetID(DD_TreeGadget)
; The 'code' member contains the real message, in our case #TVN_BEGINDRAG
If
*
nmhdr\code =
#TVN_BEGINDRAG
; Ok, for the #TVN_BEGINDRAG notification message, lParam is a pointer to a
; NMTREEVIEW Structure. You might think that this can't be, as lParam allready
; pointed to a NMHDR structure, but this is correct, as NMTREEVIEW has a
; NMHDR structure inside, it only adds more members to it.
*
nmv.NMTREEVIEW =
lParam
; The 'hItem' member contains the index of the source item, which we will need
; later.
TreeItemSource =
*
nmv\itemNew\hItem
OldTreeItem =
TreeItemSource ; will be used to unhilite the item which was hilited
; By sending a #TVM_CREATEDRAGIMAGE message to the gadget, we create an ImageList
; that contains just one image, the drag&drop image. We will need the Imagelist WinAPI
; commands to work with that one later.
HighLightTreeItem(GadgetID(DD_TreeGadget),TreeItemSource,0
)
HighLightTreeItem(GadgetID(DD_TreeGadget),GadgetItemID(DD_TreeGadget,GetGadgetState(DD_TreeGadget)),0
)
DragImageList =
SendMessage_(GadgetID(DD_TreeGadget), #TVM_CREATEDRAGIMAGE
, 0
,TreeItemSource)
;
; If the user is draging a node,
; we'll modify the image by adding all the items contained by the node
LImage =
400
HImage =
600
Pb_Image =
CreateImage(#PB_Any
,LImage,HImage)
Font1 =
LoadFont(#PB_Any
, "Tahoma"
, 8
)
StartDrawing(ImageOutput(Pb_Image))
DrawingFont(FontID(Font1))
Box(0
, 0
, LImage, HImage ,RGB(255
,255
,255
))
ItemIndex =
GetTreeItemIndexFromHandle(TreeItemSource,GadgetID(DD_TreeGadget))
ItemText$ =
GetGadgetItemText(DD_TreeGadget,ItemIndex,0
)
DraggedItemsList$ =
Str(ItemIndex)+
Chr(13
)+
ReplaceString(ItemText$,Chr(13
),""
)+
Chr(13
)+
"0"
+
Chr(13
)
DrawText(0
,0
,ItemText$,0
,RGB(255
,255
,255
))
dep =
TextWidth(ItemText$)
posvert=
0
hcar =
14
hItem =
SendMessage_(GadgetID(DD_TreeGadget), #TVM_GETNEXTITEM
, #TVGN_CHILD
, TreeItemSource)
If
hItem
level =
1
Repeat
posvert +
hcar
ItemIndex =
GetTreeItemIndexFromHandle(hItem,GadgetID(DD_TreeGadget))
ItemText$ =
GetGadgetItemText(DD_TreeGadget,ItemIndex,0
)
DraggedItemsList$ +
Str(ItemIndex)+
Chr(13
)+
ReplaceString(ItemText$,Chr(13
),""
)+
Chr(13
)+
Str(level)+
Chr(13
)
DrawText(level*
20
,posvert,ItemText$,0
,RGB(255
,255
,255
))
nWidth =
TextWidth(ItemText$)+
(level*
20
)
If
nWidth>
dep ; calculate max text width for our draging image
dep =
nWidth
EndIf
hItem2 =
SendMessage_(GadgetID(DD_TreeGadget), #TVM_GETNEXTITEM
, #TVGN_CHILD
, hItem) ; is the next item a child ?
If
hItem2
level +
1
hItem =
hItem2
Else
hItem2 =
SendMessage_(GadgetID(DD_TreeGadget), #TVM_GETNEXTITEM
, #TVGN_NEXT
, hItem) ; is it a same level item ?
If
hItem2
hItem =
hItem2
Else
hItem =
SendMessage_(GadgetID(DD_TreeGadget), #TVM_GETNEXTITEM
,#TVGN_PARENT
, hItem) ; get the parent of our item
hItem =
SendMessage_(GadgetID(DD_TreeGadget), #TVM_GETNEXTITEM
, #TVGN_NEXT
, hItem) ; and go to the next
level -
1
EndIf
EndIf
Until
level =
0
Or
hItem =
0
EndIf
DraggedItemsList$ +
"Store_end"
+
Chr(13
)
StopDrawing()
FreeFont(Font1)
ImageList_SetIconSize_(DragImageList,dep+
5
,posvert+
hcar)
ImageList_AddMasked_(DragImageList,ImageID(Pb_Image),RGB(255
,255
,255
))
FreeImage(Pb_Image)
If
DragImageList
; This begins the drag&drop operation by displaying the image
If
ImageList_BeginDrag_(DragImageList , 0
, 0
, 0
)
; this command shows or hides the drag&drop image. Or course,
; we want to see it now :)
ImageList_DragShowNolock_(#True
)
; this causes windows to send all mouse messages to our window,
; even if the mouse is outside of our window. This is neccesary,
; because we need to detect the mouseup event to abort the
; operation, even if the mouse is outside our window.
SetCapture_(GetParent_(GadgetID(DD_TreeGadget)))
; hide the standard cursor
ShowCursor_(#False
)
; When processing the other events, we need to know whether something
; is being draged or not.
TreeIsDraging =
#True
EndIf
; check for ImageList_BeginDrag_()
EndIf
; check for DragImageList
EndIf
; check for #TVN_BEGINDRAG
EndIf
; check for right gadget
; The next message we need is #WM_MOUSEMOVE, to update the mouse.
; But only if TreeIsDraging is #TRUE.
ElseIf
Message =
#WM_MOUSEMOVE
And
TreeIsDraging
; now we hide the image to avoid redrawn problems.
ImageList_DragShowNolock_(#False
)
; the next thing we do is hilighting the target item in the target gadget.
GetWindowRect_(GadgetID(DD_TreeGadget),re.RECT)
GetCursorPos_(pt.POINT)
If
PtInRect_(@re, pt\x |
(pt\y<<
32
))
; What we need next is the Item, that is currently under the mouse cursor.
; the #TVM_HITTEST message does that test for us.
; here, we need coordinates relative to the top/left corner of our target
; Gadget, so we substract the Gadget position from our window coordinates
; When #EM_MOUSEMOVE is sent, the lParam parameter contains
; the x coordinate in the low-word and the y coordinate in the high-word, so we
; just use them here:
MouseX =
lParam &
$FFFF
MouseY =
lParam >>
16
hittestinfo.TV_HITTESTINFO
hittestinfo\pt\x =
MouseX -
GadgetX(DD_TreeGadget)
hittestinfo\pt\y =
MouseY -
GadgetY(DD_TreeGadget)
; find the item, if none is under the cursor, we get -1, and the next
; SendMessage won't work, and nothing is hilighted.
TargetItem =
SendMessage_(GadgetID(DD_TreeGadget), #TVM_HITTEST
, 0
, @hittestinfo)
If
TargetItem<>-
1
And
TargetItem<>
OldTreeItem
If
OldTreeItem
HighLightTreeItem(GadgetID(DD_TreeGadget),OldTreeItem,0
) ; Unhilighte the precedent hilighted item
EndIf
OldTreeItem =
TargetItem
HighLightTreeItem(GadgetID(DD_TreeGadget),OldTreeItem,1
)
EndIf
Else
; scroll treegadget if mouse is upper or lower than it
GetWindowRect_(GadgetID(DD_TreeGadget),re.RECT)
GetCursorPos_(@MP.POINT)
If
MP\y <
re\top
SendMessage_(GadgetID(DD_TreeGadget), #WM_VSCROLL
, #SB_LINEUP
, 0
);
EndIf
If
MP\y >
re\bottom
SendMessage_(GadgetID(DD_TreeGadget), #WM_VSCROLL
, #SB_LINEDOWN
, 0
);
EndIf
EndIf
; now we can show the drag image again:
ImageList_DragShowNolock_(#True
)
; this moves the drag Image.
GetCursorPos_(@MP.Point)
ImageList_DragMove_(MP\x, MP\y-
7
)
; that's all to do while moving the mouse. Of course, there can be more checks added,
; and for example, a different cursor displayed, if you don't want the source to
; be draged to the current target and so on, but i think this is enough for a basic
; example.
; next is the end of the drag&drop operation... when the user releases the mouse.
ElseIf
Message =
#WM_LBUTTONUP
And
TreeIsDraging
; first, we release all we did, to unlock the mouse.
; mouse messages will be sent to other windows again
ReleaseCapture_()
; and drag&drop (remove the image)
ImageList_EndDrag_()
; free the image list
ImageList_Destroy_(DragImageList)
; show cursor again
ShowCursor_(#True
)
; no draging in progress now.
TreeIsDraging =
#False
; next, we unhilight the last target item
If
OldTreeItem
HighLightTreeItem(GadgetID(DD_TreeGadget),OldTreeItem,0
)
EndIf
GetWindowRect_(GadgetID(DD_TreeGadget),re.RECT)
GetCursorPos_(pt.POINT)
If
PtInRect_(@re, pt\x |
(pt\y<<
32
))
; now, move the items as demanded by the user:
;
; examine items at old positions
;
nbitems =
0
FIndex =
-
1
ct =
0
Repeat
ct +
1
LValue$ =
StringField(DraggedItemsList$,ct,Chr(13
))
If
LValue$ <>
"Store_end"
ItemIndex =
Val(LValue$)
If
FIndex =
-
1
: FIndex =
ItemIndex: EndIf
ct +
2
nbitems +
1
EndIf
Until
LValue$ =
"Store_end"
;
; add items at new position
;
nPosition =
GetTreeItemIndexFromHandle(OldTreeItem,GadgetID(DD_TreeGadget))+
1
If
nPosition>
FIndex And
nPosition<
(FIndex+
nbitems+
1
)
Debug
"Trying to put a node inside its own content !!!!"
Else
mnPosition =
nPosition
nLevel =
GetGadgetItemAttribute(DD_TreeGadget,nPosition-
1
,#PB_Tree_SubLevel
)
iconindex =
GetTreeItemIconIndex(DD_TreeGadget,GadgetItemID(DD_TreeGadget,nPosition-
1
))
If
iconindex And
iconindex<>-
1
; get the icon from the target item
Debug
"target is a folder"
; if there is one, we suppose that the item is a folder (a potential node)
nLevel +
1
EndIf
ct =
0
Repeat
ct +
1
LValue$ =
StringField(DraggedItemsList$,ct,Chr(13
))
If
LValue$ <>
"Store_end"
ItemIndex =
Val(LValue$)
ct +
1
ItemText$ =
StringField(DraggedItemsList$,ct,Chr(13
))
ct +
1
level =
Val(StringField(DraggedItemsList$,ct,Chr(13
)))
If
FIndex>=
mnPosition
ItemIndex +
nPosition -
mnPosition
EndIf
iconindex =
GetTreeItemIconIndex(DD_TreeGadget,GadgetItemID(DD_TreeGadget,ItemIndex)); get the icon from the old item
AddGadgetItem(DD_TreeGadget, nPosition, ItemText$,0
,level+
nLevel)
SetTreeItemIconIndex(DD_TreeGadget,GadgetItemID(DD_TreeGadget,nPosition),iconindex); set the icon for the new item
nPosition +
1
EndIf
Until
LValue$ =
"Store_end"
If
FIndex>=
mnPosition ; position has to be adjusted if items to delete are after added items
FIndex +
nbitems
nPosition =
mnPosition
Else
nPosition =
mnPosition-
nbitems
EndIf
RemoveGadgetItem(DD_TreeGadget,FIndex)
SetGadgetState(DD_TreeGadget,nPosition)
SetActiveGadget(DD_TreeGadget)
EndIf
; IsMouseOver(GadgetID(DD_TreeGadget))
EndIf
; If Message = #WM_LBUTTONUP And TreeIsDraging
EndIf
; check Message
ProcedureReturn
Result
EndProcedure
;
Global
hFolderIcon
Procedure
Enable_DragnDrop_On_TreeGadget(Window,TreeGadget)
DD_TreeGadget =
TreeGadget
hWndTV =
GadgetID(TreeGadget)
Style =
GetWindowLong_(hWndTV, #GWL_STYLE
)
Style =
Style &
(~
#TVS_DISABLEDRAGDROP
)
SetWindowLong_(hWndTV, #GWL_STYLE
, Style) ; enable drag'n drop for the gadget
;
hFolderIcon =
GetFolderIconHandle() ; get a folder icon to use later in our list
;
SendMessage_(hWndTV, #TVM_GETIMAGELIST
,#TVSIL_NORMAL
,imageList)
If
imageList =
0
; The TreeGadget has no image list!! We need one, so we'll create one.
AddGadgetItem(TreeGadget, -
1
, "ToDelete"
, hFolderIcon,0
) ; PB will automatically create an image list if we add an item with an icon
RemoveGadgetItem(TreeGadget, CountGadgetItems(TreeGadget)-
1
) ; OK, we can now delete this item
EndIf
;
SetWindowCallback(@DD_TreeCallback(),Window)
EndProcedure
; Window und Gadget...
winMain =
OpenWindow(#PB_Any
, 0
, 0
, 350
, 260
, "Drag'n Drop sorting with a TreeView"
, #PB_Window_SystemMenu
|
#PB_Window_ScreenCentered
)
TreeGadget =
TreeGadget(#PB_Any
, 5
, 5
, 200
, 250
,#PB_Tree_AlwaysShowSelection
)
Enable_DragnDrop_On_TreeGadget(winMain,TreeGadget)
ItemString =
StringGadget(#PB_Any
,220
,5
,120
,20
,""
)
TextGadget =
TextGadget(#PB_Any
, 220
, 50
, 120
, 250
,"You can sort this treeview manually by draging items from one position to another one."
)
PosVert =
160
BNewFolder =
ButtonGadget(#PB_Any
,220
,PosVert,120
,20
,"New Folder"
)
PosVert +
25
BNewItem =
ButtonGadget(#PB_Any
,220
,PosVert,120
,20
,"New Item"
)
PosVert +
25
BDelete =
ButtonGadget(#PB_Any
,220
,PosVert,120
,20
,"Delete"
)
PosVert +
25
BSort =
ButtonGadget(#PB_Any
,220
,PosVert,120
,20
,"Alphabetical Sort"
)
AddGadgetItem(TreeGadget, -
1
, "Item1"
+
Chr(13
), 0
,0
)
AddGadgetItem(TreeGadget, -
1
, "Folder#1"
, hFolderIcon,0
)
AddGadgetItem(TreeGadget, -
1
, "Item11"
,0
,1
)
AddGadgetItem(TreeGadget, -
1
, "Item12"
,0
,1
)
AddGadgetItem(TreeGadget, -
1
, "Folder#12"
,hFolderIcon,1
)
AddGadgetItem(TreeGadget, -
1
, "Item121"
,0
,2
)
AddGadgetItem(TreeGadget, -
1
, "Item122"
,0
,2
)
AddGadgetItem(TreeGadget, -
1
, "Folder#2"
, hFolderIcon,0
)
AddGadgetItem(TreeGadget, -
1
, "Itemz11"
,0
,1
)
AddGadgetItem(TreeGadget, -
1
, "zItem1a"
,0
,1
)
For
ct =
1
To
20
AddGadgetItem(TreeGadget, -
1
, "Item"
+
Str(ct+
1
),0
,0
)
Next
SetGadgetState(TreeGadget,0
)
SetGadgetText(ItemString,GetGadgetText(TreeGadget))
SendMessage_(GadgetID(ItemString), #EM_SETSEL
, 0
, Len(GetGadgetText(TreeGadget)))
SetActiveGadget(ItemString)
Repeat
Event =
WaitWindowEvent()
If
Event =
#PB_Event_Gadget
If
EventGadget() =
TreeGadget
ItemText$ =
GetGadgetItemText(TreeGadget,GetGadgetState(TreeGadget))
SetGadgetText(ItemString,ItemText$)
SendMessage_(GadgetID(ItemString), #EM_SETSEL
, 0
, Len(ItemText$))
EndIf
If
EventGadget() =
ItemString And
EventType() =
#PB_EventType_Change
SetGadgetItemText(TreeGadget,GetGadgetState(TreeGadget),GetGadgetText(ItemString))
ElseIf
EventGadget() =
BNewFolder Or
EventGadget() =
BNewItem
IIndex =
GetGadgetState(TreeGadget)+
1
If
EventGadget() =
BNewFolder
AddGadgetItem(TreeGadget,IIndex,"New folder"
,hFolderIcon)
Else
AddGadgetItem(TreeGadget,IIndex,"New item"
)
EndIf
SetGadgetState(TreeGadget,IIndex)
ItemText$ =
GetGadgetItemText(TreeGadget,IIndex)
SetGadgetText(ItemString,ItemText$)
SendMessage_(GadgetID(ItemString), #EM_SETSEL
, 0
, Len(ItemText$))
SetActiveGadget(ItemString)
ElseIf
EventGadget() =
BDelete
IIndex =
GetGadgetState(TreeGadget)
RemoveGadgetItem(TreeGadget, IIndex)
SetGadgetState(TreeGadget,IIndex)
SetGadgetText(ItemString,ItemText$)
SendMessage_(GadgetID(ItemString), #EM_SETSEL
, 0
, Len(ItemText$))
SetActiveGadget(TreeGadget)
ElseIf
EventGadget() =
BSort
; Windows API has a sort function for treeview (#TVM_SORTCHILDREN message)
; but we can't use it because the PureBasic element index is not sorted with the elements.
; So, we recreate a complete sort function for PB treegadget.
lastitem =
CountGadgetItems(TreeGadget)-
1
maxlevel =
0
For
clevel =
0
To
maxlevel
For
i=
0
To
lastitem-
1
nlevel =
GetGadgetItemAttribute(TreeGadget,i,#PB_Tree_SubLevel
)
If
nlevel>
maxlevel : maxlevel =
nlevel : EndIf
If
nlevel =
clevel
min=
i
For
j=
i+
1
To
lastitem
If
GetGadgetItemText(TreeGadget,j)<
GetGadgetItemText(TreeGadget,min) And
GetGadgetItemAttribute(TreeGadget,j,#PB_Tree_SubLevel
)=
clevel
min=
j
EndIf
If
GetGadgetItemAttribute(TreeGadget,j,#PB_Tree_SubLevel
)<
nlevel
j =
lastitem
EndIf
Next
If
min<>
i
For
b =
1
To
2
storeitems$ =
""
If
b =
1
posd =
i
Else
posd =
min
EndIf
; Store the node content
ct =
1
While
GetGadgetItemAttribute(TreeGadget,posd+
ct,#PB_Tree_SubLevel
)>
clevel
storeitems$ +
GetGadgetItemText(TreeGadget,posd+
ct)+
Chr(13
)+
Str(GetGadgetItemAttribute(TreeGadget,posd+
ct,#PB_Tree_SubLevel
))+
Chr(13
)+
Str(GetTreeItemIconIndex(TreeGadget,GadgetItemID(TreeGadget,posd+
ct)))+
Chr(13
)
ct +
1
If
b =
1
And
min>
i
min -
1
EndIf
If
b =
2
And
i>
min
i -
1
EndIf
Wend
If
b =
1
storeitems_i$ =
storeitems$
Else
storeitems_min$ =
storeitems$
EndIf
; Delete the node content
While
GetGadgetItemAttribute(TreeGadget,posd+
1
,#PB_Tree_SubLevel
)>
clevel
RemoveGadgetItem(TreeGadget,posd+
1
)
Wend
Next
; recreate the node content at the right place
For
b =
1
To
2
If
b =
1
posi =
min
storeitems$ =
storeitems_i$
Else
posi =
i
storeitems$ =
storeitems_min$
EndIf
ct =
0
Repeat
ct +
1
itemtext$ =
StringField(storeitems$,ct,Chr(13
))
If
itemtext$
ct +
1
level =
Val(StringField(storeitems$,ct,Chr(13
)))
ct +
1
iconindex =
Val(StringField(storeitems$,ct,Chr(13
)))
posi +
1
AddGadgetItem(TreeGadget,posi,itemtext$,0
,level)
SetTreeItemIconIndex(TreeGadget,GadgetItemID(TreeGadget,posi),iconindex)
If
b =
1
And
i>
min
i +
1
EndIf
If
b =
2
And
min>
i
min +
1
EndIf
EndIf
Until
itemtext$ =
""
Next
InvertTreeGadgetItems(TreeGadget,i,min)
EndIf
EndIf
Next
Next
SetGadgetState(TreeGadget,0
)
SetGadgetText(ItemString,GetGadgetText(TreeGadget))
SendMessage_(GadgetID(ItemString), #EM_SETSEL
, 0
, Len(GetGadgetText(TreeGadget)))
SetActiveGadget(ItemString)
EndIf
EndIf
Until
Event =
#PB_Event_CloseWindow
End
Cette solution bien que moins complète que celle-ci, a l'avantage d'être multi-plateforme (Windows, Linux, Mac OS).
; ------------------------------------------------------------------
;
; Example for Drag & Drop inside a TreeGadget to reorder items.
;
; Requires 4.10 beta or newer to run
;
; ------------------------------------------------------------------
#Tree
=
0
#Window
=
0
; If you want to do multiple drag&drop in different Gadgets of your program,
; you can use different values here so the events do not collide.
; (ie so the user cannot drag to the wrong gadget)
#PrivateType
=
0
If
OpenWindow(#Window
, 0
, 0
, 300
, 500
, "TreeGadget Drag & Drop"
, #PB_Window_ScreenCentered
|
#PB_Window_SystemMenu
)
CreateGadgetList(WindowID(#Window
))
TreeGadget(#Tree
, 10
, 10
, 280
, 480
)
; Add some items. We will be able to move items into the
; "Directory" ones.
;
For
i =
0
To
20
If
i % 5
=
0
AddGadgetItem(#Tree
, -
1
, "Directory"
+
Str(i), 0
, 0
)
Else
AddGadgetItem(#Tree
, -
1
, "Item"
+
Str(i), 0
, 0
)
EndIf
Next
i
; this enables dropping our private type with a move operation
EnableGadgetDrop(#Tree
, #PB_Drop_Private
, #PB_Drag_Move
, #PrivateType
)
Repeat
Event =
WaitWindowEvent()
If
Event =
#PB_Event_Gadget
;
; The DragStart event tells us that the user clicked on an item and
; wants to start draging it. We save this item for later use and
; start our private drag
;
If
EventGadget() =
#Tree
And
EventType() =
#PB_EventType_DragStart
SourceItem =
GetGadgetState(#Tree
)
DragPrivate(#PrivateType
, #PB_Drag_Move
)
EndIf
ElseIf
Event =
#PB_Event_GadgetDrop
;
; Here we get a drop event. Make sure it is on the right gadget and of right type,
; especially if you have multiple Drag & Drop stuff in your program.
;
If
EventGadget() =
#Tree
And
EventDropType() =
#PB_Drop_Private
And
EventDropPrivate() =
#PrivateType
TargetItem =
GetGadgetState(#Tree
)
; nothing to do if source and target are equal
;
If
SourceItem <>
TargetItem
; Find out to which index and sublevel to move the item
;
If
TargetItem =
-
1
; if dropped on the empty area, append at the end
TargetItem =
CountGadgetItems(#Tree
)
TargetLevel =
0
ElseIf
Left(GetGadgetItemText(#Tree
, TargetItem), 4
) =
"Item"
; if dropped on an "Item", move right after this item
TargetLevel =
GetGadgetItemAttribute(#Tree
, TargetItem, #PB_Tree_SubLevel
)
TargetItem +
1
Else
; if dropped on a "Directory", move into the directory and to the end of it
; all this can be easily done by examining the sublevel
TargetLevel =
GetGadgetItemAttribute(#Tree
, TargetItem, #PB_Tree_SubLevel
) +
1
TargetItem +
1
While
GetGadgetItemAttribute(#Tree
, TargetItem, #PB_Tree_SubLevel
) >=
TargetLevel
TargetItem +
1
Wend
EndIf
; Find out how many children our source item has, as we want to
; move them all. If you do not allow moving of directory nodes, it gets
; much simpler as there is only one delete + add then.
;
; childnodes are all directly following ones with a higher level
;
SourceLevel =
GetGadgetItemAttribute(#Tree
, SourceItem, #PB_Tree_SubLevel
)
ChildCount =
0
For
i =
SourceItem+
1
To
CountGadgetItems(#Tree
)-
1
If
GetGadgetItemAttribute(#Tree
, i, #PB_Tree_SubLevel
) >
SourceLevel
ChildCount +
1
Else
Break
EndIf
Next
i
; Note: because by adding new items, the index of our old ones changes,
; we need to make a distinction here wether we move before or after our old item.
; Note also that we cannot move an item into one of its childs, which we
; prevent by this check as well.
;
; We copy first the source item and all children to the new location and then
; delete the source item.
;
If
TargetItem >
SourceItem +
ChildCount +
1
;
; The target index is higher than the source one, so the source items are not
; affected by adding the new items in this case...
;
For
i =
0
To
ChildCount
; copy everything here (also colors and GetGadgetItemData() etc if you use that)
Text$ =
GetGadgetItemText(#Tree
, SourceItem+
i)
Level =
GetGadgetItemAttribute(#Tree
, SourceItem+
i, #PB_Tree_SubLevel
) -
SourceLevel +
TargetLevel
AddGadgetItem(#Tree
, TargetItem+
i, Text$, 0
, Level)
Next
i
; We apply the state of each item AFTER all items are copied.
; This must be in a separate loop, as else the "expanded" state of the items is
; not preserved, as the childs were not added yet in the above loop.
For
i =
0
To
ChildCount
SetGadgetItemState(#Tree
, TargetItem+
i, GetGadgetItemState(#Tree
, SourceItem+
i))
Next
i
; remove the source item. This automatically removes all children as well.
RemoveGadgetItem(#Tree
, SourceItem)
; select the target. Note that the index is now 'ChildCount+1' less
; because of the remove of the source which was before the target
SetGadgetState(#Tree
, TargetItem-
ChildCount-
1
)
ElseIf
TargetItem <=
SourceItem
;
; Second case: Target is lower than source. This means that each time
; we add a target item, the source items index increases by 1 as well,
; this is why we read the source items with the "SourceItem+i*2"
;
For
i =
0
To
ChildCount
Text$ =
GetGadgetItemText(#Tree
, SourceItem+
i*
2
)
Level =
GetGadgetItemAttribute(#Tree
, SourceItem+
i*
2
, #PB_Tree_SubLevel
) -
SourceLevel +
TargetLevel
AddGadgetItem(#Tree
, TargetItem+
i, Text$, 0
, Level)
Next
i
; Loop for the states. Note that here the index of the sourceitems is
; 'ChildCount+1' higher than before because of the added targets
;
For
i =
0
To
ChildCount
SetGadgetItemState(#Tree
, TargetItem+
i, GetGadgetItemState(#Tree
, SourceItem+
ChildCount+
1
+
i))
Next
i
; remove source and select target. Here the target index is not affected by the remove as it is lower
RemoveGadgetItem(#Tree
, SourceItem+
ChildCount+
1
)
SetGadgetState(#Tree
, TargetItem)
EndIf
EndIf
EndIf
EndIf
Until
Event =
#PB_Event_CloseWindow
EndIf
End
Un petit code qui permet de déplacer des éléments dans un TreeGadget.
4 boutons pour :
- Déplacer vers le haut
- Déplacer vers le bas
- Augmenter le niveau
- Diminuer le niveau
Déplacement des éléments par glisser déposer :
- Diminuer le niveau en déplaçant l'élément vers la gauche
- Augmenter le niveau en déplaçant l'élément vers la droite
- Déplacer l'élément vers le haut ou le bas
Quand on déplace ou change le niveau d'un élément, tous les enfants de l'élément sont également déplacer.
Le TreeGadget doit être rempli à partir d'une Liste.
Le code est portable, il suffit de supprimer les 2 APIs lockWindowUpdate_() qui ne servent qu'à éviter le clignotement du TreeGadget lors du remplissage avec les éléments.
; Auteur : Le Soldat Inconnu
; Version de PB : 4.50
;
; Explication du programme :
; Arbre modifiable
Structure
ArbreInfo
Nom.s
Niveau.l
Pliage.l
EndStructure
Global
NewList
Arbre.ArbreInfo()
#Arbre
=
0
#Fenetre
=
0
#Arbre_DragDrop_Deplacer
=
0
Global
DragDrop_Start, DragDrop_Start_X
Procedure
Arbre_Pliage()
ForEach
Arbre()
If
GetGadgetItemState(#Arbre
, ListIndex(Arbre())) &
#PB_Tree_Expanded
Arbre()\Pliage =
1
Else
Arbre()\Pliage =
0
EndIf
Next
EndProcedure
Procedure
Arbre_Niveau_Correction()
Niveau =
0
ForEach
Arbre()
If
Arbre()\Niveau >
Niveau +
1
Arbre()\Niveau =
Niveau +
1
EndIf
If
Arbre()\Niveau <
0
Arbre()\Niveau =
0
EndIf
Niveau =
Arbre()\Niveau
Next
EndProcedure
Procedure
Arbre_Remplir(Position =
-
1
)
LockWindowUpdate_(WindowID(0
))
ClearGadgetItems(#Arbre
)
ForEach
Arbre()
AddGadgetItem(#Arbre
, -
1
, Arbre()\Nom, 0
, Arbre()\Niveau)
If
Pliage
SetGadgetItemState(#Arbre
, ListIndex(Arbre()) -
1
, #PB_Tree_Expanded
)
EndIf
Pliage =
Arbre()\Pliage
Next
If
Position >=
0
SetGadgetState(#Arbre
, Position)
EndIf
LockWindowUpdate_(0
)
EndProcedure
Procedure
Arbre_Deplacer(Position, Mouvement)
Protected
PositionFinale, *
Deplacer1.ArbreInfo, *
Deplacer2.ArbreInfo
Arbre_Pliage()
If
Position >=
0
; Vérification
If
Position +
Mouvement <
0
Mouvement =
-
Position
EndIf
If
Position +
Mouvement >=
ListSize(Arbre())
Mouvement =
ListSize(Arbre()) -
1
-
Position
EndIf
; Evolution du niveau entre le départ et l'arrivée
SelectElement(Arbre(), Position)
Niveau =
Arbre()\Niveau
SelectElement(Arbre(), Position +
Mouvement)
Evolution =
Arbre()\Niveau -
Niveau
If
NextElement(Arbre())
If
Arbre()\Niveau >
Niveau +
Evolution
Evolution +
1
EndIf
EndIf
; Position finale
PositionFinale =
Position +
Mouvement
; Nombre d'élément à déplacer (Regarde le nombre d'enfants à déplacer)
SelectElement(Arbre(), Position)
Suivant =
0
While
NextElement(Arbre())
If
Arbre()\Niveau <=
Niveau
Break
EndIf
Suivant +
1
Wend
If
Mouvement >
0
And
Position +
Suivant >
PositionFinale
Suivant =
0
; Si le déplacement se fait dans un élément enfant, on ne déplace pas les enfants
EndIf
; Déplacement
Repeat
SelectElement(Arbre(), Position)
If
Mouvement >
0
For
i =
1
To
Mouvement
*
Deplacer1 =
@Arbre()
NextElement(Arbre())
*
Deplacer2 =
@Arbre()
SwapElements(Arbre(), *
Deplacer1, *
Deplacer2)
ChangeCurrentElement(Arbre(), *
Deplacer1)
Next
ElseIf
Mouvement <
0
For
i =
1
To
-
Mouvement
*
Deplacer1 =
@Arbre()
PreviousElement(Arbre())
*
Deplacer2 =
@Arbre()
SwapElements(Arbre(), *
Deplacer1, *
Deplacer2)
ChangeCurrentElement(Arbre(), *
Deplacer1)
Next
Position +
1
EndIf
Arbre()\Niveau +
Evolution
Suivant -
1
Until
Suivant <
0
Arbre_Niveau_Correction()
Arbre_Remplir(PositionFinale)
EndIf
EndProcedure
Procedure
Arbre_Niveau(Position, Evolution)
Arbre_Pliage()
If
Position >=
0
SelectElement(Arbre(), Position)
Niveau =
Arbre()\Niveau
; Vérification
If
Niveau +
Evolution <
0
Evolution =
-
Niveau
EndIf
If
Evolution >
0
If
PreviousElement(Arbre())
If
Niveau +
Evolution >
Arbre()\Niveau +
1
Evolution =
Arbre()\Niveau +
1
-
Niveau
EndIf
NextElement(Arbre())
EndIf
EndIf
; Correction du pliage de l'arbre
If
Evolution >
0
If
PreviousElement(Arbre())
Arbre()\Pliage =
1
NextElement(Arbre())
EndIf
EndIf
If
Evolution <
0
If
NextElement(Arbre())
If
Arbre()\Niveau =
Niveau
PreviousElement(Arbre())
Arbre()\Pliage =
1
Else
PreviousElement(Arbre())
EndIf
EndIf
EndIf
; Change le niveau
Arbre()\Niveau +
Evolution
While
NextElement(Arbre())
If
Arbre()\Niveau <=
Niveau
Break
EndIf
Arbre()\Niveau +
Evolution
Wend
Arbre_Niveau_Correction()
Arbre_Remplir(Position)
EndIf
EndProcedure
Procedure
Arbre_GlisserDeposer()
Protected
DragDrop_X, DragDrop_End
DragDrop_End =
GetGadgetState(#Arbre
)
If
DragDrop_End =
-
1
DragDrop_End =
CountGadgetItems(#Arbre
) -
1
EndIf
DragDrop_X =
WindowMouseX(#Fenetre
) -
DragDrop_Start_X
If
DragDrop_End =
DragDrop_Start
; On change le niveau de l'élément
If
DragDrop_X >
8
Arbre_Niveau(DragDrop_Start, 1
)
ElseIf
DragDrop_X <
-
8
Arbre_Niveau(DragDrop_Start, -
1
)
EndIf
Else
; On déplace l'élément
Arbre_Deplacer(DragDrop_Start, DragDrop_End -
DragDrop_Start)
EndIf
EndProcedure
; Création de la fenêtre et de la GadgetList
If
OpenWindow(#Fenetre
, 0
, 0
, 500
, 500
, "Arbre"
, #PB_Window_SystemMenu
|
#PB_Window_ScreenCentered
|
#PB_Window_MinimizeGadget
) =
0
End
EndIf
TreeGadget(#Arbre
, 0
, 0
, 300
, 500
, #PB_Tree_AlwaysShowSelection
)
EnableGadgetDrop(#Arbre
, #PB_Drop_Private
, #PB_Drag_Move
, #Arbre_DragDrop_Deplacer
)
ButtonGadget(1
, 300
, 0
, 200
, 30
, "Monter"
)
ButtonGadget(2
, 300
, 30
, 200
, 30
, "Descendre"
)
ButtonGadget(3
, 300
, 60
, 200
, 30
, "Niveau +"
)
ButtonGadget(4
, 300
, 90
, 200
, 30
, "Niveau -"
)
; Remplissage de l'arbre
For
i =
1
To
20
AddElement(Arbre())
Arbre()\Nom =
"Elément "
+
Str(i)
Next
Arbre_Remplir()
Repeat
Event =
WaitWindowEvent()
Select
Event
Case
#PB_Event_Gadget
Position =
GetGadgetState(#Arbre
)
Select
EventGadget() ; Gadgets
Case
#Arbre
Select
EventType()
Case
#PB_EventType_DragStart
; Glisser déposer
DragDrop_Start =
Position
DragDrop_Start_X =
WindowMouseX(#Fenetre
)
DragPrivate(#Arbre_DragDrop_Deplacer
, #PB_Drag_Move
)
EndSelect
Case
1
Arbre_Deplacer(Position, -
1
)
Case
2
Arbre_Deplacer(Position, 1
)
Case
3
Arbre_Niveau(Position, 1
)
Case
4
Arbre_Niveau(Position, -
1
)
EndSelect
Case
#PB_Event_GadgetDrop
; Opération de glisser déposer
Select
EventGadget()
Case
#Arbre
Position =
GetGadgetState(#Arbre
)
Select
EventDropType()
Case
#PB_Drop_Private
Select
EventDropPrivate()
Case
#Arbre_DragDrop_Deplacer
Arbre_GlisserDeposer()
EndSelect
EndSelect
EndSelect
EndSelect
Until
Event =
#PB_Event_CloseWindow