1 #----------------------------------------------------------------------------
2 # Name: AbstractEditor.py
3 # Purpose: Non-text editor for DataModel and Process
5 # Author: Peter Yared, Morgan Hua
9 # Copyright: (c) 2004-2005 ActiveGrid, Inc.
10 # License: wxWindows License
11 #----------------------------------------------------------------------------
16 import wx
.lib
.ogl
as ogl
17 import PropertyService
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
)
26 NORMALFONT
= wx
.SystemSettings
.GetFont(wx
.SYS_DEFAULT_GUI_FONT
)
27 SLANTFONT
= wx
.Font(NORMALFONT
.GetPointSize(), NORMALFONT
.GetFamily(), wx
.SLANT
, NORMALFONT
.GetWeight())
28 BOLDFONT
= wx
.Font(NORMALFONT
.GetPointSize(), NORMALFONT
.GetFamily(), NORMALFONT
.GetStyle(), wx
.BOLD
)
30 DEFAULT_BACKGROUND_COLOR
= wx
.Colour(0xEE, 0xEE, 0xEE)
31 HEADER_BRUSH
= wx
.Brush(wx
.Colour(0xDB, 0xEB, 0xFF), wx
.SOLID
)
32 BODY_BRUSH
= wx
.Brush(wx
.WHITE
, wx
.SOLID
)
36 PARKING_HORIZONTAL
= 2
37 PARKING_OFFSET
= 30 # space between shapes
39 FORCE_REDRAW_METHOD
= "ForceRedraw"
41 def GetRawModel(model
):
42 if hasattr(model
, "GetRawModel"):
43 rawModel
= model
.GetRawModel()
50 model
= GetRawModel(model
)
51 if hasattr(model
, "__xmlname__"):
52 label
= model
.__xmlname
__
55 label
= label
[0].upper() + label
[1:]
56 if (hasattr(model
, "complexType")):
57 label
+= ': %s/%s' % (model
.complexType
.name
, model
.name
)
60 label
+= ': %s' % model
.name
62 label
+= ': %s' % model
.ref
63 except AttributeError:
70 class CanvasView(wx
.lib
.docview
.View
):
73 #----------------------------------------------------------------------------
75 #----------------------------------------------------------------------------
78 def __init__(self
, brush
=SHAPE_BRUSH
, background
=DEFAULT_BACKGROUND_COLOR
):
79 wx
.lib
.docview
.View
.__init
__(self
)
81 self
._backgroundColor
= background
85 self
._needEraseLasso
= False
86 self
._propShape
= None
88 self
._maxHeight
= 16000
89 self
._valetParking
= False
93 """ for Print Preview and Print """
95 self
._canvas
.Redraw(dc
)
99 def OnCreate(self
, doc
, flags
):
100 frame
= wx
.GetApp().CreateDocumentFrame(self
, doc
, flags
)
102 sizer
= wx
.BoxSizer()
103 self
._CreateCanvas
(frame
)
104 sizer
.Add(self
._canvas
, 1, wx
.EXPAND
, 0)
105 frame
.SetSizer(sizer
)
108 wx
.EVT_RIGHT_DOWN(self
._canvas
, self
.OnRightClick
)
112 def OnActivateView(self
, activate
, activeView
, deactiveView
):
113 if activate
and self
._canvas
:
114 # In MDI mode just calling set focus doesn't work and in SDI mode using CallAfter causes an endless loop
115 if self
.GetDocumentManager().GetFlags() & wx
.lib
.docview
.DOC_SDI
:
118 wx
.CallAfter(self
.SetFocus
)
123 self
._canvas
.SetFocus()
126 def OnFocus(self
, event
):
127 self
.FocusColorPropertyShape(True)
131 def FocusOnClick(self
, event
):
136 def OnKillFocus(self
, event
):
137 self
.FocusColorPropertyShape(False)
142 winWithFocus
= wx
.Window
.FindFocus()
146 if winWithFocus
== self
._canvas
:
148 winWithFocus
= winWithFocus
.GetParent()
152 def OnClose(self
, deleteWindow
= True):
153 statusC
= wx
.GetApp().CloseChildDocuments(self
.GetDocument())
154 statusP
= wx
.lib
.docview
.View
.OnClose(self
, deleteWindow
= deleteWindow
)
155 if hasattr(self
, "ClearOutline"):
156 wx
.CallAfter(self
.ClearOutline
) # need CallAfter because when closing the document, it is Activated and then Close, so need to match OnActivateView's CallAfter
157 if not (statusC
and statusP
):
160 if deleteWindow
and self
.GetFrame():
161 self
.GetFrame().Destroy()
165 def _CreateCanvas(self
, parent
):
166 self
._canvas
= ogl
.ShapeCanvas(parent
)
167 wx
.EVT_LEFT_DOWN(self
._canvas
, self
.OnLeftClick
)
168 wx
.EVT_LEFT_UP(self
._canvas
, self
.OnLeftUp
)
169 wx
.EVT_MOTION(self
._canvas
, self
.OnLeftDrag
)
170 wx
.EVT_LEFT_DCLICK(self
._canvas
, self
.OnLeftDoubleClick
)
171 wx
.EVT_KEY_DOWN(self
._canvas
, self
.OnKeyPressed
)
173 # need this otherwise mouse clicks don't set focus to this view
174 wx
.EVT_LEFT_DOWN(self
._canvas
, self
.FocusOnClick
)
175 wx
.EVT_LEFT_DCLICK(self
._canvas
, self
.FocusOnClick
)
176 wx
.EVT_RIGHT_DOWN(self
._canvas
, self
.FocusOnClick
)
177 wx
.EVT_RIGHT_DCLICK(self
._canvas
, self
.FocusOnClick
)
178 wx
.EVT_MIDDLE_DOWN(self
._canvas
, self
.FocusOnClick
)
179 wx
.EVT_MIDDLE_DCLICK(self
._canvas
, self
.FocusOnClick
)
181 wx
.EVT_KILL_FOCUS(self
._canvas
, self
.OnKillFocus
)
182 wx
.EVT_SET_FOCUS(self
._canvas
, self
.OnFocus
)
184 self
._canvas
.SetScrollbars(20, 20, self
._maxWidth
/ 20, self
._maxHeight
/ 20)
186 self
._canvas
.SetBackgroundColour(self
._backgroundColor
)
187 self
._diagram
= ogl
.Diagram()
188 self
._canvas
.SetDiagram(self
._diagram
)
189 self
._diagram
.SetCanvas(self
._canvas
)
190 self
._canvas
.SetFont(NORMALFONT
)
193 def OnClear(self
, event
):
194 """ Deletion of selected objects from view.
197 self
.SetPropertyModel(None)
200 def SetLastRightClick(self
, x
, y
):
201 self
._lastRightClick
= (x
,y
)
204 def GetLastRightClick(self
):
205 if hasattr(self
, "_lastRightClick"):
206 return self
._lastRightClick
210 def OnKeyPressed(self
, event
):
211 key
= event
.KeyCode()
212 if key
== wx
.WXK_DELETE
:
218 def OnRightClick(self
, event
):
219 """ force selection underneath right click position. """
221 self
._canvas
.SetFocus()
223 dc
= wx
.ClientDC(self
._canvas
)
224 self
._canvas
.PrepareDC(dc
)
225 x
, y
= event
.GetLogicalPosition(dc
) # this takes into account scrollbar offset
226 self
.SetLastRightClick(x
, y
)
227 shape
= self
._canvas
.FindShape(x
, y
)[0]
231 self
.SetSelection(None)
232 self
.SetPropertyShape(None)
233 elif hasattr(shape
, "GetModel"):
234 self
.BringToFront(shape
)
235 self
.SetPropertyShape(shape
)
236 self
.SetSelection(shape
)
237 shape
.Select(True, dc
)
238 model
= shape
.GetModel()
239 elif shape
.GetParent() and isinstance(shape
.GetParent(), ogl
.CompositeShape
): # ComplexTypeHeader for ComplexTypeShape
240 self
.BringToFront(shape
)
241 self
.SetPropertyShape(shape
.GetParent())
242 self
.SetSelection(shape
.GetParent())
243 shape
.GetParent().Select(True, dc
)
244 model
= shape
.GetParent().GetModel()
246 self
.SetPropertyModel(model
)
248 return (shape
, model
)
251 def OnLeftClick(self
, event
):
253 self
._canvas
.SetFocus()
255 self
.EraseRubberBand()
257 dc
= wx
.ClientDC(self
._canvas
)
258 self
._canvas
.PrepareDC(dc
)
260 # keep track of mouse down for group select
261 self
._pt
1 = event
.GetLogicalPosition(dc
) # this takes into account scrollbar offset
264 shape
= self
._canvas
.FindShape(self
._pt
1[0], self
._pt
1[1])[0]
266 self
.BringToFront(shape
)
269 event
.Skip() # pass on event to shape handler to take care of selection
272 elif event
.ControlDown() or event
.ShiftDown(): # extend select, don't deselect
275 # click on empty part of canvas, deselect everything
276 forceRedrawShapes
= []
278 for shape
in self
._diagram
.GetShapeList():
279 if hasattr(shape
, "GetModel"):
282 shape
.Select(False, dc
)
283 if hasattr(shape
, FORCE_REDRAW_METHOD
):
284 forceRedrawShapes
.append(shape
)
286 self
._canvas
.Redraw(dc
)
288 self
.SetPropertyModel(None)
290 if len(self
.GetSelection()) == 0:
291 self
.SetPropertyShape(None)
293 for shape
in forceRedrawShapes
:
296 def OnLeftDoubleClick(self
, event
):
297 propertyService
= wx
.GetApp().GetService(PropertyService
.PropertyService
)
299 propertyService
.ShowWindow()
302 def OnLeftDrag(self
, event
):
303 # draw lasso for group select
304 if self
._pt
1 and event
.LeftIsDown(): # we are in middle of lasso selection
305 self
.EraseRubberBand()
307 dc
= wx
.ClientDC(self
._canvas
)
308 self
._canvas
.PrepareDC(dc
)
309 self
._pt
2 = event
.GetLogicalPosition(dc
) # this takes into account scrollbar offset
310 self
.DrawRubberBand()
315 def OnLeftUp(self
, event
):
317 if self
._needEraseLasso
:
318 self
.EraseRubberBand()
320 dc
= wx
.ClientDC(self
._canvas
)
321 self
._canvas
.PrepareDC(dc
)
323 x2
, y2
= event
.GetLogicalPosition(dc
) # this takes into account scrollbar offset
325 tol
= self
._diagram
.GetMouseTolerance()
326 if abs(x1
- x2
) > tol
or abs(y1
- y2
) > tol
:
327 # make sure x1 < x2 and y1 < y2 to make comparison test easier
337 for shape
in self
._diagram
.GetShapeList():
338 if not shape
.GetParent() and hasattr(shape
, "GetModel"): # if part of a composite, don't select it
339 x
, y
= shape
.GetX(), shape
.GetY()
340 width
, height
= shape
.GetBoundingBoxMax()
341 selected
= x1
< x
- width
/2 and x2
> x
+ width
/2 and y1
< y
- height
/2 and y2
> y
+ height
/2
342 if event
.ControlDown() or event
.ShiftDown(): # extend select, don't deselect
344 shape
.Select(selected
, dc
)
345 else: # select items in lasso and deselect items out of lasso
346 shape
.Select(selected
, dc
)
347 self
._canvas
.Redraw(dc
)
354 def EraseRubberBand(self
):
355 if self
._needEraseLasso
:
356 self
._needEraseLasso
= False
358 dc
= wx
.ClientDC(self
._canvas
)
359 self
._canvas
.PrepareDC(dc
)
360 dc
.SetLogicalFunction(wx
.XOR
)
361 pen
= wx
.Pen(wx
.Colour(200, 200, 200), 1, wx
.SHORT_DASH
)
363 brush
= wx
.Brush(wx
.Colour(255, 255, 255), wx
.TRANSPARENT
)
365 dc
.ResetBoundingBox()
371 # make sure x1 < x2 and y1 < y2
372 # this will make (x1, y1) = upper left corner
382 # erase previous outline
383 dc
.SetClippingRegion(x1
, y1
, x2
- x1
, y2
- y1
)
384 dc
.DrawRectangle(x1
, y1
, x2
- x1
, y2
- y1
)
388 def DrawRubberBand(self
):
389 self
._needEraseLasso
= True
391 dc
= wx
.ClientDC(self
._canvas
)
392 self
._canvas
.PrepareDC(dc
)
393 dc
.SetLogicalFunction(wx
.XOR
)
394 pen
= wx
.Pen(wx
.Colour(200, 200, 200), 1, wx
.SHORT_DASH
)
396 brush
= wx
.Brush(wx
.Colour(255, 255, 255), wx
.TRANSPARENT
)
398 dc
.ResetBoundingBox()
404 # make sure x1 < x2 and y1 < y2
405 # this will make (x1, y1) = upper left corner
416 dc
.SetClippingRegion(x1
, y1
, x2
- x1
, y2
- y1
)
417 dc
.DrawRectangle(x1
, y1
, x2
- x1
, y2
- y1
)
421 def SetValetParking(self
, enable
=True):
422 """ If valet parking is enabled, remember last parking spot and try for a spot near it """
423 self
._valetParking
= enable
425 self
._valetPosition
= None
428 def FindParkingSpot(self
, width
, height
, parking
=PARKING_HORIZONTAL
, x
=PARKING_OFFSET
, y
=PARKING_OFFSET
):
430 Given a width and height, find a upper left corner where shape can be parked without overlapping other shape
432 if self
._valetParking
and self
._valetPosition
:
433 x
, y
= self
._valetPosition
435 max = 700 # max distance to the right where we'll place tables
439 point
= self
.isSpotOccupied(x
, y
, width
, height
)
441 if parking
== PARKING_HORIZONTAL
:
442 x
= point
[0] + PARKING_OFFSET
445 y
= point
[1] + PARKING_OFFSET
446 else: # parking == PARKING_VERTICAL:
447 y
= point
[1] + PARKING_OFFSET
450 x
= point
[0] + PARKING_OFFSET
452 noParkingSpot
= False
454 if self
._valetParking
:
455 self
._valetPosition
= (x
, y
)
460 def isSpotOccupied(self
, x
, y
, width
, height
):
461 """ returns None if at x,y,width,height no object occupies that rectangle,
462 otherwise returns lower right corner of object that occupies given x,y position
467 for shape
in self
._diagram
.GetShapeList():
468 if isinstance(shape
, ogl
.RectangleShape
) or isinstance(shape
, ogl
.EllipseShape
) or isinstance(shape
, ogl
.PolygonShape
):
469 if shape
.GetParent() and isinstance(shape
.GetParent(), ogl
.CompositeShape
):
470 # skip, part of a composite shape
473 if hasattr(shape
, "GetModel"):
474 other_x
, other_y
, other_width
, other_height
= shape
.GetModel().getEditorBounds()
475 other_x2
= other_x
+ other_width
476 other_y2
= other_y
+ other_height
478 # shapes x,y are at the center of the shape, need to transform to upper left coordinate
479 other_width
, other_height
= shape
.GetBoundingBoxMax()
480 other_x
= shape
.GetX() - other_width
/2
481 other_y
= shape
.GetY() - other_height
/2
483 other_x2
= other_x
+ other_width
484 other_y2
= other_y
+ other_height
486 if ((other_x2
< other_x
or other_x2
> x
) and
487 (other_y2
< other_y
or other_y2
> y
) and
488 (x2
< x
or x2
> other_x
) and
489 (y2
< y
or y2
> other_y
)):
490 return (other_x2
, other_y2
)
494 #----------------------------------------------------------------------------
496 #----------------------------------------------------------------------------
498 def AddShape(self
, shape
, x
= None, y
= None, pen
= None, brush
= None, text
= None, eventHandler
= None, shown
=True):
499 if isinstance(shape
, ogl
.CompositeShape
):
500 dc
= wx
.ClientDC(self
._canvas
)
501 self
._canvas
.PrepareDC(dc
)
504 shape
.SetDraggable(True, True)
505 shape
.SetCanvas(self
._canvas
)
511 shape
.SetCentreResize(False)
515 shape
.SetBrush(brush
)
518 shape
.SetShadowMode(ogl
.SHADOW_NONE
)
519 self
._diagram
.AddShape(shape
)
522 eventHandler
= EditorCanvasShapeEvtHandler(self
)
523 eventHandler
.SetShape(shape
)
524 eventHandler
.SetPreviousHandler(shape
.GetEventHandler())
525 shape
.SetEventHandler(eventHandler
)
529 def RemoveShape(self
, model
= None, shape
= None):
530 if not model
and not shape
:
534 shape
= self
.GetShape(model
)
538 for line
in shape
.GetLines():
539 shape
.RemoveLine(line
)
540 self
._diagram
.RemoveShape(line
)
542 for obj
in self
._diagram
.GetShapeList():
543 for line
in obj
.GetLines():
544 if self
.IsShapeContained(shape
, line
.GetTo()) or self
.IsShapeContained(shape
, line
.GetFrom()):
546 self
._diagram
.RemoveShape(line
)
550 self
._diagram
.RemoveShape(line
)
554 shape
.RemoveFromCanvas(self
._canvas
)
555 self
._diagram
.RemoveShape(shape
)
559 def IsShapeContained(self
, parent
, shape
):
562 elif shape
.GetParent():
563 return self
.IsShapeContained(parent
, shape
.GetParent())
568 def UpdateShape(self
, model
):
569 for shape
in self
._diagram
.GetShapeList():
570 if hasattr(shape
, "GetModel") and shape
.GetModel() == model
:
571 oldw
, oldh
= shape
.GetBoundingBoxMax()
575 x
, y
, w
, h
= model
.getEditorBounds()
579 if oldw
!= w
or oldh
!= h
or oldx
!= newX
or oldy
!= newY
:
580 dc
= wx
.ClientDC(self
._canvas
)
581 self
._canvas
.PrepareDC(dc
)
582 shape
.SetSize(w
, h
, True) # wxBug: SetSize must be before Move because links won't go to the right place
583 shape
.Move(dc
, newX
, newY
) # wxBug: Move must be after SetSize because links won't go to the right place
584 shape
.ResetControlPoints()
585 self
._canvas
.Refresh()
590 def GetShape(self
, model
):
591 for shape
in self
._diagram
.GetShapeList():
592 if hasattr(shape
, "GetModel") and shape
.GetModel() == model
:
597 def GetShapeCount(self
):
598 return self
._diagram
.GetCount()
601 def GetSelection(self
):
602 return filter(lambda shape
: shape
.Selected(), self
._diagram
.GetShapeList())
605 def SetSelection(self
, models
, extendSelect
= False):
606 dc
= wx
.ClientDC(self
._canvas
)
607 self
._canvas
.PrepareDC(dc
)
609 if not isinstance(models
, type([])) and not isinstance(models
, type(())):
611 for shape
in self
._diagram
.GetShapeList():
612 if hasattr(shape
, "GetModel"):
613 if shape
.Selected() and not shape
.GetModel() in models
: # was selected, but not in new list, so deselect, unless extend select
615 shape
.Select(False, dc
)
617 elif not shape
.Selected() and shape
.GetModel() in models
: # was not selected and in new list, so select
618 shape
.Select(True, dc
)
620 elif extendSelect
and shape
.Selected() and shape
.GetModel() in models
: # was selected, but extend select means to deselect
621 shape
.Select(False, dc
)
624 self
._canvas
.Redraw(dc
)
627 def BringToFront(self
, shape
):
628 if shape
.GetParent() and isinstance(shape
.GetParent(), ogl
.CompositeShape
):
629 self
._diagram
.RemoveShape(shape
.GetParent())
630 self
._diagram
.AddShape(shape
.GetParent())
632 self
._diagram
.RemoveShape(shape
)
633 self
._diagram
.AddShape(shape
)
636 def SendToBack(self
, shape
):
637 if shape
.GetParent() and isinstance(shape
.GetParent(), ogl
.CompositeShape
):
638 self
._diagram
.RemoveShape(shape
.GetParent())
639 self
._diagram
.InsertShape(shape
.GetParent())
641 self
._diagram
.RemoveShape(shape
)
642 self
._diagram
.InsertShape(shape
)
645 def ScrollVisible(self
, shape
):
649 xUnit
, yUnit
= self
._canvas
.GetScrollPixelsPerUnit()
650 scrollX
, scrollY
= self
._canvas
.GetViewStart() # in scroll units
651 scrollW
, scrollH
= self
._canvas
.GetSize() # in pixels
652 w
, h
= shape
.GetBoundingBoxMax() # in pixels
653 x
= shape
.GetX() - w
/2 # convert to upper left coordinate from center
654 y
= shape
.GetY() - h
/2 # convert to upper left coordinate from center
656 if x
>= scrollX
*xUnit
and x
<= scrollX
*xUnit
+ scrollW
: # don't scroll if already visible
661 if y
>= scrollY
*yUnit
and y
<= scrollY
*yUnit
+ scrollH
: # don't scroll if already visible
666 self
._canvas
.Scroll(x
, y
) # in scroll units
669 def SetPropertyShape(self
, shape
):
670 # no need to highlight if no PropertyService is running
671 propertyService
= wx
.GetApp().GetService(PropertyService
.PropertyService
)
672 if not propertyService
:
675 if shape
== self
._propShape
:
678 if hasattr(shape
, "GetPropertyShape"):
679 shape
= shape
.GetPropertyShape()
681 dc
= wx
.ClientDC(self
._canvas
)
682 self
._canvas
.PrepareDC(dc
)
685 # erase old selection if it still exists
686 if self
._propShape
and self
._propShape
in self
._diagram
.GetShapeList():
687 if hasattr(self
._propShape
, "DEFAULT_BRUSH"):
688 self
._propShape
.SetBrush(self
._propShape
.DEFAULT_BRUSH
)
690 self
._propShape
.SetBrush(self
._brush
)
691 if (self
._propShape
._textColourName
in ["BLACK", "WHITE"]): # Would use GetTextColour() but it is broken
692 self
._propShape
.SetTextColour("BLACK", 0)
693 self
._propShape
.Draw(dc
)
696 self
._propShape
= shape
699 if self
._propShape
and self
._propShape
in self
._diagram
.GetShapeList():
701 self
._propShape
.SetBrush(SELECT_BRUSH
)
703 self
._propShape
.SetBrush(INACTIVE_SELECT_BRUSH
)
704 if (self
._propShape
._textColourName
in ["BLACK", "WHITE"]): # Would use GetTextColour() but it is broken
705 self
._propShape
.SetTextColour("WHITE", 0)
706 self
._propShape
.Draw(dc
)
711 def FocusColorPropertyShape(self
, gotFocus
=False):
712 # no need to change highlight if no PropertyService is running
713 propertyService
= wx
.GetApp().GetService(PropertyService
.PropertyService
)
714 if not propertyService
:
717 if not self
._propShape
:
720 dc
= wx
.ClientDC(self
._canvas
)
721 self
._canvas
.PrepareDC(dc
)
724 # draw deactivated selection
725 if self
._propShape
and self
._propShape
in self
._diagram
.GetShapeList():
727 self
._propShape
.SetBrush(SELECT_BRUSH
)
729 self
._propShape
.SetBrush(INACTIVE_SELECT_BRUSH
)
730 if (self
._propShape
._textColourName
in ["BLACK", "WHITE"]): # Would use GetTextColour() but it is broken
731 self
._propShape
.SetTextColour("WHITE", 0)
732 self
._propShape
.Draw(dc
)
734 if hasattr(self
._propShape
, FORCE_REDRAW_METHOD
):
735 self
._propShape
.ForceRedraw()
740 #----------------------------------------------------------------------------
741 # Property Service methods
742 #----------------------------------------------------------------------------
744 def GetPropertyModel(self
):
745 if hasattr(self
, "_propModel"):
746 return self
._propModel
750 def SetPropertyModel(self
, model
):
751 # no need to set the model if no PropertyService is running
752 propertyService
= wx
.GetApp().GetService(PropertyService
.PropertyService
)
753 if not propertyService
:
756 if hasattr(self
, "_propModel") and model
== self
._propModel
:
759 self
._propModel
= model
760 propertyService
.LoadProperties(self
._propModel
, self
.GetDocument())
763 class EditorCanvasShapeMixin
:
769 def SetModel(self
, model
):
773 class EditorCanvasShapeEvtHandler(ogl
.ShapeEvtHandler
):
775 """ wxBug: Bug in OLG package. With wxShape.SetShadowMode() turned on, when we set the size,
776 the width/height is larger by 6 pixels. Need to subtract this value from width and height when we
782 def __init__(self
, view
):
783 ogl
.ShapeEvtHandler
.__init
__(self
)
787 def OnLeftClick(self
, x
, y
, keys
= 0, attachment
= 0):
788 shape
= self
.GetShape()
789 if hasattr(shape
, "GetModel"): # Workaround, on drag, we should deselect all other objects and select the clicked on object
790 model
= shape
.GetModel()
792 shape
= shape
.GetParent()
794 model
= shape
.GetModel()
797 self
._view
.SetSelection(model
, keys
== self
.SHIFT_KEY
or keys
== self
.CONTROL_KEY
)
798 self
._view
.SetPropertyShape(shape
)
799 self
._view
.SetPropertyModel(model
)
802 def OnEndDragLeft(self
, x
, y
, keys
= 0, attachment
= 0):
803 ogl
.ShapeEvtHandler
.OnEndDragLeft(self
, x
, y
, keys
, attachment
)
804 shape
= self
.GetShape()
805 if hasattr(shape
, "GetModel"): # Workaround, on drag, we should deselect all other objects and select the clicked on object
806 model
= shape
.GetModel()
808 parentShape
= shape
.GetParent()
810 model
= parentShape
.GetModel()
811 self
._view
.SetSelection(model
, keys
== self
.SHIFT_KEY
or keys
== self
.CONTROL_KEY
)
814 def OnMovePre(self
, dc
, x
, y
, oldX
, oldY
, display
):
815 """ Prevent objects from being dragged outside of viewable area """
816 if (x
< 0) or (y
< 0) or (x
> self
._view
._maxWidth
) or (y
> self
._view
._maxHeight
):
819 return ogl
.ShapeEvtHandler
.OnMovePre(self
, dc
, x
, y
, oldX
, oldY
, display
)
822 def OnMovePost(self
, dc
, x
, y
, oldX
, oldY
, display
):
823 """ Update the model's record of where the shape should be. Also enable redo/undo. """
824 if x
== oldX
and y
== oldY
:
826 if not self
._view
.GetDocument():
828 shape
= self
.GetShape()
829 if isinstance(shape
, EditorCanvasShapeMixin
) and shape
.Draggable():
830 model
= shape
.GetModel()
831 if hasattr(model
, "getEditorBounds") and model
.getEditorBounds():
832 x
, y
, w
, h
= model
.getEditorBounds()
833 newX
= shape
.GetX() - shape
.GetBoundingBoxMax()[0] / 2
834 newY
= shape
.GetY() - shape
.GetBoundingBoxMax()[1] / 2
835 newWidth
= shape
.GetBoundingBoxMax()[0]
836 newHeight
= shape
.GetBoundingBoxMax()[1]
837 if shape
._shadowMode
!= ogl
.SHADOW_NONE
:
838 newWidth
-= shape
._shadowOffsetX
839 newHeight
-= shape
._shadowOffsetY
840 newbounds
= (newX
, newY
, newWidth
, newHeight
)
842 if x
!= newX
or y
!= newY
or w
!= newWidth
or h
!= newHeight
:
843 self
._view
.GetDocument().GetCommandProcessor().Submit(EditorCanvasUpdateShapeBoundariesCommand(self
._view
.GetDocument(), model
, newbounds
))
850 class EditorCanvasUpdateShapeBoundariesCommand(wx
.lib
.docview
.Command
):
853 def __init__(self
, canvasDocument
, model
, newbounds
):
854 wx
.lib
.docview
.Command
.__init
__(self
, canUndo
= True)
855 self
._canvasDocument
= canvasDocument
857 self
._oldbounds
= model
.getEditorBounds()
858 self
._newbounds
= newbounds
862 name
= self
._canvasDocument
.GetNameForObject(self
._model
)
865 print "ERROR: AbstractEditor.EditorCanvasUpdateShapeBoundariesCommand.GetName: unable to get name for ", self
._model
866 return _("Move/Resize %s") % name
870 return self
._canvasDocument
.UpdateEditorBoundaries(self
._model
, self
._newbounds
)
874 return self
._canvasDocument
.UpdateEditorBoundaries(self
._model
, self
._oldbounds
)