D'n'D & Treegadget

Just starting out? Need help? Post your questions and find answers here.
User avatar
Progi1984
Addict
Addict
Posts: 806
Joined: Fri Feb 25, 2005 1:01 am
Location: France > Rennes
Contact:

D'n'D & Treegadget

Post by Progi1984 »

Hi, I search a piece of code which explains me how can I use Drag and Drop with TreeGadget for sorting differents items...

Thank you in advance...
eJan
Enthusiast
Enthusiast
Posts: 366
Joined: Sun May 21, 2006 11:22 pm
Location: Sankt Veit am Flaum

Post by eJan »

Look at Freak's Codesnippets 'TreeDrag': http://freak.purearea.net/code/code.html
freak
PureBasic Team
PureBasic Team
Posts: 5940
Joined: Fri Apr 25, 2003 5:21 pm
Location: Germany

Post by freak »

It is actually much easier now with 4.10 and the Drag & Drop library.
Here is a short example (this code is fully crossplatform)

The Drag & Drop is actually the easiest part here. What needs a bit more code
is the actual moving of the old item to the new place, because we need to move
nodes including all their children.

Run the code and drag around the items. Items named "Directory" can contain
other items.

Code: Select all

; ------------------------------------------------------------------
;
;   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
quidquid Latine dictum sit altum videtur
User avatar
Progi1984
Addict
Addict
Posts: 806
Joined: Fri Feb 25, 2005 1:01 am
Location: France > Rennes
Contact:

Post by Progi1984 »

It's exactly the code what i need...

Very thank you dear Freak !
Foz
Addict
Addict
Posts: 1359
Joined: Tue Nov 13, 2007 12:42 pm
Location: Manchester, UK

Post by Foz »

Thanks Freak, you just saved me creating a new topic asking an already answered question :lol:
User avatar
DoubleDutch
Addict
Addict
Posts: 3220
Joined: Thu Aug 07, 2003 7:01 pm
Location: United Kingdom
Contact:

Post by DoubleDutch »

I've used this example loads of times now - it's a great little routine. :D
https://deluxepixel.com <- My Business website
https://reportcomplete.com <- School end of term reports system
Klonk
Enthusiast
Enthusiast
Posts: 173
Joined: Tue Jul 13, 2004 2:17 pm

Re: D'n'D & Treegadget

Post by Klonk »

Exactly what I searched for.
Many thanks.

BTW: Works also on PB 5.60 (Just CreateGadgetList(9 has to be removed)

Just one thing: Any idea how to get it dropped at the very first position?

The only thing i can think of is: always inserting draged stuff before the item you droped on. But this does not work with directories...
Bye Karl
Klonk
Enthusiast
Enthusiast
Posts: 173
Joined: Tue Jul 13, 2004 2:17 pm

Re: D'n'D & Treegadget

Post by Klonk »

OK, one more thing is missing: Handling of item images.

BTW: Is there some way to obtain the ImageID of a Treeitem so it can be reused in Addgadgetitem?
Bye Karl
Post Reply