LINE_BRUSH = wx.BLACK_BRUSH
INACTIVE_SELECT_BRUSH = wx.Brush("LIGHT BLUE", wx.SOLID)
+NORMALFONT = wx.SystemSettings.GetFont(wx.SYS_DEFAULT_GUI_FONT)
+SLANTFONT = wx.Font(NORMALFONT.GetPointSize(), NORMALFONT.GetFamily(), wx.SLANT, NORMALFONT.GetWeight())
+BOLDFONT = wx.Font(NORMALFONT.GetPointSize(), NORMALFONT.GetFamily(), NORMALFONT.GetStyle(), wx.BOLD)
+
+DEFAULT_BACKGROUND_COLOR = wx.Colour(0xEE, 0xEE, 0xEE)
+HEADER_BRUSH = wx.Brush(wx.Colour(0xDB, 0xEB, 0xFF), wx.SOLID)
+BODY_BRUSH = wx.Brush(wx.WHITE, wx.SOLID)
+
+
+PARKING_VERTICAL = 1
+PARKING_HORIZONTAL = 2
+PARKING_OFFSET = 30 # space between shapes
+
+FORCE_REDRAW_METHOD = "ForceRedraw"
def GetRawModel(model):
if hasattr(model, "GetRawModel"):
return rawModel
+def GetLabel(model):
+ model = GetRawModel(model)
+ if hasattr(model, "__xmlname__"):
+ label = model.__xmlname__
+ try:
+ if (len(label) > 0):
+ label = label[0].upper() + label[1:]
+ if (hasattr(model, "complexType")):
+ label += ': %s/%s' % (model.complexType.name, model.name)
+ else:
+ if model.name:
+ label += ': %s' % model.name
+ elif model.ref:
+ label += ': %s' % model.ref
+ except AttributeError:
+ pass
+ else:
+ label = str(model)
+ return label
+
+
class CanvasView(wx.lib.docview.View):
#----------------------------------------------------------------------------
- def __init__(self, brush = SHAPE_BRUSH):
+ def __init__(self, brush=SHAPE_BRUSH, background=DEFAULT_BACKGROUND_COLOR):
wx.lib.docview.View.__init__(self)
self._brush = brush
+ self._backgroundColor = background
self._canvas = None
self._pt1 = None
self._pt2 = None
self._needEraseLasso = False
self._propShape = None
+ self._maxWidth = 2000
+ self._maxHeight = 16000
+ self._valetParking = False
+ def OnDraw(self, dc):
+ """ for Print Preview and Print """
+ dc.BeginDrawing()
+ self._canvas.Redraw(dc)
+ dc.EndDrawing()
+
+
def OnCreate(self, doc, flags):
frame = wx.GetApp().CreateDocumentFrame(self, doc, flags)
frame.Show()
frame.SetSizer(sizer)
frame.Layout()
self.Activate()
+ wx.EVT_RIGHT_DOWN(self._canvas, self.OnRightClick)
return True
def OnFocus(self, event):
- self.SetFocus()
self.FocusColorPropertyShape(True)
event.Skip()
+ def FocusOnClick(self, event):
+ self.SetFocus()
+ event.Skip()
+
+
def OnKillFocus(self, event):
self.FocusColorPropertyShape(False)
event.Skip()
wx.EVT_KEY_DOWN(self._canvas, self.OnKeyPressed)
# need this otherwise mouse clicks don't set focus to this view
- wx.EVT_LEFT_DOWN(self._canvas, self.OnFocus)
- wx.EVT_LEFT_DCLICK(self._canvas, self.OnFocus)
- wx.EVT_RIGHT_DOWN(self._canvas, self.OnFocus)
- wx.EVT_RIGHT_DCLICK(self._canvas, self.OnFocus)
- wx.EVT_MIDDLE_DOWN(self._canvas, self.OnFocus)
- wx.EVT_MIDDLE_DCLICK(self._canvas, self.OnFocus)
+ wx.EVT_LEFT_DOWN(self._canvas, self.FocusOnClick)
+ wx.EVT_LEFT_DCLICK(self._canvas, self.FocusOnClick)
+ wx.EVT_RIGHT_DOWN(self._canvas, self.FocusOnClick)
+ wx.EVT_RIGHT_DCLICK(self._canvas, self.FocusOnClick)
+ wx.EVT_MIDDLE_DOWN(self._canvas, self.FocusOnClick)
+ wx.EVT_MIDDLE_DCLICK(self._canvas, self.FocusOnClick)
wx.EVT_KILL_FOCUS(self._canvas, self.OnKillFocus)
wx.EVT_SET_FOCUS(self._canvas, self.OnFocus)
- maxWidth = 2000
- maxHeight = 16000
- self._canvas.SetScrollbars(20, 20, maxWidth / 20, maxHeight / 20)
+ self._canvas.SetScrollbars(20, 20, self._maxWidth / 20, self._maxHeight / 20)
- self._canvas.SetBackgroundColour(wx.WHITE)
+ self._canvas.SetBackgroundColour(self._backgroundColor)
self._diagram = ogl.Diagram()
self._canvas.SetDiagram(self._diagram)
self._diagram.SetCanvas(self._canvas)
+ self._canvas.SetFont(NORMALFONT)
+
+ def OnClear(self, event):
+ """ Deletion of selected objects from view.
+ *Must Override*
+ """
+ self.SetPropertyModel(None)
+
+
+ def SetLastRightClick(self, x, y):
+ self._lastRightClick = (x,y)
+
+
+ def GetLastRightClick(self):
+ if hasattr(self, "_lastRightClick"):
+ return self._lastRightClick
+ return (-1,-1)
+
def OnKeyPressed(self, event):
key = event.KeyCode()
event.Skip()
+ def OnRightClick(self, event):
+ """ force selection underneath right click position. """
+ self.Activate()
+ self._canvas.SetFocus()
+
+ dc = wx.ClientDC(self._canvas)
+ self._canvas.PrepareDC(dc)
+ x, y = event.GetLogicalPosition(dc) # this takes into account scrollbar offset
+ self.SetLastRightClick(x, y)
+ shape = self._canvas.FindShape(x, y)[0]
+
+ model = None
+ if not shape:
+ self.SetSelection(None)
+ self.SetPropertyShape(None)
+ elif hasattr(shape, "GetModel"):
+ self.BringToFront(shape)
+ self.SetPropertyShape(shape)
+ self.SetSelection(shape)
+ shape.Select(True, dc)
+ model = shape.GetModel()
+ elif shape.GetParent() and isinstance(shape.GetParent(), ogl.CompositeShape): # ComplexTypeHeader for ComplexTypeShape
+ self.BringToFront(shape)
+ self.SetPropertyShape(shape.GetParent())
+ self.SetSelection(shape.GetParent())
+ shape.GetParent().Select(True, dc)
+ model = shape.GetParent().GetModel()
+
+ self.SetPropertyModel(model)
+
+ return (shape, model)
+
+
def OnLeftClick(self, event):
+ self.Activate()
+ self._canvas.SetFocus()
+
self.EraseRubberBand()
dc = wx.ClientDC(self._canvas)
pass
else:
# click on empty part of canvas, deselect everything
+ forceRedrawShapes = []
needRefresh = False
for shape in self._diagram.GetShapeList():
if hasattr(shape, "GetModel"):
if shape.Selected():
needRefresh = True
shape.Select(False, dc)
+ if hasattr(shape, FORCE_REDRAW_METHOD):
+ forceRedrawShapes.append(shape)
if needRefresh:
self._canvas.Redraw(dc)
if len(self.GetSelection()) == 0:
self.SetPropertyShape(None)
-
+ for shape in forceRedrawShapes:
+ shape.ForceRedraw()
def OnLeftDoubleClick(self, event):
propertyService = wx.GetApp().GetService(PropertyService.PropertyService)
dc.EndDrawing()
- def FindParkingSpot(self, width, height):
- """ given a width and height, find a upper left corner where shape can be parked without overlapping other shape """
- offset = 30 # space between shapes
- x = offset
- y = offset
- maxX = 700 # max distance to the right where we'll place tables
+ def SetValetParking(self, enable=True):
+ """ If valet parking is enabled, remember last parking spot and try for a spot near it """
+ self._valetParking = enable
+ if enable:
+ self._valetPosition = None
+
+
+ def FindParkingSpot(self, width, height, parking=PARKING_HORIZONTAL, x=PARKING_OFFSET, y=PARKING_OFFSET):
+ """
+ Given a width and height, find a upper left corner where shape can be parked without overlapping other shape
+ """
+ if self._valetParking and self._valetPosition:
+ x, y = self._valetPosition
+
+ max = 700 # max distance to the right where we'll place tables
noParkingSpot = True
while noParkingSpot:
point = self.isSpotOccupied(x, y, width, height)
if point:
- x = point[0] + offset
- if x > maxX:
- x = offset
- y = point[1] + offset
+ if parking == PARKING_HORIZONTAL:
+ x = point[0] + PARKING_OFFSET
+ if x > max:
+ x = PARKING_OFFSET
+ y = point[1] + PARKING_OFFSET
+ else: # parking == PARKING_VERTICAL:
+ y = point[1] + PARKING_OFFSET
+ if y > max:
+ y = PARKING_OFFSET
+ x = point[0] + PARKING_OFFSET
else:
noParkingSpot = False
+ if self._valetParking:
+ self._valetPosition = (x, y)
+
return x, y
y2 = y + height
for shape in self._diagram.GetShapeList():
- if isinstance(shape, ogl.RectangleShape) or isinstance(shape, ogl.EllipseShape):
+ if isinstance(shape, ogl.RectangleShape) or isinstance(shape, ogl.EllipseShape) or isinstance(shape, ogl.PolygonShape):
if shape.GetParent() and isinstance(shape.GetParent(), ogl.CompositeShape):
# skip, part of a composite shape
continue
# Canvas methods
#----------------------------------------------------------------------------
- def AddShape(self, shape, x = None, y = None, pen = None, brush = None, text = None, eventHandler = None):
+ def AddShape(self, shape, x = None, y = None, pen = None, brush = None, text = None, eventHandler = None, shown=True):
if isinstance(shape, ogl.CompositeShape):
dc = wx.ClientDC(self._canvas)
self._canvas.PrepareDC(dc)
shape.SetBrush(brush)
if text:
shape.AddText(text)
- shape.SetShadowMode(ogl.SHADOW_RIGHT)
+ shape.SetShadowMode(ogl.SHADOW_NONE)
self._diagram.AddShape(shape)
- shape.Show(True)
+ shape.Show(shown)
if not eventHandler:
eventHandler = EditorCanvasShapeEvtHandler(self)
eventHandler.SetShape(shape)
if shape:
shape.Select(False)
- self._diagram.RemoveShape(shape)
- if isinstance(shape, ogl.CompositeShape):
+ for line in shape.GetLines():
+ shape.RemoveLine(line)
+ self._diagram.RemoveShape(line)
+ line.Delete()
+ for obj in self._diagram.GetShapeList():
+ for line in obj.GetLines():
+ if self.IsShapeContained(shape, line.GetTo()) or self.IsShapeContained(shape, line.GetFrom()):
+ obj.RemoveLine(line)
+ self._diagram.RemoveShape(line)
+ line.Delete()
+ if line == shape:
+ obj.RemoveLine(line)
+ self._diagram.RemoveShape(line)
+ line.Delete()
+
+ if self._canvas:
shape.RemoveFromCanvas(self._canvas)
+ self._diagram.RemoveShape(shape)
+ shape.Delete()
+
+
+ def IsShapeContained(self, parent, shape):
+ if parent == shape:
+ return True
+ elif shape.GetParent():
+ return self.IsShapeContained(parent, shape.GetParent())
+
+ return False
def UpdateShape(self, model):
for shape in self._diagram.GetShapeList():
if hasattr(shape, "GetModel") and shape.GetModel() == model:
+ oldw, oldh = shape.GetBoundingBoxMax()
+ oldx = shape.GetX()
+ oldy = shape.GetY()
+
x, y, w, h = model.getEditorBounds()
newX = x + w / 2
newY = y + h / 2
- changed = False
- if isinstance(shape, ogl.CompositeShape):
- if shape.GetX() != newX or shape.GetY() != newY:
- dc = wx.ClientDC(self._canvas)
- self._canvas.PrepareDC(dc)
- shape.SetSize(w, h, True) # wxBug: SetSize must be before Move because links won't go to the right place
- shape.Move(dc, newX, newY) # wxBug: Move must be before SetSize because links won't go to the right place
- changed = True
- else:
- oldw, oldh = shape.GetBoundingBoxMax()
- oldx = shape.GetX()
- oldy = shape.GetY()
- if oldw != w or oldh != h or oldx != newX or oldy != newY:
- shape.SetSize(w, h)
- shape.SetX(newX)
- shape.SetY(newY)
- changed = True
- if changed:
+
+ if oldw != w or oldh != h or oldx != newX or oldy != newY:
+ dc = wx.ClientDC(self._canvas)
+ self._canvas.PrepareDC(dc)
+ shape.SetSize(w, h, True) # wxBug: SetSize must be before Move because links won't go to the right place
+ shape.Move(dc, newX, newY) # wxBug: Move must be after SetSize because links won't go to the right place
shape.ResetControlPoints()
self._canvas.Refresh()
+
break
return None
+ def GetShapeCount(self):
+ return self._diagram.GetCount()
+
+
def GetSelection(self):
return filter(lambda shape: shape.Selected(), self._diagram.GetShapeList())
def ScrollVisible(self, shape):
- xUnit, yUnit = shape._canvas.GetScrollPixelsPerUnit()
+ if not shape:
+ return
+
+ xUnit, yUnit = self._canvas.GetScrollPixelsPerUnit()
scrollX, scrollY = self._canvas.GetViewStart() # in scroll units
scrollW, scrollH = self._canvas.GetSize() # in pixels
w, h = shape.GetBoundingBoxMax() # in pixels
# erase old selection if it still exists
if self._propShape and self._propShape in self._diagram.GetShapeList():
- self._propShape.SetBrush(self._brush)
+ if hasattr(self._propShape, "DEFAULT_BRUSH"):
+ self._propShape.SetBrush(self._propShape.DEFAULT_BRUSH)
+ else:
+ self._propShape.SetBrush(self._brush)
if (self._propShape._textColourName in ["BLACK", "WHITE"]): # Would use GetTextColour() but it is broken
self._propShape.SetTextColour("BLACK", 0)
self._propShape.Draw(dc)
self._propShape.SetTextColour("WHITE", 0)
self._propShape.Draw(dc)
+ if hasattr(self._propShape, FORCE_REDRAW_METHOD):
+ self._propShape.ForceRedraw()
+
dc.EndDrawing()
if shape:
model = shape.GetModel()
- self._view.SetSelection(model, keys == self.SHIFT_KEY or keys == self.CONTROL_KEY)
- self._view.SetPropertyShape(shape)
- self._view.SetPropertyModel(model)
+ if model:
+ self._view.SetSelection(model, keys == self.SHIFT_KEY or keys == self.CONTROL_KEY)
+ self._view.SetPropertyShape(shape)
+ self._view.SetPropertyModel(model)
def OnEndDragLeft(self, x, y, keys = 0, attachment = 0):
self._view.SetSelection(model, keys == self.SHIFT_KEY or keys == self.CONTROL_KEY)
+ def OnMovePre(self, dc, x, y, oldX, oldY, display):
+ """ Prevent objects from being dragged outside of viewable area """
+ if (x < 0) or (y < 0) or (x > self._view._maxWidth) or (y > self._view._maxHeight):
+ return False
+
+ return ogl.ShapeEvtHandler.OnMovePre(self, dc, x, y, oldX, oldY, display)
+
+
def OnMovePost(self, dc, x, y, oldX, oldY, display):
+ """ Update the model's record of where the shape should be. Also enable redo/undo. """
if x == oldX and y == oldY:
return
if not self._view.GetDocument():