]> git.saurik.com Git - wxWidgets.git/blob - wxPython/samples/ide/activegrid/tool/AbstractEditor.py
Docview and IDE patch from Morag Hua with fix for bug #1217890
[wxWidgets.git] / wxPython / samples / ide / activegrid / tool / AbstractEditor.py
1 #----------------------------------------------------------------------------
2 # Name: AbstractEditor.py
3 # Purpose: Non-text editor for DataModel and Process
4 #
5 # Author: Peter Yared, Morgan Hua
6 #
7 # Created: 7/28/04
8 # CVS-ID: $Id$
9 # Copyright: (c) 2004-2005 ActiveGrid, Inc.
10 # License: wxWindows License
11 #----------------------------------------------------------------------------
12
13
14 import wx
15 import wx.lib.docview
16 import wx.lib.ogl as ogl
17 import PropertyService
18 _ = wx.GetTranslation
19
20
21 SELECT_BRUSH = wx.Brush("BLUE", wx.SOLID)
22 SHAPE_BRUSH = wx.Brush("WHEAT", wx.SOLID)
23 LINE_BRUSH = wx.BLACK_BRUSH
24 INACTIVE_SELECT_BRUSH = wx.Brush("LIGHT BLUE", wx.SOLID)
25
26
27 def GetRawModel(model):
28 if hasattr(model, "GetRawModel"):
29 rawModel = model.GetRawModel()
30 else:
31 rawModel = model
32 return rawModel
33
34
35 class CanvasView(wx.lib.docview.View):
36
37
38 #----------------------------------------------------------------------------
39 # Overridden methods
40 #----------------------------------------------------------------------------
41
42
43 def __init__(self, brush = SHAPE_BRUSH):
44 wx.lib.docview.View.__init__(self)
45 self._brush = brush
46 self._canvas = None
47 self._pt1 = None
48 self._pt2 = None
49 self._needEraseLasso = False
50 self._propShape = None
51 self._maxWidth = 2000
52 self._maxHeight = 16000
53
54
55 def OnDraw(self, dc):
56 """ for Print Preview and Print """
57 dc.BeginDrawing()
58 self._canvas.Redraw(dc)
59 dc.EndDrawing()
60
61
62 def OnCreate(self, doc, flags):
63 frame = wx.GetApp().CreateDocumentFrame(self, doc, flags)
64 frame.Show()
65 sizer = wx.BoxSizer()
66 self._CreateCanvas(frame)
67 sizer.Add(self._canvas, 1, wx.EXPAND, 0)
68 frame.SetSizer(sizer)
69 frame.Layout()
70 self.Activate()
71 return True
72
73
74 def OnActivateView(self, activate, activeView, deactiveView):
75 if activate and self._canvas:
76 # In MDI mode just calling set focus doesn't work and in SDI mode using CallAfter causes an endless loop
77 if self.GetDocumentManager().GetFlags() & wx.lib.docview.DOC_SDI:
78 self.SetFocus()
79 else:
80 wx.CallAfter(self.SetFocus)
81
82
83 def SetFocus(self):
84 if self._canvas:
85 self._canvas.SetFocus()
86
87
88 def OnFocus(self, event):
89 self.FocusColorPropertyShape(True)
90 event.Skip()
91
92
93 def FocusOnClick(self, event):
94 self.SetFocus()
95 event.Skip()
96
97
98 def OnKillFocus(self, event):
99 self.FocusColorPropertyShape(False)
100 event.Skip()
101
102
103 def HasFocus(self):
104 winWithFocus = wx.Window.FindFocus()
105 if not winWithFocus:
106 return False
107 while winWithFocus:
108 if winWithFocus == self._canvas:
109 return True
110 winWithFocus = winWithFocus.GetParent()
111 return False
112
113
114 def OnClose(self, deleteWindow = True):
115 statusC = wx.GetApp().CloseChildDocuments(self.GetDocument())
116 statusP = wx.lib.docview.View.OnClose(self, deleteWindow = deleteWindow)
117 if hasattr(self, "ClearOutline"):
118 wx.CallAfter(self.ClearOutline) # need CallAfter because when closing the document, it is Activated and then Close, so need to match OnActivateView's CallAfter
119 if not (statusC and statusP):
120 return False
121 self.Activate(False)
122 if deleteWindow and self.GetFrame():
123 self.GetFrame().Destroy()
124 return True
125
126
127 def _CreateCanvas(self, parent):
128 self._canvas = ogl.ShapeCanvas(parent)
129 wx.EVT_LEFT_DOWN(self._canvas, self.OnLeftClick)
130 wx.EVT_LEFT_UP(self._canvas, self.OnLeftUp)
131 wx.EVT_MOTION(self._canvas, self.OnLeftDrag)
132 wx.EVT_LEFT_DCLICK(self._canvas, self.OnLeftDoubleClick)
133 wx.EVT_KEY_DOWN(self._canvas, self.OnKeyPressed)
134
135 # need this otherwise mouse clicks don't set focus to this view
136 wx.EVT_LEFT_DOWN(self._canvas, self.FocusOnClick)
137 wx.EVT_LEFT_DCLICK(self._canvas, self.FocusOnClick)
138 wx.EVT_RIGHT_DOWN(self._canvas, self.FocusOnClick)
139 wx.EVT_RIGHT_DCLICK(self._canvas, self.FocusOnClick)
140 wx.EVT_MIDDLE_DOWN(self._canvas, self.FocusOnClick)
141 wx.EVT_MIDDLE_DCLICK(self._canvas, self.FocusOnClick)
142
143 wx.EVT_KILL_FOCUS(self._canvas, self.OnKillFocus)
144 wx.EVT_SET_FOCUS(self._canvas, self.OnFocus)
145
146 self._canvas.SetScrollbars(20, 20, self._maxWidth / 20, self._maxHeight / 20)
147
148 self._canvas.SetBackgroundColour(wx.WHITE)
149 self._diagram = ogl.Diagram()
150 self._canvas.SetDiagram(self._diagram)
151 self._diagram.SetCanvas(self._canvas)
152
153
154 def OnKeyPressed(self, event):
155 key = event.KeyCode()
156 if key == wx.WXK_DELETE:
157 self.OnClear(event)
158 else:
159 event.Skip()
160
161
162 def OnLeftClick(self, event):
163 self.EraseRubberBand()
164
165 dc = wx.ClientDC(self._canvas)
166 self._canvas.PrepareDC(dc)
167
168 # keep track of mouse down for group select
169 self._pt1 = event.GetLogicalPosition(dc) # this takes into account scrollbar offset
170 self._pt2 = None
171
172 shape = self._canvas.FindShape(self._pt1[0], self._pt1[1])[0]
173 if shape:
174 self.BringToFront(shape)
175
176 self._pt1 = None
177 event.Skip() # pass on event to shape handler to take care of selection
178
179 return
180 elif event.ControlDown() or event.ShiftDown(): # extend select, don't deselect
181 pass
182 else:
183 # click on empty part of canvas, deselect everything
184 needRefresh = False
185 for shape in self._diagram.GetShapeList():
186 if hasattr(shape, "GetModel"):
187 if shape.Selected():
188 needRefresh = True
189 shape.Select(False, dc)
190 if needRefresh:
191 self._canvas.Redraw(dc)
192
193 self.SetPropertyModel(None)
194
195 if len(self.GetSelection()) == 0:
196 self.SetPropertyShape(None)
197
198
199
200 def OnLeftDoubleClick(self, event):
201 propertyService = wx.GetApp().GetService(PropertyService.PropertyService)
202 if propertyService:
203 propertyService.ShowWindow()
204
205
206 def OnLeftDrag(self, event):
207 # draw lasso for group select
208 if self._pt1 and event.LeftIsDown(): # we are in middle of lasso selection
209 self.EraseRubberBand()
210
211 dc = wx.ClientDC(self._canvas)
212 self._canvas.PrepareDC(dc)
213 self._pt2 = event.GetLogicalPosition(dc) # this takes into account scrollbar offset
214 self.DrawRubberBand()
215 else:
216 event.Skip()
217
218
219 def OnLeftUp(self, event):
220 # do group select
221 if self._needEraseLasso:
222 self.EraseRubberBand()
223
224 dc = wx.ClientDC(self._canvas)
225 self._canvas.PrepareDC(dc)
226 x1, y1 = self._pt1
227 x2, y2 = event.GetLogicalPosition(dc) # this takes into account scrollbar offset
228
229 tol = self._diagram.GetMouseTolerance()
230 if abs(x1 - x2) > tol or abs(y1 - y2) > tol:
231 # make sure x1 < x2 and y1 < y2 to make comparison test easier
232 if x1 > x2:
233 temp = x1
234 x1 = x2
235 x2 = temp
236 if y1 > y2:
237 temp = y1
238 y1 = y2
239 y2 = temp
240
241 for shape in self._diagram.GetShapeList():
242 if not shape.GetParent() and hasattr(shape, "GetModel"): # if part of a composite, don't select it
243 x, y = shape.GetX(), shape.GetY()
244 width, height = shape.GetBoundingBoxMax()
245 selected = x1 < x - width/2 and x2 > x + width/2 and y1 < y - height/2 and y2 > y + height/2
246 if event.ControlDown() or event.ShiftDown(): # extend select, don't deselect
247 if selected:
248 shape.Select(selected, dc)
249 else: # select items in lasso and deselect items out of lasso
250 shape.Select(selected, dc)
251 self._canvas.Redraw(dc)
252 else:
253 event.Skip()
254 else:
255 event.Skip()
256
257
258 def EraseRubberBand(self):
259 if self._needEraseLasso:
260 self._needEraseLasso = False
261
262 dc = wx.ClientDC(self._canvas)
263 self._canvas.PrepareDC(dc)
264 dc.SetLogicalFunction(wx.XOR)
265 pen = wx.Pen(wx.Colour(200, 200, 200), 1, wx.SHORT_DASH)
266 dc.SetPen(pen)
267 brush = wx.Brush(wx.Colour(255, 255, 255), wx.TRANSPARENT)
268 dc.SetBrush(brush)
269 dc.ResetBoundingBox()
270 dc.BeginDrawing()
271
272 x1, y1 = self._pt1
273 x2, y2 = self._pt2
274
275 # make sure x1 < x2 and y1 < y2
276 # this will make (x1, y1) = upper left corner
277 if x1 > x2:
278 temp = x1
279 x1 = x2
280 x2 = temp
281 if y1 > y2:
282 temp = y1
283 y1 = y2
284 y2 = temp
285
286 # erase previous outline
287 dc.SetClippingRegion(x1, y1, x2 - x1, y2 - y1)
288 dc.DrawRectangle(x1, y1, x2 - x1, y2 - y1)
289 dc.EndDrawing()
290
291
292 def DrawRubberBand(self):
293 self._needEraseLasso = True
294
295 dc = wx.ClientDC(self._canvas)
296 self._canvas.PrepareDC(dc)
297 dc.SetLogicalFunction(wx.XOR)
298 pen = wx.Pen(wx.Colour(200, 200, 200), 1, wx.SHORT_DASH)
299 dc.SetPen(pen)
300 brush = wx.Brush(wx.Colour(255, 255, 255), wx.TRANSPARENT)
301 dc.SetBrush(brush)
302 dc.ResetBoundingBox()
303 dc.BeginDrawing()
304
305 x1, y1 = self._pt1
306 x2, y2 = self._pt2
307
308 # make sure x1 < x2 and y1 < y2
309 # this will make (x1, y1) = upper left corner
310 if x1 > x2:
311 temp = x1
312 x1 = x2
313 x2 = temp
314 if y1 > y2:
315 temp = y1
316 y1 = y2
317 y2 = temp
318
319 # draw outline
320 dc.SetClippingRegion(x1, y1, x2 - x1, y2 - y1)
321 dc.DrawRectangle(x1, y1, x2 - x1, y2 - y1)
322 dc.EndDrawing()
323
324
325 def FindParkingSpot(self, width, height):
326 """ given a width and height, find a upper left corner where shape can be parked without overlapping other shape """
327 offset = 30 # space between shapes
328 x = offset
329 y = offset
330 maxX = 700 # max distance to the right where we'll place tables
331 noParkingSpot = True
332
333 while noParkingSpot:
334 point = self.isSpotOccupied(x, y, width, height)
335 if point:
336 x = point[0] + offset
337 if x > maxX:
338 x = offset
339 y = point[1] + offset
340 else:
341 noParkingSpot = False
342
343 return x, y
344
345
346 def isSpotOccupied(self, x, y, width, height):
347 """ returns None if at x,y,width,height no object occupies that rectangle,
348 otherwise returns lower right corner of object that occupies given x,y position
349 """
350 x2 = x + width
351 y2 = y + height
352
353 for shape in self._diagram.GetShapeList():
354 if isinstance(shape, ogl.RectangleShape) or isinstance(shape, ogl.EllipseShape):
355 if shape.GetParent() and isinstance(shape.GetParent(), ogl.CompositeShape):
356 # skip, part of a composite shape
357 continue
358
359 if hasattr(shape, "GetModel"):
360 other_x, other_y, other_width, other_height = shape.GetModel().getEditorBounds()
361 other_x2 = other_x + other_width
362 other_y2 = other_y + other_height
363 else:
364 # shapes x,y are at the center of the shape, need to transform to upper left coordinate
365 other_width, other_height = shape.GetBoundingBoxMax()
366 other_x = shape.GetX() - other_width/2
367 other_y = shape.GetY() - other_height/2
368
369 other_x2 = other_x + other_width
370 other_y2 = other_y + other_height
371 # intersection check
372 if ((other_x2 < other_x or other_x2 > x) and
373 (other_y2 < other_y or other_y2 > y) and
374 (x2 < x or x2 > other_x) and
375 (y2 < y or y2 > other_y)):
376 return (other_x2, other_y2)
377 return None
378
379
380 #----------------------------------------------------------------------------
381 # Canvas methods
382 #----------------------------------------------------------------------------
383
384 def AddShape(self, shape, x = None, y = None, pen = None, brush = None, text = None, eventHandler = None):
385 if isinstance(shape, ogl.CompositeShape):
386 dc = wx.ClientDC(self._canvas)
387 self._canvas.PrepareDC(dc)
388 shape.Move(dc, x, y)
389 else:
390 shape.SetDraggable(True, True)
391 shape.SetCanvas(self._canvas)
392
393 if x:
394 shape.SetX(x)
395 if y:
396 shape.SetY(y)
397 shape.SetCentreResize(False)
398 if pen:
399 shape.SetPen(pen)
400 if brush:
401 shape.SetBrush(brush)
402 if text:
403 shape.AddText(text)
404 shape.SetShadowMode(ogl.SHADOW_NONE)
405 self._diagram.AddShape(shape)
406 shape.Show(True)
407 if not eventHandler:
408 eventHandler = EditorCanvasShapeEvtHandler(self)
409 eventHandler.SetShape(shape)
410 eventHandler.SetPreviousHandler(shape.GetEventHandler())
411 shape.SetEventHandler(eventHandler)
412 return shape
413
414
415 def RemoveShape(self, model = None, shape = None):
416 if not model and not shape:
417 return
418
419 if not shape:
420 shape = self.GetShape(model)
421
422 if shape:
423 shape.Select(False)
424 for line in shape.GetLines():
425 shape.RemoveLine(line)
426 self._diagram.RemoveShape(line)
427 for obj in self._diagram.GetShapeList():
428 for line in obj.GetLines():
429 if self.IsShapeContained(shape, line.GetTo()) or self.IsShapeContained(shape, line.GetFrom()):
430 obj.RemoveLine(line)
431 self._diagram.RemoveShape(line)
432 if line == shape:
433 obj.RemoveLine(line)
434
435 shape.RemoveFromCanvas(self._canvas)
436 self._diagram.RemoveShape(shape)
437
438
439 def IsShapeContained(self, parent, shape):
440 if parent == shape:
441 return True
442 elif shape.GetParent():
443 return self.IsShapeContained(parent, shape.GetParent())
444
445 return False
446
447
448 def UpdateShape(self, model):
449 for shape in self._diagram.GetShapeList():
450 if hasattr(shape, "GetModel") and shape.GetModel() == model:
451 x, y, w, h = model.getEditorBounds()
452 newX = x + w / 2
453 newY = y + h / 2
454 changed = False
455 if isinstance(shape, ogl.CompositeShape):
456 if shape.GetX() != newX or shape.GetY() != newY:
457 dc = wx.ClientDC(self._canvas)
458 self._canvas.PrepareDC(dc)
459 shape.SetSize(w, h, True) # wxBug: SetSize must be before Move because links won't go to the right place
460 shape.Move(dc, newX, newY) # wxBug: Move must be before SetSize because links won't go to the right place
461 changed = True
462 else:
463 oldw, oldh = shape.GetBoundingBoxMax()
464 oldx = shape.GetX()
465 oldy = shape.GetY()
466 if oldw != w or oldh != h or oldx != newX or oldy != newY:
467 shape.SetSize(w, h)
468 shape.SetX(newX)
469 shape.SetY(newY)
470 changed = True
471 if changed:
472 shape.ResetControlPoints()
473 self._canvas.Refresh()
474 break
475
476
477 def GetShape(self, model):
478 for shape in self._diagram.GetShapeList():
479 if hasattr(shape, "GetModel") and shape.GetModel() == model:
480 return shape
481 return None
482
483
484 def GetSelection(self):
485 return filter(lambda shape: shape.Selected(), self._diagram.GetShapeList())
486
487
488 def SetSelection(self, models, extendSelect = False):
489 dc = wx.ClientDC(self._canvas)
490 self._canvas.PrepareDC(dc)
491 update = False
492 if not isinstance(models, type([])) and not isinstance(models, type(())):
493 models = [models]
494 for shape in self._diagram.GetShapeList():
495 if hasattr(shape, "GetModel"):
496 if shape.Selected() and not shape.GetModel() in models: # was selected, but not in new list, so deselect, unless extend select
497 if not extendSelect:
498 shape.Select(False, dc)
499 update = True
500 elif not shape.Selected() and shape.GetModel() in models: # was not selected and in new list, so select
501 shape.Select(True, dc)
502 update = True
503 elif extendSelect and shape.Selected() and shape.GetModel() in models: # was selected, but extend select means to deselect
504 shape.Select(False, dc)
505 update = True
506 if update:
507 self._canvas.Redraw(dc)
508
509
510 def BringToFront(self, shape):
511 if shape.GetParent() and isinstance(shape.GetParent(), ogl.CompositeShape):
512 self._diagram.RemoveShape(shape.GetParent())
513 self._diagram.AddShape(shape.GetParent())
514 else:
515 self._diagram.RemoveShape(shape)
516 self._diagram.AddShape(shape)
517
518
519 def SendToBack(self, shape):
520 if shape.GetParent() and isinstance(shape.GetParent(), ogl.CompositeShape):
521 self._diagram.RemoveShape(shape.GetParent())
522 self._diagram.InsertShape(shape.GetParent())
523 else:
524 self._diagram.RemoveShape(shape)
525 self._diagram.InsertShape(shape)
526
527
528 def ScrollVisible(self, shape):
529 xUnit, yUnit = shape._canvas.GetScrollPixelsPerUnit()
530 scrollX, scrollY = self._canvas.GetViewStart() # in scroll units
531 scrollW, scrollH = self._canvas.GetSize() # in pixels
532 w, h = shape.GetBoundingBoxMax() # in pixels
533 x = shape.GetX() - w/2 # convert to upper left coordinate from center
534 y = shape.GetY() - h/2 # convert to upper left coordinate from center
535
536 if x >= scrollX*xUnit and x <= scrollX*xUnit + scrollW: # don't scroll if already visible
537 x = -1
538 else:
539 x = x/xUnit
540
541 if y >= scrollY*yUnit and y <= scrollY*yUnit + scrollH: # don't scroll if already visible
542 y = -1
543 else:
544 y = y/yUnit
545
546 self._canvas.Scroll(x, y) # in scroll units
547
548
549 def SetPropertyShape(self, shape):
550 # no need to highlight if no PropertyService is running
551 propertyService = wx.GetApp().GetService(PropertyService.PropertyService)
552 if not propertyService:
553 return
554
555 if shape == self._propShape:
556 return
557
558 if hasattr(shape, "GetPropertyShape"):
559 shape = shape.GetPropertyShape()
560
561 dc = wx.ClientDC(self._canvas)
562 self._canvas.PrepareDC(dc)
563 dc.BeginDrawing()
564
565 # erase old selection if it still exists
566 if self._propShape and self._propShape in self._diagram.GetShapeList():
567 self._propShape.SetBrush(self._brush)
568 if (self._propShape._textColourName in ["BLACK", "WHITE"]): # Would use GetTextColour() but it is broken
569 self._propShape.SetTextColour("BLACK", 0)
570 self._propShape.Draw(dc)
571
572 # set new selection
573 self._propShape = shape
574
575 # draw new selection
576 if self._propShape and self._propShape in self._diagram.GetShapeList():
577 if self.HasFocus():
578 self._propShape.SetBrush(SELECT_BRUSH)
579 else:
580 self._propShape.SetBrush(INACTIVE_SELECT_BRUSH)
581 if (self._propShape._textColourName in ["BLACK", "WHITE"]): # Would use GetTextColour() but it is broken
582 self._propShape.SetTextColour("WHITE", 0)
583 self._propShape.Draw(dc)
584
585 dc.EndDrawing()
586
587
588 def FocusColorPropertyShape(self, gotFocus=False):
589 # no need to change highlight if no PropertyService is running
590 propertyService = wx.GetApp().GetService(PropertyService.PropertyService)
591 if not propertyService:
592 return
593
594 if not self._propShape:
595 return
596
597 dc = wx.ClientDC(self._canvas)
598 self._canvas.PrepareDC(dc)
599 dc.BeginDrawing()
600
601 # draw deactivated selection
602 if self._propShape and self._propShape in self._diagram.GetShapeList():
603 if gotFocus:
604 self._propShape.SetBrush(SELECT_BRUSH)
605 else:
606 self._propShape.SetBrush(INACTIVE_SELECT_BRUSH)
607 if (self._propShape._textColourName in ["BLACK", "WHITE"]): # Would use GetTextColour() but it is broken
608 self._propShape.SetTextColour("WHITE", 0)
609 self._propShape.Draw(dc)
610
611 dc.EndDrawing()
612
613
614 #----------------------------------------------------------------------------
615 # Property Service methods
616 #----------------------------------------------------------------------------
617
618 def GetPropertyModel(self):
619 if hasattr(self, "_propModel"):
620 return self._propModel
621 return None
622
623
624 def SetPropertyModel(self, model):
625 # no need to set the model if no PropertyService is running
626 propertyService = wx.GetApp().GetService(PropertyService.PropertyService)
627 if not propertyService:
628 return
629
630 if hasattr(self, "_propModel") and model == self._propModel:
631 return
632
633 self._propModel = model
634 propertyService.LoadProperties(self._propModel, self.GetDocument())
635
636
637 class EditorCanvasShapeMixin:
638
639 def GetModel(self):
640 return self._model
641
642
643 def SetModel(self, model):
644 self._model = model
645
646
647 class EditorCanvasShapeEvtHandler(ogl.ShapeEvtHandler):
648
649 """ wxBug: Bug in OLG package. With wxShape.SetShadowMode() turned on, when we set the size,
650 the width/height is larger by 6 pixels. Need to subtract this value from width and height when we
651 resize the object.
652 """
653 SHIFT_KEY = 1
654 CONTROL_KEY = 2
655
656 def __init__(self, view):
657 ogl.ShapeEvtHandler.__init__(self)
658 self._view = view
659
660
661 def OnLeftClick(self, x, y, keys = 0, attachment = 0):
662 shape = self.GetShape()
663 if hasattr(shape, "GetModel"): # Workaround, on drag, we should deselect all other objects and select the clicked on object
664 model = shape.GetModel()
665 else:
666 shape = shape.GetParent()
667 if shape:
668 model = shape.GetModel()
669
670 self._view.SetSelection(model, keys == self.SHIFT_KEY or keys == self.CONTROL_KEY)
671 self._view.SetPropertyShape(shape)
672 self._view.SetPropertyModel(model)
673
674
675 def OnEndDragLeft(self, x, y, keys = 0, attachment = 0):
676 ogl.ShapeEvtHandler.OnEndDragLeft(self, x, y, keys, attachment)
677 shape = self.GetShape()
678 if hasattr(shape, "GetModel"): # Workaround, on drag, we should deselect all other objects and select the clicked on object
679 model = shape.GetModel()
680 else:
681 parentShape = shape.GetParent()
682 if parentShape:
683 model = parentShape.GetModel()
684 self._view.SetSelection(model, keys == self.SHIFT_KEY or keys == self.CONTROL_KEY)
685
686
687 def OnMovePre(self, dc, x, y, oldX, oldY, display):
688 """ Prevent objects from being dragged outside of viewable area """
689 if (x > self._view._maxWidth) or (y > self._view._maxHeight):
690 return False
691
692 return ogl.ShapeEvtHandler.OnMovePre(self, dc, x, y, oldX, oldY, display)
693
694
695 def OnMovePost(self, dc, x, y, oldX, oldY, display):
696 """ Update the model's record of where the shape should be. Also enable redo/undo. """
697 if x == oldX and y == oldY:
698 return
699 if not self._view.GetDocument():
700 return
701 shape = self.GetShape()
702 if isinstance(shape, EditorCanvasShapeMixin) and shape.Draggable():
703 model = shape.GetModel()
704 if hasattr(model, "getEditorBounds") and model.getEditorBounds():
705 x, y, w, h = model.getEditorBounds()
706 newX = shape.GetX() - shape.GetBoundingBoxMax()[0] / 2
707 newY = shape.GetY() - shape.GetBoundingBoxMax()[1] / 2
708 newWidth = shape.GetBoundingBoxMax()[0]
709 newHeight = shape.GetBoundingBoxMax()[1]
710 if shape._shadowMode != ogl.SHADOW_NONE:
711 newWidth -= shape._shadowOffsetX
712 newHeight -= shape._shadowOffsetY
713 newbounds = (newX, newY, newWidth, newHeight)
714
715 if x != newX or y != newY or w != newWidth or h != newHeight:
716 self._view.GetDocument().GetCommandProcessor().Submit(EditorCanvasUpdateShapeBoundariesCommand(self._view.GetDocument(), model, newbounds))
717
718
719 def Draw(self, dc):
720 pass
721
722
723 class EditorCanvasUpdateShapeBoundariesCommand(wx.lib.docview.Command):
724
725
726 def __init__(self, canvasDocument, model, newbounds):
727 wx.lib.docview.Command.__init__(self, canUndo = True)
728 self._canvasDocument = canvasDocument
729 self._model = model
730 self._oldbounds = model.getEditorBounds()
731 self._newbounds = newbounds
732
733
734 def GetName(self):
735 name = self._canvasDocument.GetNameForObject(self._model)
736 if not name:
737 name = ""
738 print "ERROR: AbstractEditor.EditorCanvasUpdateShapeBoundariesCommand.GetName: unable to get name for ", self._model
739 return _("Move/Resize %s") % name
740
741
742 def Do(self):
743 return self._canvasDocument.UpdateEditorBoundaries(self._model, self._newbounds)
744
745
746 def Undo(self):
747 return self._canvasDocument.UpdateEditorBoundaries(self._model, self._oldbounds)
748