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