Page 1 of 1

How to drag & drop rows in ListIcon ?

Posted: Tue Mar 20, 2012 11:27 pm
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 ...

Re: How to drag & drop rows in ListIcon ?

Posted: Wed Mar 21, 2012 12:57 am
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.

Re: How to drag & drop rows in ListIcon ?

Posted: Wed Mar 21, 2012 1:21 am
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

Re: How to drag & drop rows in ListIcon ?

Posted: Wed Mar 21, 2012 1:24 am
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.

Re: How to drag & drop rows in ListIcon ?

Posted: Wed Mar 21, 2012 1:54 am
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

Re: How to drag & drop rows in ListIcon ?

Posted: Wed Mar 21, 2012 10:35 am
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


Re: How to drag & drop rows in ListIcon ?

Posted: Wed Mar 21, 2012 11:36 am
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

Re: How to drag & drop rows in ListIcon ?

Posted: Wed Mar 21, 2012 4:32 pm
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.)

Re: How to drag & drop rows in ListIcon ?

Posted: Wed Mar 21, 2012 4:50 pm
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:

Re: How to drag & drop rows in ListIcon ?

Posted: Wed Mar 21, 2012 5:02 pm
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.

Re: How to drag & drop rows in ListIcon ?

Posted: Wed Mar 21, 2012 9:16 pm
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


Re: How to drag & drop rows in ListIcon ?

Posted: Wed Mar 21, 2012 10:39 pm
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

Re: How to drag & drop rows in ListIcon ?

Posted: Thu Mar 22, 2012 9:15 am
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

Re: How to drag & drop rows in ListIcon ?

Posted: Thu Mar 22, 2012 4:22 pm
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.

Re: How to drag & drop rows in ListIcon ?

Posted: Tue May 14, 2013 1:51 pm
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