X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/6f1a3f9c1a056e5ae063f020d38a5f40cc5e85ef..908f8fc481c0503bf8be5002e5d5208666da7649:/wxPython/samples/ide/activegrid/tool/AbstractEditor.py diff --git a/wxPython/samples/ide/activegrid/tool/AbstractEditor.py b/wxPython/samples/ide/activegrid/tool/AbstractEditor.py index 8369738428..8a2e9c5232 100644 --- a/wxPython/samples/ide/activegrid/tool/AbstractEditor.py +++ b/wxPython/samples/ide/activegrid/tool/AbstractEditor.py @@ -23,6 +23,20 @@ SHAPE_BRUSH = wx.Brush("WHEAT", wx.SOLID) 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"): @@ -32,6 +46,27 @@ def GetRawModel(model): 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): @@ -40,16 +75,27 @@ 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() @@ -59,6 +105,7 @@ class CanvasView(wx.lib.docview.View): frame.SetSizer(sizer) frame.Layout() self.Activate() + wx.EVT_RIGHT_DOWN(self._canvas, self.OnRightClick) return True @@ -77,11 +124,15 @@ class CanvasView(wx.lib.docview.View): 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() @@ -120,25 +171,41 @@ class CanvasView(wx.lib.docview.View): 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() @@ -148,7 +215,43 @@ class CanvasView(wx.lib.docview.View): 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) @@ -170,12 +273,15 @@ class CanvasView(wx.lib.docview.View): 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) @@ -184,7 +290,8 @@ class CanvasView(wx.lib.docview.View): if len(self.GetSelection()) == 0: self.SetPropertyShape(None) - + for shape in forceRedrawShapes: + shape.ForceRedraw() def OnLeftDoubleClick(self, event): propertyService = wx.GetApp().GetService(PropertyService.PropertyService) @@ -311,24 +418,42 @@ class CanvasView(wx.lib.docview.View): 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 @@ -340,7 +465,7 @@ class CanvasView(wx.lib.docview.View): 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 @@ -370,7 +495,7 @@ class CanvasView(wx.lib.docview.View): # 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) @@ -390,9 +515,9 @@ class CanvasView(wx.lib.docview.View): 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) @@ -410,37 +535,55 @@ class CanvasView(wx.lib.docview.View): 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 @@ -451,6 +594,10 @@ class CanvasView(wx.lib.docview.View): return None + def GetShapeCount(self): + return self._diagram.GetCount() + + def GetSelection(self): return filter(lambda shape: shape.Selected(), self._diagram.GetShapeList()) @@ -496,7 +643,10 @@ class CanvasView(wx.lib.docview.View): 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 @@ -534,7 +684,10 @@ class CanvasView(wx.lib.docview.View): # 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) @@ -578,6 +731,9 @@ class CanvasView(wx.lib.docview.View): self._propShape.SetTextColour("WHITE", 0) self._propShape.Draw(dc) + if hasattr(self._propShape, FORCE_REDRAW_METHOD): + self._propShape.ForceRedraw() + dc.EndDrawing() @@ -637,9 +793,10 @@ class EditorCanvasShapeEvtHandler(ogl.ShapeEvtHandler): 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): @@ -654,7 +811,16 @@ class EditorCanvasShapeEvtHandler(ogl.ShapeEvtHandler): 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():