How to drag & drop rows in ListIcon ?

Just starting out? Need help? Post your questions and find answers here.
swan
Enthusiast
Enthusiast
Posts: 225
Joined: Sat Jul 03, 2004 9:04 am
Location: Sydney Australia
Contact:

How to drag & drop rows in ListIcon ?

Post by swan »

I have a project where I need to store a sequential material list. I've used a ListIcon to do this, and because it's a sequential list it will never need sorting. However I will need the facility to manually make order adjustments, eg, drag & drop a row up or down on the list. At the moment I have a up & down button that send the row up or down one, but a drag & drop facility would be much more efficient.

Have done a search and notice srod has provided examples but unfortunately the links are broken (get well soon srod) :)
Any pointers or links would be much appreciated ...
User avatar
Tenaja
Addict
Addict
Posts: 1959
Joined: Tue Nov 09, 2010 10:15 pm

Re: How to drag & drop rows in ListIcon ?

Post by Tenaja »

There is a ListIconGadget() example with drag & drop in the Help file. (Search help for DragDrop.pb ) It is also posted here:
http://purebasic.fr/english/viewtopic.p ... +drag+drop

If you have row moving with the keyboard, this example should get you going.
swan
Enthusiast
Enthusiast
Posts: 225
Joined: Sat Jul 03, 2004 9:04 am
Location: Sydney Australia
Contact:

Re: How to drag & drop rows in ListIcon ?

Post by swan »

Thanx Tenaja, yes I've seen that. However it's for the drag/drop lib which is handy for drag/dropping between gadgets. My project needs to drag/drop on the same ListIcon gadget (manually changing row order) ... :D
User avatar
Tenaja
Addict
Addict
Posts: 1959
Joined: Tue Nov 09, 2010 10:15 pm

Re: How to drag & drop rows in ListIcon ?

Post by Tenaja »

Filled with curiosity, I played with it until I got it working. It is just a quick & dirty solution--to delete the original text, I put it in variable StartPosition for removal. If there is a way to remove it without that var, then please post it.

Code: Select all

;	started from PB's HELP File, modified to allow drop in both directions,
; 		including upon starting gadget.
;	
;



#Window = 0

Enumeration    ; Images
  #ImageSource
  #ImageTarget
EndEnumeration

Enumeration    ; Gadgets
  #SourceText
  #SourceImage
  #SourceFiles
  #SourcePrivate
  #TargetText
  #TargetImage
  #TargetFiles
  #TargetPrivate1
  #TargetPrivate2
EndEnumeration



