]>
Commit | Line | Data |
---|---|---|
1 | #---------------------------------------------------------------------------- | |
2 | # Name: GridColMover.py | |
3 | # Purpose: Grid Column Mover Extension | |
4 | # | |
5 | # Author: Gerrit van Dyk (email: gerritvd@decillion.net) | |
6 | # | |
7 | # Version 0.1 | |
8 | # Date: Nov 19, 2002 | |
9 | # RCS-ID: $Id$ | |
10 | # Licence: wxWindows license | |
11 | #---------------------------------------------------------------------------- | |
12 | # 12/07/2003 - Jeff Grimmett (grimmtooth@softhome.net) | |
13 | # | |
14 | # o 2.5 Compatability changes | |
15 | # | |
16 | # 12/18/2003 - Jeff Grimmett (grimmtooth@softhome.net) | |
17 | # | |
18 | # o wxGridColMoveEvent -> GridColMoveEvent | |
19 | # o wxGridRowMoveEvent -> GridRowMoveEvent | |
20 | # o wxGridColMover -> GridColMover | |
21 | # o wxGridRowMover -> GridRowMover | |
22 | # | |
23 | ||
24 | ||
25 | import wx | |
26 | import wx.grid | |
27 | ||
28 | #---------------------------------------------------------------------------- | |
29 | # event class and macros | |
30 | # | |
31 | # New style 12/7/03 | |
32 | # | |
33 | ||
34 | wxEVT_COMMAND_GRID_COL_MOVE = wx.NewEventType() | |
35 | wxEVT_COMMAND_GRID_ROW_MOVE = wx.NewEventType() | |
36 | ||
37 | EVT_GRID_COL_MOVE = wx.PyEventBinder(wxEVT_COMMAND_GRID_COL_MOVE, 1) | |
38 | EVT_GRID_ROW_MOVE = wx.PyEventBinder(wxEVT_COMMAND_GRID_ROW_MOVE, 1) | |
39 | ||
40 | #---------------------------------------------------------------------------- | |
41 | ||
42 | class GridColMoveEvent(wx.PyCommandEvent): | |
43 | def __init__(self, id, dCol, bCol): | |
44 | wx.PyCommandEvent.__init__(self, id = id) | |
45 | self.SetEventType(wxEVT_COMMAND_GRID_COL_MOVE) | |
46 | self.moveColumn = dCol | |
47 | self.beforeColumn = bCol | |
48 | ||
49 | def GetMoveColumn(self): | |
50 | return self.moveColumn | |
51 | ||
52 | def GetBeforeColumn(self): | |
53 | return self.beforeColumn | |
54 | ||
55 | ||
56 | class GridRowMoveEvent(wx.PyCommandEvent): | |
57 | def __init__(self, id, dRow, bRow): | |
58 | wx.PyCommandEvent.__init__(self,id = id) | |
59 | self.SetEventType(wxEVT_COMMAND_GRID_ROW_MOVE) | |
60 | self.moveRow = dRow | |
61 | self.beforeRow = bRow | |
62 | ||
63 | def GetMoveRow(self): | |
64 | return self.moveRow | |
65 | ||
66 | def GetBeforeRow(self): | |
67 | return self.beforeRow | |
68 | ||
69 | ||
70 | #---------------------------------------------------------------------------- | |
71 | # graft new methods into the wxGrid class | |
72 | ||
73 | def _ColToRect(self,col): | |
74 | if self.GetNumberRows() > 0: | |
75 | rect = self.CellToRect(0,col) | |
76 | else: | |
77 | rect = wx.Rect() | |
78 | rect.height = self.GetColLabelSize() | |
79 | rect.width = self.GetColSize(col) | |
80 | ||
81 | for cCol in range(0,col): | |
82 | rect.x += self.GetColSize(cCol) | |
83 | ||
84 | rect.y = self.GetGridColLabelWindow().GetPosition()[1] | |
85 | return rect | |
86 | ||
87 | wx.grid.Grid.ColToRect = _ColToRect | |
88 | ||
89 | ||
90 | def _RowToRect(self,row): | |
91 | if self.GetNumberCols() > 0: | |
92 | rect = self.CellToRect(row,0) | |
93 | else: | |
94 | rect = wx.Rect() | |
95 | rect.width = self.GetRowLabelSize() | |
96 | rect.height = self.GetRowSize(row) | |
97 | ||
98 | for cRow in range(0,row): | |
99 | rect.y += self.GetRowSize(cRow) | |
100 | ||
101 | rect.x = self.GetGridRowLabelWindow().GetPosition()[0] | |
102 | return rect | |
103 | ||
104 | wx.grid.Grid.RowToRect = _RowToRect | |
105 | ||
106 | ||
107 | #---------------------------------------------------------------------------- | |
108 | ||
109 | class ColDragWindow(wx.Window): | |
110 | def __init__(self,parent,image,dragCol): | |
111 | wx.Window.__init__(self,parent,-1, style=wx.SIMPLE_BORDER) | |
112 | self.image = image | |
113 | self.SetSize((self.image.GetWidth(),self.image.GetHeight())) | |
114 | self.ux = parent.GetScrollPixelsPerUnit()[0] | |
115 | self.moveColumn = dragCol | |
116 | ||
117 | self.Bind(wx.EVT_PAINT, self.OnPaint) | |
118 | ||
119 | def DisplayAt(self,pos,y): | |
120 | x = self.GetPositionTuple()[0] | |
121 | if x == pos: | |
122 | self.Refresh() # Need to display insertion point | |
123 | else: | |
124 | self.MoveXY(pos,y) | |
125 | ||
126 | def GetMoveColumn(self): | |
127 | return self.moveColumn | |
128 | ||
129 | def _GetInsertionInfo(self): | |
130 | parent = self.GetParent() | |
131 | sx = parent.GetViewStart()[0] * self.ux | |
132 | sx -= parent._rlSize | |
133 | x = self.GetPosition()[0] | |
134 | w = self.GetSize()[0] | |
135 | sCol = parent.XToCol(x + sx) | |
136 | eCol = parent.XToCol(x + w + sx) | |
137 | iPos = xPos = xCol = 99999 | |
138 | centerPos = x + sx + (w / 2) | |
139 | ||
140 | for col in range(sCol,eCol + 1): | |
141 | cx = parent.ColToRect(col)[0] | |
142 | ||
143 | if abs(cx - centerPos) < iPos: | |
144 | iPos = abs(cx - centerPos) | |
145 | xCol = col | |
146 | xPos = cx | |
147 | ||
148 | if xCol < 0 or xCol > parent.GetNumberCols(): | |
149 | xCol = parent.GetNumberCols() | |
150 | ||
151 | return (xPos - sx - x,xCol) | |
152 | ||
153 | def GetInsertionColumn(self): | |
154 | return self._GetInsertionInfo()[1] | |
155 | ||
156 | def GetInsertionPos(self): | |
157 | return self._GetInsertionInfo()[0] | |
158 | ||
159 | def OnPaint(self,evt): | |
160 | dc = wx.PaintDC(self) | |
161 | w,h = self.GetSize() | |
162 | dc.DrawBitmap(self.image, 0,0) | |
163 | dc.SetPen(wx.Pen(wx.BLACK,1,wx.SOLID)) | |
164 | dc.SetBrush(wx.TRANSPARENT_BRUSH) | |
165 | dc.DrawRectangle(0,0, w,h) | |
166 | iPos = self.GetInsertionPos() | |
167 | dc.DrawLine(iPos,h - 10, iPos,h) | |
168 | ||
169 | ||
170 | ||
171 | ||
172 | class RowDragWindow(wx.Window): | |
173 | def __init__(self,parent,image,dragRow): | |
174 | wx.Window.__init__(self,parent,-1, style=wx.SIMPLE_BORDER) | |
175 | self.image = image | |
176 | self.SetSize((self.image.GetWidth(),self.image.GetHeight())) | |
177 | self.uy = parent.GetScrollPixelsPerUnit()[1] | |
178 | self.moveRow = dragRow | |
179 | ||
180 | self.Bind(wx.EVT_PAINT, self.OnPaint) | |
181 | ||
182 | def DisplayAt(self,x,pos): | |
183 | y = self.GetPosition()[1] | |
184 | if y == pos: | |
185 | self.Refresh() # Need to display insertion point | |
186 | else: | |
187 | self.MoveXY(x,pos) | |
188 | ||
189 | def GetMoveRow(self): | |
190 | return self.moveRow | |
191 | ||
192 | def _GetInsertionInfo(self): | |
193 | parent = self.GetParent() | |
194 | sy = parent.GetViewStart()[1] * self.uy | |
195 | sy -= parent._clSize | |
196 | y = self.GetPosition()[1] | |
197 | h = self.GetSize()[1] | |
198 | sRow = parent.YToRow(y + sy) | |
199 | eRow = parent.YToRow(y + h + sy) | |
200 | iPos = yPos = yRow = 99999 | |
201 | centerPos = y + sy + (h / 2) | |
202 | ||
203 | for row in range(sRow,eRow + 1): | |
204 | cy = parent.RowToRect(row)[1] | |
205 | ||
206 | if abs(cy - centerPos) < iPos: | |
207 | iPos = abs(cy - centerPos) | |
208 | yRow = row | |
209 | yPos = cy | |
210 | ||
211 | if yRow < 0 or yRow > parent.GetNumberRows(): | |
212 | yRow = parent.GetNumberRows() | |
213 | ||
214 | return (yPos - sy - y,yRow) | |
215 | ||
216 | def GetInsertionRow(self): | |
217 | return self._GetInsertionInfo()[1] | |
218 | ||
219 | def GetInsertionPos(self): | |
220 | return self._GetInsertionInfo()[0] | |
221 | ||
222 | def OnPaint(self,evt): | |
223 | dc = wx.PaintDC(self) | |
224 | w,h = self.GetSize() | |
225 | dc.DrawBitmap(self.image, 0,0) | |
226 | dc.SetPen(wx.Pen(wx.BLACK,1,wx.SOLID)) | |
227 | dc.SetBrush(wx.TRANSPARENT_BRUSH) | |
228 | dc.DrawRectangle(0,0, w,h) | |
229 | iPos = self.GetInsertionPos() | |
230 | dc.DrawLine(w - 10,iPos, w,iPos) | |
231 | ||
232 | #---------------------------------------------------------------------------- | |
233 | ||
234 | class GridColMover(wx.EvtHandler): | |
235 | def __init__(self,grid): | |
236 | wx.EvtHandler.__init__(self) | |
237 | ||
238 | self.grid = grid | |
239 | self.grid._rlSize = self.grid.GetRowLabelSize() | |
240 | self.lwin = grid.GetGridColLabelWindow() | |
241 | self.lwin.PushEventHandler(self) | |
242 | self.colWin = None | |
243 | self.ux = self.grid.GetScrollPixelsPerUnit()[0] | |
244 | self.startX = -10 | |
245 | self.cellX = 0 | |
246 | self.didMove = False | |
247 | self.isDragging = False | |
248 | ||
249 | self.Bind(wx.EVT_MOTION, self.OnMouseMove) | |
250 | self.Bind(wx.EVT_LEFT_DOWN, self.OnPress) | |
251 | self.Bind(wx.EVT_LEFT_UP, self.OnRelease) | |
252 | ||
253 | def OnMouseMove(self,evt): | |
254 | if self.isDragging: | |
255 | if abs(self.startX - evt.m_x) >= 3 \ | |
256 | and abs(evt.m_x - self.lastX) >= 3: | |
257 | self.lastX = evt.m_x | |
258 | self.didMove = True | |
259 | sx,y = self.grid.GetViewStart() | |
260 | w,h = self.lwin.GetClientSize() | |
261 | x = sx * self.ux | |
262 | ||
263 | if (evt.m_x + x) < x: | |
264 | x = evt.m_x + x | |
265 | elif evt.m_x > w: | |
266 | x += evt.m_x - w | |
267 | ||
268 | if x < 1: x = 0 | |
269 | else: x /= self.ux | |
270 | ||
271 | if x != sx: | |
272 | if wx.Platform == '__WXMSW__': | |
273 | self.colWin.Show(False) | |
274 | ||
275 | self.grid.Scroll(x,y) | |
276 | ||
277 | x,y = self.lwin.ClientToScreenXY(evt.m_x,0) | |
278 | x,y = self.grid.ScreenToClientXY(x,y) | |
279 | ||
280 | if not self.colWin.IsShown(): | |
281 | self.colWin.Show(True) | |
282 | ||
283 | px = x - self.cellX | |
284 | ||
285 | if px < 0 + self.grid._rlSize: px = 0 + self.grid._rlSize | |
286 | ||
287 | if px > w - self.colWin.GetSize()[0] + self.grid._rlSize: | |
288 | px = w - self.colWin.GetSize()[0] + self.grid._rlSize | |
289 | ||
290 | self.colWin.DisplayAt(px,y) | |
291 | return | |
292 | ||
293 | ||
294 | def OnPress(self,evt): | |
295 | self.startX = self.lastX = evt.m_x | |
296 | sx = self.grid.GetViewStart()[0] * self.ux | |
297 | sx -= self.grid._rlSize | |
298 | px,py = self.lwin.ClientToScreenXY(evt.m_x,evt.m_y) | |
299 | px,py = self.grid.ScreenToClientXY(px,py) | |
300 | ||
301 | if self.grid.XToEdgeOfCol(px + sx) != wx.NOT_FOUND: | |
302 | evt.Skip() | |
303 | return | |
304 | ||
305 | self.isDragging = True | |
306 | self.didMove = False | |
307 | col = self.grid.XToCol(px + sx) | |
308 | rect = self.grid.ColToRect(col) | |
309 | self.cellX = px + sx - rect.x | |
310 | size = self.lwin.GetSize() | |
311 | rect.y = 0 | |
312 | rect.x -= sx + self.grid._rlSize | |
313 | rect.height = size[1] | |
314 | colImg = self._CaptureImage(rect) | |
315 | self.colWin = ColDragWindow(self.grid,colImg,col) | |
316 | self.colWin.Show(False) | |
317 | self.lwin.CaptureMouse() | |
318 | evt.Skip() | |
319 | ||
320 | def OnRelease(self,evt): | |
321 | if self.isDragging: | |
322 | self.lwin.ReleaseMouse() | |
323 | self.colWin.Show(False) | |
324 | self.isDragging = False | |
325 | ||
326 | if not self.didMove: | |
327 | px = self.lwin.ClientToScreenXY(self.startX,0)[0] | |
328 | px = self.grid.ScreenToClientXY(px,0)[0] | |
329 | sx = self.grid.GetViewStart()[0] * self.ux | |
330 | sx -= self.grid._rlSize | |
331 | col = self.grid.XToCol(px+sx) | |
332 | ||
333 | if col != wx.NOT_FOUND: | |
334 | self.grid.SelectCol(col,evt.m_controlDown) | |
335 | ||
336 | return | |
337 | else: | |
338 | bCol = self.colWin.GetInsertionColumn() | |
339 | dCol = self.colWin.GetMoveColumn() | |
340 | wx.PostEvent(self, | |
341 | GridColMoveEvent(self.grid.GetId(), dCol, bCol)) | |
342 | ||
343 | self.colWin.Destroy() | |
344 | evt.Skip() | |
345 | ||
346 | def _CaptureImage(self,rect): | |
347 | bmp = wx.EmptyBitmap(rect.width,rect.height) | |
348 | memdc = wx.MemoryDC() | |
349 | memdc.SelectObject(bmp) | |
350 | dc = wx.WindowDC(self.lwin) | |
351 | memdc.Blit(0,0, rect.width, rect.height, dc, rect.x, rect.y) | |
352 | memdc.SelectObject(wx.NullBitmap) | |
353 | return bmp | |
354 | ||
355 | ||
356 | class GridRowMover(wx.EvtHandler): | |
357 | def __init__(self,grid): | |
358 | wx.EvtHandler.__init__(self) | |
359 | ||
360 | self.grid = grid | |
361 | self.grid._clSize = self.grid.GetColLabelSize() | |
362 | self.lwin = grid.GetGridRowLabelWindow() | |
363 | self.lwin.PushEventHandler(self) | |
364 | self.rowWin = None | |
365 | self.uy = self.grid.GetScrollPixelsPerUnit()[1] | |
366 | self.startY = -10 | |
367 | self.cellY = 0 | |
368 | self.didMove = False | |
369 | self.isDragging = False | |
370 | ||
371 | self.Bind(wx.EVT_MOTION, self.OnMouseMove) | |
372 | self.Bind(wx.EVT_LEFT_DOWN, self.OnPress) | |
373 | self.Bind(wx.EVT_LEFT_UP, self.OnRelease) | |
374 | ||
375 | def OnMouseMove(self,evt): | |
376 | if self.isDragging: | |
377 | if abs(self.startY - evt.m_y) >= 3 \ | |
378 | and abs(evt.m_y - self.lastY) >= 3: | |
379 | self.lastY = evt.m_y | |
380 | self.didMove = True | |
381 | x,sy = self.grid.GetViewStart() | |
382 | w,h = self.lwin.GetClientSizeTuple() | |
383 | y = sy * self.uy | |
384 | ||
385 | if (evt.m_y + y) < y: | |
386 | y = evt.m_y + y | |
387 | elif evt.m_y > h: | |
388 | y += evt.m_y - h | |
389 | ||
390 | if y < 1: | |
391 | y = 0 | |
392 | else: | |
393 | y /= self.uy | |
394 | ||
395 | if y != sy: | |
396 | if wx.Platform == '__WXMSW__': | |
397 | self.rowWin.Show(False) | |
398 | ||
399 | self.grid.Scroll(x,y) | |
400 | ||
401 | x,y = self.lwin.ClientToScreenXY(0,evt.m_y) | |
402 | x,y = self.grid.ScreenToClientXY(x,y) | |
403 | ||
404 | if not self.rowWin.IsShown(): | |
405 | self.rowWin.Show(True) | |
406 | ||
407 | py = y - self.cellY | |
408 | ||
409 | if py < 0 + self.grid._clSize: | |
410 | py = 0 + self.grid._clSize | |
411 | ||
412 | if py > h - self.rowWin.GetSize()[1] + self.grid._clSize: | |
413 | py = h - self.rowWin.GetSize()[1] + self.grid._clSize | |
414 | ||
415 | self.rowWin.DisplayAt(x,py) | |
416 | return | |
417 | ||
418 | ||
419 | def OnPress(self,evt): | |
420 | self.startY = self.lastY = evt.m_y | |
421 | sy = self.grid.GetViewStart()[1] * self.uy | |
422 | sy -= self.grid._clSize | |
423 | px,py = self.lwin.ClientToScreenXY(evt.m_x,evt.m_y) | |
424 | px,py = self.grid.ScreenToClientXY(px,py) | |
425 | ||
426 | if self.grid.YToEdgeOfRow(py + sy) != wx.NOT_FOUND: | |
427 | evt.Skip() | |
428 | return | |
429 | ||
430 | self.isDragging = True | |
431 | self.didMove = False | |
432 | row = self.grid.YToRow(py + sy) | |
433 | rect = self.grid.RowToRect(row) | |
434 | self.cellY = py + sy - rect.y | |
435 | size = self.lwin.GetSize() | |
436 | rect.x = 0 | |
437 | rect.y -= sy + self.grid._clSize | |
438 | rect.width = size[0] | |
439 | rowImg = self._CaptureImage(rect) | |
440 | self.rowWin = RowDragWindow(self.grid,rowImg,row) | |
441 | self.rowWin.Show(False) | |
442 | self.lwin.CaptureMouse() | |
443 | evt.Skip() | |
444 | ||
445 | def OnRelease(self,evt): | |
446 | if self.isDragging: | |
447 | self.lwin.ReleaseMouse() | |
448 | self.rowWin.Show(False) | |
449 | self.isDragging = False | |
450 | ||
451 | if not self.didMove: | |
452 | py = self.lwin.ClientToScreenXY(0,self.startY)[1] | |
453 | py = self.grid.ScreenToClientXY(0,py)[1] | |
454 | sy = self.grid.GetViewStart()[1] * self.uy | |
455 | sy -= self.grid._clSize | |
456 | row = self.grid.YToRow(py + sy) | |
457 | ||
458 | if row != wx.NOT_FOUND: | |
459 | self.grid.SelectRow(row,evt.m_controlDown) | |
460 | return | |
461 | else: | |
462 | bRow = self.rowWin.GetInsertionRow() | |
463 | dRow = self.rowWin.GetMoveRow() | |
464 | ||
465 | wx.PostEvent(self, | |
466 | GridRowMoveEvent(self.grid.GetId(), dRow, bRow)) | |
467 | ||
468 | self.rowWin.Destroy() | |
469 | evt.Skip() | |
470 | ||
471 | def _CaptureImage(self,rect): | |
472 | bmp = wx.EmptyBitmap(rect.width,rect.height) | |
473 | memdc = wx.MemoryDC() | |
474 | memdc.SelectObject(bmp) | |
475 | dc = wx.WindowDC(self.lwin) | |
476 | memdc.Blit(0,0, rect.width, rect.height, dc, rect.x, rect.y) | |
477 | memdc.SelectObject(wx.NullBitmap) | |
478 | return bmp | |
479 | ||
480 | ||
481 | #---------------------------------------------------------------------------- |