]>
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.GetRowLabelSize() | |
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.GetColLabelSize() | |
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.lwin = grid.GetGridColLabelWindow() | |
240 | self.lwin.PushEventHandler(self) | |
241 | self.colWin = None | |
242 | self.ux = self.grid.GetScrollPixelsPerUnit()[0] | |
243 | self.startX = -10 | |
244 | self.cellX = 0 | |
245 | self.didMove = False | |
246 | self.isDragging = False | |
247 | ||
248 | self.Bind(wx.EVT_MOTION, self.OnMouseMove) | |
249 | self.Bind(wx.EVT_LEFT_DOWN, self.OnPress) | |
250 | self.Bind(wx.EVT_LEFT_UP, self.OnRelease) | |
251 | ||
252 | def OnMouseMove(self,evt): | |
253 | if self.isDragging: | |
254 | _rlSize = self.grid.GetRowLabelSize() | |
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 + _rlSize: px = 0 + _rlSize | |
286 | ||
287 | if px > w - self.colWin.GetSize()[0] + _rlSize: | |
288 | px = w - self.colWin.GetSize()[0] + _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 | _rlSize = self.grid.GetRowLabelSize() | |
297 | sx = self.grid.GetViewStart()[0] * self.ux | |
298 | sx -= _rlSize | |
299 | px,py = self.lwin.ClientToScreenXY(evt.m_x,evt.m_y) | |
300 | px,py = self.grid.ScreenToClientXY(px,py) | |
301 | ||
302 | if self.grid.XToEdgeOfCol(px + sx) != wx.NOT_FOUND: | |
303 | evt.Skip() | |
304 | return | |
305 | ||
306 | self.isDragging = True | |
307 | self.didMove = False | |
308 | col = self.grid.XToCol(px + sx) | |
309 | rect = self.grid.ColToRect(col) | |
310 | self.cellX = px + sx - rect.x | |
311 | size = self.lwin.GetSize() | |
312 | rect.y = 0 | |
313 | rect.x -= sx + _rlSize | |
314 | rect.height = size[1] | |
315 | colImg = self._CaptureImage(rect) | |
316 | self.colWin = ColDragWindow(self.grid,colImg,col) | |
317 | self.colWin.Show(False) | |
318 | self.lwin.CaptureMouse() | |
319 | evt.Skip() | |
320 | ||
321 | def OnRelease(self,evt): | |
322 | if self.isDragging: | |
323 | self.lwin.ReleaseMouse() | |
324 | self.colWin.Show(False) | |
325 | self.isDragging = False | |
326 | ||
327 | if not self.didMove: | |
328 | px = self.lwin.ClientToScreenXY(self.startX,0)[0] | |
329 | px = self.grid.ScreenToClientXY(px,0)[0] | |
330 | sx = self.grid.GetViewStart()[0] * self.ux | |
331 | sx -= self.grid.GetRowLabelSize() | |
332 | col = self.grid.XToCol(px+sx) | |
333 | ||
334 | if col != wx.NOT_FOUND: | |
335 | self.grid.SelectCol(col,evt.m_controlDown) | |
336 | ||
337 | return | |
338 | else: | |
339 | bCol = self.colWin.GetInsertionColumn() | |
340 | dCol = self.colWin.GetMoveColumn() | |
341 | wx.PostEvent(self, | |
342 | GridColMoveEvent(self.grid.GetId(), dCol, bCol)) | |
343 | ||
344 | self.colWin.Destroy() | |
345 | evt.Skip() | |
346 | ||
347 | def _CaptureImage(self,rect): | |
348 | bmp = wx.EmptyBitmap(rect.width,rect.height) | |
349 | memdc = wx.MemoryDC() | |
350 | memdc.SelectObject(bmp) | |
351 | dc = wx.WindowDC(self.lwin) | |
352 | memdc.Blit(0,0, rect.width, rect.height, dc, rect.x, rect.y) | |
353 | memdc.SelectObject(wx.NullBitmap) | |
354 | return bmp | |
355 | ||
356 | ||
357 | class GridRowMover(wx.EvtHandler): | |
358 | def __init__(self,grid): | |
359 | wx.EvtHandler.__init__(self) | |
360 | ||
361 | self.grid = grid | |
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 | _clSize = self.grid.GetColLabelSize() | |
378 | if abs(self.startY - evt.m_y) >= 3 \ | |
379 | and abs(evt.m_y - self.lastY) >= 3: | |
380 | self.lastY = evt.m_y | |
381 | self.didMove = True | |
382 | x,sy = self.grid.GetViewStart() | |
383 | w,h = self.lwin.GetClientSizeTuple() | |
384 | y = sy * self.uy | |
385 | ||
386 | if (evt.m_y + y) < y: | |
387 | y = evt.m_y + y | |
388 | elif evt.m_y > h: | |
389 | y += evt.m_y - h | |
390 | ||
391 | if y < 1: | |
392 | y = 0 | |
393 | else: | |
394 | y /= self.uy | |
395 | ||
396 | if y != sy: | |
397 | if wx.Platform == '__WXMSW__': | |
398 | self.rowWin.Show(False) | |
399 | ||
400 | self.grid.Scroll(x,y) | |
401 | ||
402 | x,y = self.lwin.ClientToScreenXY(0,evt.m_y) | |
403 | x,y = self.grid.ScreenToClientXY(x,y) | |
404 | ||
405 | if not self.rowWin.IsShown(): | |
406 | self.rowWin.Show(True) | |
407 | ||
408 | py = y - self.cellY | |
409 | ||
410 | if py < 0 + _clSize: | |
411 | py = 0 + _clSize | |
412 | ||
413 | if py > h - self.rowWin.GetSize()[1] + _clSize: | |
414 | py = h - self.rowWin.GetSize()[1] + _clSize | |
415 | ||
416 | self.rowWin.DisplayAt(x,py) | |
417 | return | |
418 | ||
419 | ||
420 | def OnPress(self,evt): | |
421 | self.startY = self.lastY = evt.m_y | |
422 | _clSize = self.grid.GetColLabelSize() | |
423 | sy = self.grid.GetViewStart()[1] * self.uy | |
424 | sy -= _clSize | |
425 | px,py = self.lwin.ClientToScreenXY(evt.m_x,evt.m_y) | |
426 | px,py = self.grid.ScreenToClientXY(px,py) | |
427 | ||
428 | if self.grid.YToEdgeOfRow(py + sy) != wx.NOT_FOUND: | |
429 | evt.Skip() | |
430 | return | |
431 | ||
432 | self.isDragging = True | |
433 | self.didMove = False | |
434 | row = self.grid.YToRow(py + sy) | |
435 | rect = self.grid.RowToRect(row) | |
436 | self.cellY = py + sy - rect.y | |
437 | size = self.lwin.GetSize() | |
438 | rect.x = 0 | |
439 | rect.y -= sy + _clSize | |
440 | rect.width = size[0] | |
441 | rowImg = self._CaptureImage(rect) | |
442 | self.rowWin = RowDragWindow(self.grid,rowImg,row) | |
443 | self.rowWin.Show(False) | |
444 | self.lwin.CaptureMouse() | |
445 | evt.Skip() | |
446 | ||
447 | def OnRelease(self,evt): | |
448 | if self.isDragging: | |
449 | self.lwin.ReleaseMouse() | |
450 | self.rowWin.Show(False) | |
451 | self.isDragging = False | |
452 | ||
453 | if not self.didMove: | |
454 | py = self.lwin.ClientToScreenXY(0,self.startY)[1] | |
455 | py = self.grid.ScreenToClientXY(0,py)[1] | |
456 | sy = self.grid.GetViewStart()[1] * self.uy | |
457 | sy -= self.grid.GetColLabelSize() | |
458 | row = self.grid.YToRow(py + sy) | |
459 | ||
460 | if row != wx.NOT_FOUND: | |
461 | self.grid.SelectRow(row,evt.m_controlDown) | |
462 | return | |
463 | else: | |
464 | bRow = self.rowWin.GetInsertionRow() | |
465 | dRow = self.rowWin.GetMoveRow() | |
466 | ||
467 | wx.PostEvent(self, | |
468 | GridRowMoveEvent(self.grid.GetId(), dRow, bRow)) | |
469 | ||
470 | self.rowWin.Destroy() | |
471 | evt.Skip() | |
472 | ||
473 | def _CaptureImage(self,rect): | |
474 | bmp = wx.EmptyBitmap(rect.width,rect.height) | |
475 | memdc = wx.MemoryDC() | |
476 | memdc.SelectObject(bmp) | |
477 | dc = wx.WindowDC(self.lwin) | |
478 | memdc.Blit(0,0, rect.width, rect.height, dc, rect.x, rect.y) | |
479 | memdc.SelectObject(wx.NullBitmap) | |
480 | return bmp | |
481 | ||
482 | ||
483 | #---------------------------------------------------------------------------- |