forked from capocchi/DEVSimPy
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathDragList.py
More file actions
173 lines (144 loc) · 6.33 KB
/
DragList.py
File metadata and controls
173 lines (144 loc) · 6.33 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
# -*- coding: utf-8 -*-
"""DnD demo with listctrl.
- Dragging of multiple selected items.
- Dropping on an empty list.
- Dropping of items on a list with a different number of columns.
- Dropping on a different applications."""
import pickle
import wx
# ----------------------------------------------------------------------
# ----------------------------------------------------------------------
# DragList
class DragList(wx.ListCtrl):
def __init__(self, *arg, **kw):
wx.ListCtrl.__init__(self, *arg, **kw)
self.Bind(wx.EVT_LIST_BEGIN_DRAG, self._startDrag)
dt = ListDrop(self)
self.SetDropTarget(dt)
def getItemInfo(self, idx):
"""Collect all relevant data of a listitem, and put it in a list"""
l = []
l.append(idx) # We need the original index, so it is easier to eventualy delete it
l.append(self.GetItemData(idx)) # Itemdata
l.append(self.GetItemText(idx)) # Text first column
for i in range(1, self.GetColumnCount()): # Possible extra columns
l.append(self.GetItem(idx, i).GetText())
return l
def _startDrag(self, e):
""" Put together a data object for drag-and-drop _from_ this list. """
l = []
idx = -1
while True: # find all the selected items and put them in a list
idx = self.GetNextItem(idx, wx.LIST_NEXT_ALL, wx.LIST_STATE_SELECTED)
if idx == -1:
break
l.append(self.getItemInfo(idx))
# Pickle the items list.
itemdata = pickle.dumps(l, 1)
# create our own data format and use it in a
# custom data object
ldata = wx.CustomDataObject("ListCtrlItems")
ldata.SetData(itemdata)
# Now make a data object for the item list.
data = wx.DataObjectComposite()
data.Add(ldata)
# Create drop source and begin drag-and-drop.
dropSource = wx.DropSource(self)
dropSource.SetData(data)
res = dropSource.DoDragDrop(flags=wx.Drag_DefaultMove)
# If move, we want to remove the item from this list.
if res == wx.DragMove:
# It's possible we are dragging/dropping from this list to this list. In which case, the
# index we are removing may have changed...
# Find correct position.
l.reverse() # Delete all the items, starting with the last item
for i in l:
pos = self.FindItem(i[0], i[2])
self.DeleteItem(pos)
def _insert(self, x, y, seq):
""" Insert text at given x, y coordinates --- used with drag-and-drop. """
# Find insertion point.
index, flags = self.HitTest((x, y))
if index == wx.NOT_FOUND: # not clicked on an item
if flags & (wx.LIST_HITTEST_NOWHERE|wx.LIST_HITTEST_ABOVE|wx.LIST_HITTEST_BELOW): # empty list or below last item
index = self.GetItemCount() # append to end of list
elif self.GetItemCount() > 0:
if y <= self.GetItemRect(0).y: # clicked just above first item
index = 0 # append to top of list
else:
index = self.GetItemCount() + 1 # append to end of list
else: # clicked on an item
# Get bounding rectangle for the item the user is dropping over.
rect = self.GetItemRect(index)
# If the user is dropping into the lower half of the rect, we want to insert _after_ this item.
# Correct for the fact that there may be a heading involved
if y > rect.y - self.GetItemRect(0).y + rect.height/2:
index += 1
for i in seq: # insert the item data
idx = self.InsertItem(index, i[2])
self.SetItemData(idx, i[1])
for j in range(1, self.GetColumnCount()):
try: # Target list can have more columns than source
self.SetStringItem(idx, j, i[2+j])
except:
pass # ignore the extra columns
index += 1
# ----------------------------------------------------------------------
# ----------------------------------------------------------------------
# ListDrop
class ListDrop(wx.PyDropTarget):
""" Drop target for simple lists. """
def __init__(self, source):
""" Arguments:
- source: source listctrl.
"""
wx.DropTarget.__init__(self)
self.dv = source
# specify the type of data we will accept
self.data = wx.CustomDataObject("ListCtrlItems")
self.SetDataObject(self.data)
# Called when OnDrop returns True. We need to get the data and
# do something with it.
def OnData(self, x, y, d):
# copy the data from the drag source to our data object
if self.GetData():
# convert it back to a list and give it to the viewer
ldata = self.data.GetData()
if isinstance(ldata, memoryview):
ldata = ldata.tobytes()
l = pickle.loads(ldata)
self.dv._insert(x, y, l)
# what is returned signals the source what to do
# with the original data (move, copy, etc.) In this
# case we just return the suggested value given to us.
return d
# ----------------------------------------------------------------------
# ----------------------------------------------------------------------
# main
if __name__ == '__main__':
items = ['Foo', 'Bar', 'Baz', 'Zif', 'Zaf', 'Zof']
class MyApp(wx.App):
def OnInit(self):
self.frame = wx.Frame(None, title='Main Frame')
self.frame.Show(True)
self.SetTopWindow(self.frame)
return True
app = MyApp(redirect=False)
dl1 = DragList(app.frame, style=wx.LC_LIST)
dl2 = DragList(app.frame, style=wx.LC_REPORT)
dl2.InsertColumn(0, "Column #0")
dl2.InsertColumn(1, "Column #1", wx.LIST_FORMAT_RIGHT)
dl2.InsertColumn(2, "Column #2")
sizer = wx.BoxSizer()
app.frame.SetSizer(sizer)
sizer.Add(dl1, proportion=1, flag=wx.EXPAND)
sizer.Add(dl2, proportion=1, flag=wx.EXPAND)
from random import choice
from sys import maxsize
for item in items:
dl1.InsertItem(maxint, item)
idx = dl2.InsertItem(maxint, item)
dl2.SetStringItem(idx, 1, choice(items))
dl2.SetStringItem(idx, 2, choice(items))
app.frame.Layout()
app.MainLoop()