]>
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 | # | |
33785d9f RD |
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 | ||
1fded56b | 24 | |
b881fc78 RD |
25 | import wx |
26 | import wx.grid | |
1fded56b | 27 | |
d14a1e28 | 28 | #---------------------------------------------------------------------------- |
b881fc78 RD |
29 | # event class and macros |
30 | # | |
31 | # New style 12/7/03 | |
32 | # | |
d14a1e28 | 33 | |
b881fc78 RD |
34 | wxEVT_COMMAND_GRID_COL_MOVE = wx.NewEventType() |
35 | wxEVT_COMMAND_GRID_ROW_MOVE = wx.NewEventType() | |
d14a1e28 | 36 | |
b881fc78 RD |
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) | |
d14a1e28 | 39 | |
b881fc78 | 40 | #---------------------------------------------------------------------------- |
d14a1e28 | 41 | |
33785d9f | 42 | class GridColMoveEvent(wx.PyCommandEvent): |
d14a1e28 | 43 | def __init__(self, id, dCol, bCol): |
b881fc78 | 44 | wx.PyCommandEvent.__init__(self, id = id) |
d14a1e28 RD |
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 | ||
33785d9f | 56 | class GridRowMoveEvent(wx.PyCommandEvent): |
d14a1e28 | 57 | def __init__(self, id, dRow, bRow): |
b881fc78 | 58 | wx.PyCommandEvent.__init__(self,id = id) |
d14a1e28 RD |
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: | |
a38c6903 | 77 | rect = wx.Rect() |
d14a1e28 RD |
78 | rect.height = self.GetColLabelSize() |
79 | rect.width = self.GetColSize(col) | |
b881fc78 | 80 | |
d14a1e28 RD |
81 | for cCol in range(0,col): |
82 | rect.x += self.GetColSize(cCol) | |
b881fc78 | 83 | |
d14a1e28 RD |
84 | rect.y = self.GetGridColLabelWindow().GetPosition()[1] |
85 | return rect | |
86 | ||
b881fc78 | 87 | wx.grid.Grid.ColToRect = _ColToRect |
d14a1e28 RD |
88 | |
89 | ||
90 | def _RowToRect(self,row): | |
91 | if self.GetNumberCols() > 0: | |
92 | rect = self.CellToRect(row,0) | |
93 | else: | |
a38c6903 | 94 | rect = wx.Rect() |
d14a1e28 RD |
95 | rect.width = self.GetRowLabelSize() |
96 | rect.height = self.GetRowSize(row) | |
b881fc78 | 97 | |
d14a1e28 RD |
98 | for cRow in range(0,row): |
99 | rect.y += self.GetRowSize(cRow) | |
b881fc78 | 100 | |
d14a1e28 RD |
101 | rect.x = self.GetGridRowLabelWindow().GetPosition()[0] |
102 | return rect | |
103 | ||
b881fc78 | 104 | wx.grid.Grid.RowToRect = _RowToRect |
d14a1e28 RD |
105 | |
106 | ||
107 | #---------------------------------------------------------------------------- | |
108 | ||
b881fc78 | 109 | class ColDragWindow(wx.Window): |
d14a1e28 | 110 | def __init__(self,parent,image,dragCol): |
b881fc78 | 111 | wx.Window.__init__(self,parent,-1, style=wx.SIMPLE_BORDER) |
d14a1e28 RD |
112 | self.image = image |
113 | self.SetSize((self.image.GetWidth(),self.image.GetHeight())) | |
114 | self.ux = parent.GetScrollPixelsPerUnit()[0] | |
115 | self.moveColumn = dragCol | |
116 | ||
b881fc78 | 117 | self.Bind(wx.EVT_PAINT, self.OnPaint) |
d14a1e28 RD |
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 | |
b881fc78 RD |
133 | x = self.GetPosition()[0] |
134 | w = self.GetSize()[0] | |
d14a1e28 RD |
135 | sCol = parent.XToCol(x + sx) |
136 | eCol = parent.XToCol(x + w + sx) | |
137 | iPos = xPos = xCol = 99999 | |
138 | centerPos = x + sx + (w / 2) | |
b881fc78 | 139 | |
d14a1e28 RD |
140 | for col in range(sCol,eCol + 1): |
141 | cx = parent.ColToRect(col)[0] | |
b881fc78 | 142 | |
d14a1e28 RD |
143 | if abs(cx - centerPos) < iPos: |
144 | iPos = abs(cx - centerPos) | |
145 | xCol = col | |
146 | xPos = cx | |
b881fc78 | 147 | |
d14a1e28 RD |
148 | if xCol < 0 or xCol > parent.GetNumberCols(): |
149 | xCol = parent.GetNumberCols() | |
b881fc78 | 150 | |
d14a1e28 RD |
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): | |
b881fc78 | 160 | dc = wx.PaintDC(self) |
d14a1e28 | 161 | w,h = self.GetSize() |
d7403ad2 | 162 | dc.DrawBitmap(self.image, 0,0) |
b881fc78 RD |
163 | dc.SetPen(wx.Pen(wx.BLACK,1,wx.SOLID)) |
164 | dc.SetBrush(wx.TRANSPARENT_BRUSH) | |
d7403ad2 | 165 | dc.DrawRectangle(0,0, w,h) |
d14a1e28 | 166 | iPos = self.GetInsertionPos() |
d7403ad2 | 167 | dc.DrawLine(iPos,h - 10, iPos,h) |
d14a1e28 RD |
168 | |
169 | ||
170 | ||
171 | ||
b881fc78 | 172 | class RowDragWindow(wx.Window): |
d14a1e28 | 173 | def __init__(self,parent,image,dragRow): |
b881fc78 | 174 | wx.Window.__init__(self,parent,-1, style=wx.SIMPLE_BORDER) |
d14a1e28 RD |
175 | self.image = image |
176 | self.SetSize((self.image.GetWidth(),self.image.GetHeight())) | |
177 | self.uy = parent.GetScrollPixelsPerUnit()[1] | |
178 | self.moveRow = dragRow | |
179 | ||
b881fc78 | 180 | self.Bind(wx.EVT_PAINT, self.OnPaint) |
d14a1e28 RD |
181 | |
182 | def DisplayAt(self,x,pos): | |
b881fc78 | 183 | y = self.GetPosition()[1] |
d14a1e28 RD |
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 | |
b881fc78 RD |
196 | y = self.GetPosition()[1] |
197 | h = self.GetSize()[1] | |
d14a1e28 RD |
198 | sRow = parent.YToRow(y + sy) |
199 | eRow = parent.YToRow(y + h + sy) | |
200 | iPos = yPos = yRow = 99999 | |
201 | centerPos = y + sy + (h / 2) | |
b881fc78 | 202 | |
d14a1e28 RD |
203 | for row in range(sRow,eRow + 1): |
204 | cy = parent.RowToRect(row)[1] | |
b881fc78 | 205 | |
d14a1e28 RD |
206 | if abs(cy - centerPos) < iPos: |
207 | iPos = abs(cy - centerPos) | |
208 | yRow = row | |
209 | yPos = cy | |
b881fc78 | 210 | |
d14a1e28 RD |
211 | if yRow < 0 or yRow > parent.GetNumberRows(): |
212 | yRow = parent.GetNumberRows() | |
b881fc78 | 213 | |
d14a1e28 RD |
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): | |
b881fc78 | 223 | dc = wx.PaintDC(self) |
d14a1e28 | 224 | w,h = self.GetSize() |
d7403ad2 | 225 | dc.DrawBitmap(self.image, 0,0) |
b881fc78 RD |
226 | dc.SetPen(wx.Pen(wx.BLACK,1,wx.SOLID)) |
227 | dc.SetBrush(wx.TRANSPARENT_BRUSH) | |
d7403ad2 | 228 | dc.DrawRectangle(0,0, w,h) |
d14a1e28 | 229 | iPos = self.GetInsertionPos() |
d7403ad2 | 230 | dc.DrawLine(w - 10,iPos, w,iPos) |
d14a1e28 RD |
231 | |
232 | #---------------------------------------------------------------------------- | |
233 | ||
33785d9f | 234 | class GridColMover(wx.EvtHandler): |
d14a1e28 | 235 | def __init__(self,grid): |
b881fc78 | 236 | wx.EvtHandler.__init__(self) |
d14a1e28 RD |
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 | ||
b881fc78 RD |
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) | |
d14a1e28 RD |
252 | |
253 | def OnMouseMove(self,evt): | |
254 | if self.isDragging: | |
255 | if abs(self.startX - evt.m_x) >= 3: | |
256 | self.didMove = True | |
257 | sx,y = self.grid.GetViewStart() | |
b881fc78 | 258 | w,h = self.lwin.GetClientSize() |
d14a1e28 | 259 | x = sx * self.ux |
b881fc78 | 260 | |
d14a1e28 RD |
261 | if (evt.m_x + x) < x: |
262 | x = evt.m_x + x | |
263 | elif evt.m_x > w: | |
264 | x += evt.m_x - w | |
b881fc78 | 265 | |
d14a1e28 RD |
266 | if x < 1: x = 0 |
267 | else: x /= self.ux | |
b881fc78 | 268 | |
d14a1e28 | 269 | if x != sx: |
b881fc78 | 270 | if wx.Platform == '__WXMSW__': |
d14a1e28 | 271 | self.colWin.Show(False) |
b881fc78 | 272 | |
d14a1e28 | 273 | self.grid.Scroll(x,y) |
b881fc78 | 274 | |
d14a1e28 RD |
275 | x,y = self.lwin.ClientToScreenXY(evt.m_x,0) |
276 | x,y = self.grid.ScreenToClientXY(x,y) | |
b881fc78 | 277 | |
d14a1e28 RD |
278 | if not self.colWin.IsShown(): |
279 | self.colWin.Show(True) | |
b881fc78 | 280 | |
d14a1e28 | 281 | px = x - self.cellX |
b881fc78 | 282 | |
d14a1e28 | 283 | if px < 0 + self.grid._rlSize: px = 0 + self.grid._rlSize |
b881fc78 RD |
284 | |
285 | if px > w - self.colWin.GetSize()[0] + self.grid._rlSize: | |
286 | px = w - self.colWin.GetSize()[0] + self.grid._rlSize | |
287 | ||
d14a1e28 RD |
288 | self.colWin.DisplayAt(px,y) |
289 | return | |
b881fc78 | 290 | |
d14a1e28 RD |
291 | evt.Skip() |
292 | ||
293 | def OnPress(self,evt): | |
294 | self.startX = evt.m_x | |
295 | sx = self.grid.GetViewStart()[0] * self.ux | |
296 | sx -= self.grid._rlSize | |
297 | px,py = self.lwin.ClientToScreenXY(evt.m_x,evt.m_y) | |
298 | px,py = self.grid.ScreenToClientXY(px,py) | |
b881fc78 RD |
299 | |
300 | if self.grid.XToEdgeOfCol(px + sx) != wx.NOT_FOUND: | |
d14a1e28 RD |
301 | evt.Skip() |
302 | return | |
303 | ||
304 | self.isDragging = True | |
305 | self.didMove = False | |
306 | col = self.grid.XToCol(px + sx) | |
307 | rect = self.grid.ColToRect(col) | |
308 | self.cellX = px + sx - rect.x | |
b881fc78 | 309 | size = self.lwin.GetSize() |
d14a1e28 RD |
310 | rect.y = 0 |
311 | rect.x -= sx + self.grid._rlSize | |
312 | rect.height = size[1] | |
313 | colImg = self._CaptureImage(rect) | |
314 | self.colWin = ColDragWindow(self.grid,colImg,col) | |
315 | self.colWin.Show(False) | |
316 | self.lwin.CaptureMouse() | |
1fa4b13e | 317 | evt.Skip() |
d14a1e28 RD |
318 | |
319 | def OnRelease(self,evt): | |
320 | if self.isDragging: | |
321 | self.lwin.ReleaseMouse() | |
322 | self.colWin.Show(False) | |
323 | self.isDragging = False | |
b881fc78 | 324 | |
d14a1e28 RD |
325 | if not self.didMove: |
326 | px = self.lwin.ClientToScreenXY(self.startX,0)[0] | |
327 | px = self.grid.ScreenToClientXY(px,0)[0] | |
328 | sx = self.grid.GetViewStart()[0] * self.ux | |
329 | sx -= self.grid._rlSize | |
330 | col = self.grid.XToCol(px+sx) | |
b881fc78 RD |
331 | |
332 | if col != wx.NOT_FOUND: | |
d14a1e28 | 333 | self.grid.SelectCol(col,evt.m_controlDown) |
b881fc78 | 334 | |
d14a1e28 RD |
335 | return |
336 | else: | |
337 | bCol = self.colWin.GetInsertionColumn() | |
338 | dCol = self.colWin.GetMoveColumn() | |
b881fc78 | 339 | wx.PostEvent(self, |
33785d9f | 340 | GridColMoveEvent(self.grid.GetId(), dCol, bCol)) |
b881fc78 | 341 | |
d14a1e28 RD |
342 | self.colWin.Destroy() |
343 | evt.Skip() | |
344 | ||
345 | def _CaptureImage(self,rect): | |
b881fc78 RD |
346 | bmp = wx.EmptyBitmap(rect.width,rect.height) |
347 | memdc = wx.MemoryDC() | |
d14a1e28 | 348 | memdc.SelectObject(bmp) |
b881fc78 | 349 | dc = wx.WindowDC(self.lwin) |
d7403ad2 | 350 | memdc.Blit(0,0, rect.width, rect.height, dc, rect.x, rect.y) |
b881fc78 | 351 | memdc.SelectObject(wx.NullBitmap) |
d14a1e28 RD |
352 | return bmp |
353 | ||
354 | ||
33785d9f | 355 | class GridRowMover(wx.EvtHandler): |
d14a1e28 | 356 | def __init__(self,grid): |
b881fc78 | 357 | wx.EvtHandler.__init__(self) |
d14a1e28 RD |
358 | |
359 | self.grid = grid | |
360 | self.grid._clSize = self.grid.GetColLabelSize() | |
361 | self.lwin = grid.GetGridRowLabelWindow() | |
362 | self.lwin.PushEventHandler(self) | |
363 | self.rowWin = None | |
364 | self.uy = self.grid.GetScrollPixelsPerUnit()[1] | |
365 | self.startY = -10 | |
366 | self.cellY = 0 | |
367 | self.didMove = False | |
368 | self.isDragging = False | |
369 | ||
b881fc78 RD |
370 | self.Bind(wx.EVT_MOTION, self.OnMouseMove) |
371 | self.Bind(wx.EVT_LEFT_DOWN, self.OnPress) | |
372 | self.Bind(wx.EVT_LEFT_UP, self.OnRelease) | |
d14a1e28 RD |
373 | |
374 | def OnMouseMove(self,evt): | |
375 | if self.isDragging: | |
376 | if abs(self.startY - evt.m_y) >= 3: | |
377 | self.didMove = True | |
378 | x,sy = self.grid.GetViewStart() | |
379 | w,h = self.lwin.GetClientSizeTuple() | |
380 | y = sy * self.uy | |
b881fc78 | 381 | |
d14a1e28 RD |
382 | if (evt.m_y + y) < y: |
383 | y = evt.m_y + y | |
384 | elif evt.m_y > h: | |
385 | y += evt.m_y - h | |
b881fc78 RD |
386 | |
387 | if y < 1: | |
388 | y = 0 | |
389 | else: | |
390 | y /= self.uy | |
391 | ||
d14a1e28 | 392 | if y != sy: |
b881fc78 | 393 | if wx.Platform == '__WXMSW__': |
d14a1e28 | 394 | self.rowWin.Show(False) |
b881fc78 | 395 | |
d14a1e28 | 396 | self.grid.Scroll(x,y) |
b881fc78 | 397 | |
d14a1e28 RD |
398 | x,y = self.lwin.ClientToScreenXY(0,evt.m_y) |
399 | x,y = self.grid.ScreenToClientXY(x,y) | |
b881fc78 | 400 | |
d14a1e28 RD |
401 | if not self.rowWin.IsShown(): |
402 | self.rowWin.Show(True) | |
b881fc78 | 403 | |
d14a1e28 | 404 | py = y - self.cellY |
b881fc78 RD |
405 | |
406 | if py < 0 + self.grid._clSize: | |
407 | py = 0 + self.grid._clSize | |
408 | ||
409 | if py > h - self.rowWin.GetSize()[1] + self.grid._clSize: | |
410 | py = h - self.rowWin.GetSize()[1] + self.grid._clSize | |
411 | ||
d14a1e28 RD |
412 | self.rowWin.DisplayAt(x,py) |
413 | return | |
b881fc78 | 414 | |
d14a1e28 RD |
415 | evt.Skip() |
416 | ||
417 | def OnPress(self,evt): | |
418 | self.startY = evt.m_y | |
419 | sy = self.grid.GetViewStart()[1] * self.uy | |
420 | sy -= self.grid._clSize | |
421 | px,py = self.lwin.ClientToScreenXY(evt.m_x,evt.m_y) | |
422 | px,py = self.grid.ScreenToClientXY(px,py) | |
b881fc78 RD |
423 | |
424 | if self.grid.YToEdgeOfRow(py + sy) != wx.NOT_FOUND: | |
d14a1e28 RD |
425 | evt.Skip() |
426 | return | |
427 | ||
428 | self.isDragging = True | |
429 | self.didMove = False | |
430 | row = self.grid.YToRow(py + sy) | |
431 | rect = self.grid.RowToRect(row) | |
432 | self.cellY = py + sy - rect.y | |
b881fc78 | 433 | size = self.lwin.GetSize() |
d14a1e28 RD |
434 | rect.x = 0 |
435 | rect.y -= sy + self.grid._clSize | |
436 | rect.width = size[0] | |
437 | rowImg = self._CaptureImage(rect) | |
438 | self.rowWin = RowDragWindow(self.grid,rowImg,row) | |
439 | self.rowWin.Show(False) | |
440 | self.lwin.CaptureMouse() | |
1fa4b13e | 441 | evt.Skip() |
d14a1e28 RD |
442 | |
443 | def OnRelease(self,evt): | |
444 | if self.isDragging: | |
445 | self.lwin.ReleaseMouse() | |
446 | self.rowWin.Show(False) | |
447 | self.isDragging = False | |
b881fc78 | 448 | |
d14a1e28 RD |
449 | if not self.didMove: |
450 | py = self.lwin.ClientToScreenXY(0,self.startY)[1] | |
451 | py = self.grid.ScreenToClientXY(0,py)[1] | |
452 | sy = self.grid.GetViewStart()[1] * self.uy | |
453 | sy -= self.grid._clSize | |
454 | row = self.grid.YToRow(py + sy) | |
b881fc78 RD |
455 | |
456 | if row != wx.NOT_FOUND: | |
d14a1e28 RD |
457 | self.grid.SelectRow(row,evt.m_controlDown) |
458 | return | |
459 | else: | |
460 | bRow = self.rowWin.GetInsertionRow() | |
461 | dRow = self.rowWin.GetMoveRow() | |
b881fc78 RD |
462 | |
463 | wx.PostEvent(self, | |
33785d9f | 464 | GridRowMoveEvent(self.grid.GetId(), dRow, bRow)) |
b881fc78 | 465 | |
d14a1e28 RD |
466 | self.rowWin.Destroy() |
467 | evt.Skip() | |
468 | ||
469 | def _CaptureImage(self,rect): | |
b881fc78 RD |
470 | bmp = wx.EmptyBitmap(rect.width,rect.height) |
471 | memdc = wx.MemoryDC() | |
d14a1e28 | 472 | memdc.SelectObject(bmp) |
b881fc78 | 473 | dc = wx.WindowDC(self.lwin) |
d7403ad2 | 474 | memdc.Blit(0,0, rect.width, rect.height, dc, rect.x, rect.y) |
b881fc78 | 475 | memdc.SelectObject(wx.NullBitmap) |
d14a1e28 RD |
476 | return bmp |
477 | ||
478 | ||
479 | #---------------------------------------------------------------------------- |