If OpenWindow(#Window, 0, 0, 760, 310, "Drag & Drop", #PB_Window_SystemMenu|#PB_Window_ScreenCentered)
 
 
  ; Create and fill the source gadgets
  ;
  ListIconGadget(#SourceText,       10, 10, 140, 140, "Drag Text here", 130)   
  ListIconGadget(#SourcePrivate,   610, 10, 140, 140, "Drag private stuff here", 260)
     
      AddGadgetItem(#SourceText, -1, "1 hello world")
      AddGadgetItem(#SourceText, -1, "2 The quick brown fox jumped over the lazy dog")
      AddGadgetItem(#SourceText, -1, "3 abcdefg")
      AddGadgetItem(#SourceText, -1, "4 123456789")
     
      AddGadgetItem(#SourcePrivate, -1, "Private type 1")
      AddGadgetItem(#SourcePrivate, -1, "Private type 2")
 

  ; Create the target gadgets
  ;
  ListIconGadget(#TargetText,  10, 160, 140, 140, "Drop Text here", 130)
  ListIconGadget(#TargetPrivate1, 460, 160, 140, 140, "Drop Private Type 1 here", 130)
  ListIconGadget(#TargetPrivate2, 610, 160, 140, 140, "Drop Private Type 2 here", 130)

 
  ; Now enable the dropping on the target gadgets
  ;
  
  EnableGadgetDrop(#SourceText,     #PB_Drop_Text,    #PB_Drag_Move | #PB_Drag_Copy)     ;this is new
  
  EnableGadgetDrop(#TargetText,     #PB_Drop_Text,    #PB_Drag_Copy)
  EnableGadgetDrop(#TargetPrivate1, #PB_Drop_Private, #PB_Drag_Copy, 1)
  EnableGadgetDrop(#TargetPrivate2, #PB_Drop_Private, #PB_Drag_Copy, 2)

  Repeat
    Event = WaitWindowEvent()
   
    ; DragStart event on the source gadgets, initiate a drag & drop
    ;
    If Event = #PB_Event_Gadget And EventType() = #PB_EventType_DragStart
      Select EventGadget()
     
      	Case #TargetText
          Text$ = GetGadgetItemText(#TargetText, GetGadgetState(#TargetText))
          DragText(Text$)
     
        Case #SourceText     ;this is new.
      	  StartPosition = GetGadgetState(#SourceText)
          Text$ = GetGadgetItemText(#SourceText, StartPosition)
          DragText(Text$)
       
        ; "Private" Drags only work within the program, everything else
        ; also works with other applications (Explorer, Word, etc)
        ;
        Case #SourcePrivate
          If GetGadgetState(#SourcePrivate) = 0
            DragPrivate(1)
          Else
            DragPrivate(2)
          EndIf
             
      EndSelect
   
    ; Drop event on the target gadgets, receive the dropped data
    ;
    ElseIf Event = #PB_Event_GadgetDrop
      Select EventGadget()
     
        Case #SourceText      ; this is heavily edited.
          temp=GetGadgetState(#SourceText)
          RemoveGadgetItem(#SourceText, StartPosition)    ; Is there a way to do this all within this CASE statement, no StartPosition var?
          AddGadgetItem(#SourceText, GetGadgetState(#SourceText), EventDropText())
     
        Case #TargetText
          AddGadgetItem(#TargetText, GetGadgetState(#TargetText), EventDropText())
       
        Case #TargetPrivate1
          AddGadgetItem(#TargetPrivate1, -1, "Private type 1 dropped")
               
        Case #TargetPrivate2
          AddGadgetItem(#TargetPrivate2, -1, "Private type 2 dropped")
       
      EndSelect
   
    EndIf
   
  Until Event = #PB_Event_CloseWindow
EndIf

End
By the way, if you have been working with ListIcons, do you know how to tell what order the columns are in, and which column the mouse is over? I have only limited time on them, but could only get the first column information. Thanks.
User avatar
Tenaja
Addict
Addict
Posts: 1959
Joined: Tue Nov 09, 2010 10:15 pm

Re: How to drag & drop rows in ListIcon ?

Post by Tenaja »

Here is a smaller version without the Private samples, but still two ListIcon boxes. I added a few edits; the StartPosition requires initialization, as well as a reset with every drop following the DragStart. (You could put the reset after the EndSelect, but I didn't, in case you have other drop events.

Code: Select all

#Window = 0

Enumeration    ; Gadgets
	#SourceText
	#TargetText
EndEnumeration

If OpenWindow(#Window, 0, 0, 400, 320, "Drag & Drop", #PB_Window_SystemMenu|#PB_Window_ScreenCentered)
	
	; Create and fill a resortable source gadgets
	ListIconGadget(#SourceText,       10, 10, 140, 300, "Drag Text here", 130)   
	
	AddGadgetItem(#SourceText, -1, "1 hello world")
	AddGadgetItem(#SourceText, -1, "2 The quick brown fox jumped over the lazy dog")
	AddGadgetItem(#SourceText, -1, "3 abcdefg")
	AddGadgetItem(#SourceText, -1, "4 123456789")
	
	; Create a target gadget
	ListIconGadget(#TargetText,  210, 10, 140, 300, "Drop Text here", 130)
	
	; Now enable the dropping on the target gadgets
	EnableGadgetDrop(#SourceText,     #PB_Drop_Text,    #PB_Drag_Move | #PB_Drag_Copy)
	EnableGadgetDrop(#TargetText,     #PB_Drop_Text,    #PB_Drag_Copy)
	
	StartPosition = -1
	
	
	Repeat
		Event = WaitWindowEvent()
		
		; DragStart event on the source gadgets, initiate a drag & drop
		If Event = #PB_Event_Gadget And EventType() = #PB_EventType_DragStart
			Select EventGadget()
					Case #TargetText
							Text$ = GetGadgetItemText(#TargetText, GetGadgetState(#TargetText))
							DragText(Text$)
					Case #SourceText
							StartPosition = GetGadgetState(#SourceText)
							Text$ = GetGadgetItemText(#SourceText, StartPosition)
							DragText(Text$)
			EndSelect
			
		; Drop event on the target gadgets, receive the dropped data
		ElseIf Event = #PB_Event_GadgetDrop
			Select EventGadget()
					Case #SourceText
							If StartPosition > -1
								RemoveGadgetItem(#SourceText, StartPosition)
							EndIf
							AddGadgetItem(#SourceText, GetGadgetState(#SourceText), EventDropText())
							StartPosition = -1
					Case #TargetText
							AddGadgetItem(#TargetText, GetGadgetState(#TargetText), EventDropText())
							StartPosition = -1
			EndSelect
			
		EndIf
		
	Until Event = #PB_Event_CloseWindow
EndIf

End
srod
PureBasic Expert
PureBasic Expert
Posts: 10589
Joined: Wed Oct 29, 2003 4:35 pm
Location: Beyond the pale...

Re: How to drag & drop rows in ListIcon ?

Post by srod »

Here is one which scrolls the target listicon if required (Windows only).

Code: Select all

Declare.i DragCallBack(Action)

OpenWindow(0,0,0,480,400,"",#PB_Window_ScreenCentered|#PB_Window_SystemMenu) 
ListIconGadget(0,20,20,200,300,"Drag from", 195, #PB_ListIcon_FullRowSelect) 
ListIconGadget(1,250,20,200,300,"Drag to", 195, #PB_ListIcon_FullRowSelect) 

For i = 0 To 99
  AddGadgetItem(0, -1, "Row "+Str(i)) 
  AddGadgetItem(1, -1, "Row "+Str(i)) 
Next

EnableGadgetDrop(1,#PB_Drop_Text, #PB_Drag_Copy) 

Repeat 
  eventID = WaitWindowEvent() 
  Select eventID 
    Case #PB_Event_GadgetDrop 
      If EventGadget() =1
        AddGadgetItem(EventGadget(), GetGadgetState(EventGadget()), EventDropText()) 
      EndIf
    Case #PB_Event_Gadget 
      If EventType() = #PB_EventType_DragStart  And EventGadget()=0
        dragrow = GetGadgetState(EventGadget()) 
        dragtxt.s = GetGadgetItemText(EventGadget(), dragrow) 
        draggadget = EventGadget() 
        SetDragCallback(@DragCallBack())
        DragText(dragtxt, #PB_Drag_Copy) 
      EndIf 
 EndSelect 
Until eventID = #PB_Event_CloseWindow 


Procedure.i DragCallBack(Action)
  Protected pt.POINT, rc.RECT
  GetCursorPos_(pt)
  GetWindowRect_(GadgetID(1), rc)
  If PtInRect_(rc, pt\x + pt\y<<32)
    ;Check if the underlying listicon requires scrolling.
      MapWindowPoints_(0,GadgetID(1),pt,1)
      If pt\y <=20  ;Change 20 to match the header height.
        top = SendMessage_(GadgetID(1), #LVM_GETTOPINDEX, 0, 0)
        If top ;Scroll up.
          SendMessage_(GadgetID(1), #LVM_ENSUREVISIBLE, top-1, 0)
          UpdateWindow_(GadgetID(1))          
        EndIf
      ElseIf pt\y>=GadgetHeight(1)-GetSystemMetrics_(#SM_CYHSCROLL)-4
        top = SendMessage_(GadgetID(1), #LVM_GETTOPINDEX, 0, 0)+SendMessage_(GadgetID(1), #LVM_GETCOUNTPERPAGE, 0, 0)
        If top<=CountGadgetItems(1) ;Scroll down.
          SendMessage_(GadgetID(1), #LVM_ENSUREVISIBLE, top, 0)
          UpdateWindow_(GadgetID(1))          
        EndIf
      EndIf
  EndIf
  ProcedureReturn #True
EndProcedure

I may look like a mule, but I'm not a complete ass.
swan
Enthusiast
Enthusiast
Posts: 225
Joined: Sat Jul 03, 2004 9:04 am
Location: Sydney Australia
Contact:

Re: How to drag & drop rows in ListIcon ?

Post by swan »

Thanx heaps guys. They work just great.
I didn't know ya could assign the same gadget for both drag & drop using the lib. Me being lazy for not trying !
Thanx srod for the nudge scroll routine ...
:D :D :D
User avatar
Tenaja
Addict
Addict
Posts: 1959
Joined: Tue Nov 09, 2010 10:15 pm

Re: How to drag & drop rows in ListIcon ?

Post by Tenaja »

srod wrote:Here is one which scrolls the target listicon if required (Windows only).
srod, I am just curious, why are you using PB if you are using Win-only commands? The only reason I chose PB was because of its cross-platform ability, but it seems that a majority of the users (just as in OS use) code for Windows only. Surely your sample could be done with OS-independent PB commands?

(BTW, glad to see you feeling well enough to return.)
srod
PureBasic Expert
PureBasic Expert
Posts: 10589
Joined: Wed Oct 29, 2003 4:35 pm
Location: Beyond the pale...

Re: How to drag & drop rows in ListIcon ?

Post by srod »

I continue to use PB because I like it and it continues to serve my needs at this time. :) Cross-platform is completely irrelevant at this point as far as I am concerned. That will probably change with the advent of MacOSX Cocoa support though.

I wish to write an app for Android very soon and will obviously use a different tool for that.

I know of no way of achieving the drag-scroll using just PB commands without dipping into API. I am sure Rashad will find a way though! :wink:
I may look like a mule, but I'm not a complete ass.
User avatar
Tenaja
Addict
Addict
Posts: 1959
Joined: Tue Nov 09, 2010 10:15 pm

Re: How to drag & drop rows in ListIcon ?

Post by Tenaja »

srod wrote:I know of no way of achieving the drag-scroll using just PB commands without dipping into API. I am sure Rashad will find a way though! :wink:
I did a quick test, and SetGadgetState(0, GetGadgetState(0) + 1) forces a scroll IF the selected item is at the bottom of the window. (Use -1 for scrolling up.) AFAIK, there is no way to know which items are visible. (Hence my other recent post inquiring about a similar topic.)

One could, in theory, force a start at the beginning, but that would be tedious on the user if the Lists are long.
RASHAD
PureBasic Expert
PureBasic Expert
Posts: 4946
Joined: Sun Apr 12, 2009 6:27 am

Re: How to drag & drop rows in ListIcon ?

Post by RASHAD »

Drag and Drop to the same ListIcon() as per the ques.
Code by infratec (Berned)

Code: Select all

Procedure ListIconGadgetColumns(GadgetNo)
i = 0
While GetGadgetItemAttribute(GadgetNo, 0, #PB_ListIcon_ColumnWidth, i) > 0
  i + 1
Wend
ProcedureReturn i
EndProcedure

Procedure ListIconGadgetMove(GadgetNo.i, Source.i, Dest.i)
Columns = ListIconGadgetColumns(GadgetNo) - 1
For j = 0 To Columns
  Source$ = GetGadgetItemText(GadgetNo, Source, j)
  If Source < Dest
   For i = Source To Dest - 1
    Help$ = GetGadgetItemText(GadgetNo, i + 1, j)
    SetGadgetItemText(GadgetNo, i, Help$, j)
   Next i
  Else
   For i = Source To Dest + 1 Step - 1
    Help$ = GetGadgetItemText(GadgetNo, i - 1, j)
    SetGadgetItemText(GadgetNo, i, Help$, j)
   Next i
  EndIf
  SetGadgetItemText(GadgetNo, i, Source$, j)
Next j
EndProcedure

OpenWindow(0, 0, 0, 600, 400, "Drag'n drop test", #PB_Window_MinimizeGadget|#PB_Window_ScreenCentered)

ListIconGadget(0, 10, 10, 580, 380, "Test 1", 150 , #PB_ListIcon_FullRowSelect|#PB_ListIcon_HeaderDragDrop)
AddGadgetColumn(0, 1, "Test 2", 150)
AddGadgetColumn(0, 2, "Test 3", 120)
AddGadgetColumn(0, 3, "Test 4", 120)
For i = 1 To 10
AddGadgetItem(0, -1, "Line " + Str(i) + " Col 1" + Chr(10) + "Line " + Str(i) + " Col 2"+  Chr(10) + "Line " + Str(i) + " Col 3" + Chr(10) + "Line " + Str(i) + " Col 4")
Next i

EnableGadgetDrop(0, #PB_Drop_Private, #PB_Drag_Move, 1)


Exit = #False
DragItem = -1

Repeat
Event = WaitWindowEvent()

Select Event
  Case #PB_Event_Gadget
   Select EventType()
    Case #PB_EventType_DragStart
     DragItem = GetGadgetState(0)
     DragPrivate(1, #PB_Drag_Move)
   EndSelect
  Case #PB_Event_GadgetDrop
   If EventDropPrivate() = 1
    TargetItem = GetGadgetState(0)
    ListIconGadgetMove(0, DragItem, TargetItem)
   EndIf
  Case #PB_Event_CloseWindow
   Exit = #True
EndSelect

Until Exit

Egypt my love
User avatar
Tenaja
Addict
Addict
Posts: 1959
Joined: Tue Nov 09, 2010 10:15 pm

Re: How to drag & drop rows in ListIcon ?

Post by Tenaja »

This is a little more elegant, if you want to move all columns. These 11 lines replace the two procedures (25 lines + 2 for calls), and also keep the Titles from getting in the mix.

Code: Select all

Select EventGadget()
                   Case #SourceText
                   		If StartPosition > -1
                   			i=1
                   			 strn = EventDropText()
	                         While GetGadgetItemAttribute(#SourceText, i, #PB_ListIcon_ColumnWidth, i) > 0
	                         	Strn + Chr(10) + GetGadgetItemText(#SourceText, StartPosition, i)
	                         	i+1
	                         Wend
                            RemoveGadgetItem(#SourceText, StartPosition)
                         EndIf
                         AddGadgetItem(#SourceText, GetGadgetState(#SourceText), strn)
                         StartPosition = -1
Last edited by Tenaja on Thu Mar 22, 2012 4:17 pm, edited 1 time in total.
infratec
Always Here
Always Here
Posts: 7580
Joined: Sun Sep 07, 2008 12:45 pm
Location: Germany

Re: How to drag & drop rows in ListIcon ?

Post by infratec »

Hi,

my version, which was shown by Rashad, has one (or two) big advantage(s):

It is independend from drag'n drop.
It is a procedure which moves simply the source row to the destination row.
So you can use it also from an other part of the program.
Ok, you can combine ListIconGadgetColumns() and ListIconGadgetMove(), but since there is no
procedure available inside PB to get the colums, I thought it was a good idea to write an own
procedure for that.

Oh, the second advantage is: crossplatform :!:

Bernd
User avatar
Tenaja
Addict
Addict
Posts: 1959
Joined: Tue Nov 09, 2010 10:15 pm

Re: How to drag & drop rows in ListIcon ?

Post by Tenaja »

infratec,
How is using drag & drop a disadvantage?

My version has a few advantages, too:
Using drag & drop, it is very short
Since it uses RemoveGadget and AddGadgetItem, there are no loops to move every single line. No loop means faster response with large lists.
Also platform independent.

...but my move code could be implemented with yours to make the best of both worlds.
Ludo
User
User
Posts: 40
Joined: Thu Oct 16, 2008 12:55 pm
Location: Belgium-Tiegem

Re: How to drag & drop rows in ListIcon ?

Post by Ludo »

@srod - et all
srod wrote:Declare.i DragCallBack(Action)

OpenWindow(0,0,0,480,400,"",#PB_Window_ScreenCentered|#PB_Window_SystemMenu)
ListIconGadget(0,20,20,200,300,"Drag from", 195, #PB_ListIcon_FullRowSelect)
ListIconGadget(1,250,20,200,300,"Drag to", 195, #PB_ListIcon_FullRowSelect)

For i = 0 To 99
AddGadgetItem(0, -1, "Row "+Str(i))
AddGadgetItem(1, -1, "Row "+Str(i))
Next
I have tried to rework your example while using TreeGadget() - but that doesn't seem to work.

Is that because it is not possible at all, or is there more then just changing the list for a tree ?

Code: Select all

TreeGadget(1,250,20,200,300, #PB_ListIcon_FullRowSelect) 
Thanks,
Ludo
Post Reply