-# -*- coding: iso-8859-1 -*-
-#----------------------------------------------------------------------------
-# Name: basic.py
-# Purpose: The basic OGL shapes
-#
-# Author: Pierre Hjälm (from C++ original by Julian Smart)
-#
-# Created: 2004-05-08
-# RCS-ID: $Id$
-# Copyright: (c) 2004 Pierre Hjälm - 1998 Julian Smart
-# Licence: wxWindows license
-#----------------------------------------------------------------------------
-
-from __future__ import division
-
-import wx
-from math import pi, sqrt, atan, sin, cos
-
-from oglmisc import *
-
-DragOffsetX = 0.0
-DragOffsetY = 0.0
-
-
-def OGLInitialize():
- global WhiteBackgroundPen, WhiteBackgroundBrush, TransparentPen
- global BlackForegroundPen, NormalFont
-
- WhiteBackgroundPen = wx.Pen(wx.WHITE, 1, wx.SOLID)
- WhiteBackgroundBrush = wx.Brush(wx.WHITE, wx.SOLID)
-
- TransparentPen = wx.Pen(wx.WHITE, 1, wx.TRANSPARENT)
- BlackForegroundPen = wx.Pen(wx.BLACK, 1, wx.SOLID)
-
- NormalFont = wx.Font(10, wx.SWISS, wx.NORMAL, wx.NORMAL)
-
-
-def OGLCleanUp():
- pass
-
-
-class ShapeTextLine(object):
- def __init__(self, the_x, the_y, the_line):
- self._x = the_x
- self._y = the_y
- self._line = the_line
-
- def GetX(self):
- return self._x
-
- def GetY(self):
- return self._y
-
- def SetX(self, x):
- self._x = x
-
- def SetY(self, y):
- self._y = y
-
- def SetText(self, text):
- self._line = text
-
- def GetText(self):
- return self._line
-
-
-
-class ShapeEvtHandler(object):
- def __init__(self, prev = None, shape = None):
- self._previousHandler = prev
- self._handlerShape = shape
-
- def __del__(self):
- pass
-
- def SetShape(self, sh):
- self._handlerShape = sh
-
- def GetShape(self):
- return self._handlerShape
-
- def SetPreviousHandler(self, handler):
- self._previousHandler = handler
-
- def GetPreviousHandler(self):
- return self._previousHandler
-
- def OnDraw(self, dc):
- if self._previousHandler:
- self._previousHandler.OnDraw(dc)
-
- def OnMoveLinks(self, dc):
- if self._previousHandler:
- self._previousHandler.OnMoveLinks(dc)
-
- def OnMoveLink(self, dc, moveControlPoints = True):
- if self._previousHandler:
- self._previousHandler.OnMoveLink(dc, moveControlPoints)
-
- def OnDrawContents(self, dc):
- if self._previousHandler:
- self._previousHandler.OnDrawContents(dc)
-
- def OnDrawBranches(self, dc, erase = False):
- if self._previousHandler:
- self._previousHandler.OnDrawBranches(dc, erase = erase)
-
- def OnSize(self, x, y):
- if self._previousHandler:
- self._previousHandler.OnSize(x, y)
-
- def OnMovePre(self, dc, x, y, old_x, old_y, display = True):
- if self._previousHandler:
- return self._previousHandler.OnMovePre(dc, x, y, old_x, old_y, display)
- else:
- return True
-
- def OnMovePost(self, dc, x, y, old_x, old_y, display = True):
- if self._previousHandler:
- return self._previousHandler.OnMovePost(dc, x, y, old_x, old_y, display)
- else:
- return True
-
- def OnErase(self, dc):
- if self._previousHandler:
- self._previousHandler.OnErase(dc)
-
- def OnEraseContents(self, dc):
- if self._previousHandler:
- self._previousHandler.OnEraseContents(dc)
-
- def OnHighlight(self, dc):
- if self._previousHandler:
- self._previousHandler.OnHighlight(dc)
-
- def OnLeftClick(self, x, y, keys, attachment):
- if self._previousHandler:
- self._previousHandler.OnLeftClick(x, y, keys, attachment)
-
- def OnLeftDoubleClick(self, x, y, keys = 0, attachment = 0):
- if self._previousHandler:
- self._previousHandler.OnLeftDoubleClick(x, y, keys, attachment)
-
- def OnRightClick(self, x, y, keys = 0, attachment = 0):
- if self._previousHandler:
- self._previousHandler.OnRightClick(x, y, keys, attachment)
-
- def OnDragLeft(self, draw, x, y, keys = 0, attachment = 0):
- if self._previousHandler:
- self._previousHandler.OnDragLeft(draw, x, y, keys, attachment)
-
- def OnBeginDragLeft(self, x, y, keys = 0, attachment = 0):
- if self._previousHandler:
- self._previousHandler.OnBeginDragLeft(x, y, keys, attachment)
-
- def OnEndDragLeft(self, x, y, keys = 0, attachment = 0):
- if self._previousHandler:
- self._previousHandler.OnEndDragLeft(x, y, keys, attachment)
-
- def OnDragRight(self, draw, x, y, keys = 0, attachment = 0):
- if self._previousHandler:
- self._previousHandler.OnDragRight(draw, x, y, keys, attachment)
-
- def OnBeginDragRight(self, x, y, keys = 0, attachment = 0):
- if self._previousHandler:
- self._previousHandler.OnBeginDragRight(x, y, keys, attachment)
-
- def OnEndDragRight(self, x, y, keys = 0, attachment = 0):
- if self._previousHandler:
- self._previousHandler.OnEndDragRight(x, y, keys, attachment)
-
- # Control points ('handles') redirect control to the actual shape,
- # to make it easier to override sizing behaviour.
- def OnSizingDragLeft(self, pt, draw, x, y, keys = 0, attachment = 0):
- if self._previousHandler:
- self._previousHandler.OnSizingDragLeft(pt, draw, x, y, keys, attachment)
-
- def OnSizingBeginDragLeft(self, pt, x, y, keys = 0, attachment = 0):
- if self._previousHandler:
- self._previousHandler.OnSizingBeginDragLeft(pt, x, y, keys, attachment)
-
- def OnSizingEndDragLeft(self, pt, x, y, keys = 0, attachment = 0):
- if self._previousHandler:
- self._previousHandler.OnSizingEndDragLeft(pt, x, y, keys, attachment)
-
- def OnBeginSize(self, w, h):
- pass
-
- def OnEndSize(self, w, h):
- pass
-
- def OnDrawOutline(self, dc, x, y, w, h):
- if self._previousHandler:
- self._previousHandler.OnDrawOutline(dc, x, y, w, h)
-
- def OnDrawControlPoints(self, dc):
- if self._previousHandler:
- self._previousHandler.OnDrawControlPoints(dc)
-
- def OnEraseControlPoints(self, dc):
- if self._previousHandler:
- self._previousHandler.OnEraseControlPoints(dc)
-
- # Can override this to prevent or intercept line reordering.
- def OnChangeAttachment(self, attachment, line, ordering):
- if self._previousHandler:
- self._previousHandler.OnChangeAttachment(attachment, line, ordering)
-
-
-
-class Shape(ShapeEvtHandler):
- """OGL base class
-
- Shape(canvas = None)
-
- The wxShape is the top-level, abstract object that all other objects
- are derived from. All common functionality is represented by wxShape's
- members, and overriden members that appear in derived classes and have
- behaviour as documented for wxShape, are not documented separately.
- """
-
- GraphicsInSizeToContents = False
-
- def __init__(self, canvas = None):
- ShapeEvtHandler.__init__(self)
-
- self._eventHandler = self
- self.SetShape(self)
- self._id = 0
- self._formatted = False
- self._canvas = canvas
- self._xpos = 0.0
- self._ypos = 0.0
- self._pen = wx.Pen(wx.BLACK, 1, wx.SOLID)
- self._brush = wx.WHITE_BRUSH
- self._font = wx.Font(10, wx.SWISS, wx.NORMAL, wx.NORMAL)
- self._textColour = wx.BLACK
- self._textColourName = wx.BLACK
- self._visible = False
- self._selected = False
- self._attachmentMode = ATTACHMENT_MODE_NONE
- self._spaceAttachments = True
- self._disableLabel = False
- self._fixedWidth = False
- self._fixedHeight = False
- self._drawHandles = True
- self._sensitivity = OP_ALL
- self._draggable = True
- self._parent = None
- self._formatMode = FORMAT_CENTRE_HORIZ | FORMAT_CENTRE_VERT
- self._shadowMode = SHADOW_NONE
- self._shadowOffsetX = 6
- self._shadowOffsetY = 6
- self._shadowBrush = wx.BLACK_BRUSH
- self._textMarginX = 5
- self._textMarginY = 5
- self._regionName="0"
- self._centreResize = True
- self._maintainAspectRatio = False
- self._highlighted = False
- self._rotation = 0.0
- self._branchNeckLength = 10
- self._branchStemLength = 10
- self._branchSpacing = 10
- self._branchStyle = BRANCHING_ATTACHMENT_NORMAL
-
- self._regions = []
- self._lines = []
- self._controlPoints = []
- self._attachmentPoints = []
- self._text = []
- self._children = []
-
- # Set up a default region. Much of the above will be put into
- # the region eventually (the duplication is for compatibility)
- region = ShapeRegion()
- region.SetName("0")
- region.SetFont(wx.Font(10, wx.SWISS, wx.NORMAL, wx.NORMAL))
- region.SetFormatMode(FORMAT_CENTRE_HORIZ | FORMAT_CENTRE_VERT)
- region.SetColour("BLACK")
- self._regions.append(region)
-
- def __str__(self):
- return "<%s.%s>" % (self.__class__.__module__, self.__class__.__name__)
-
- def GetClassName(self):
- return str(self.__class__).split(".")[-1][:-2]
-
- def __del__(self):
- if self._parent:
- i = self._parent.GetChildren().index(self)
- self._parent.GetChildren(i).remove(self)
-
- self.ClearText()
- self.ClearRegions()
- self.ClearAttachments()
-
- if self._canvas:
- self._canvas.RemoveShape(self)
-
- self.GetEventHandler().OnDelete()
-
- def Draggable(self):
- """TRUE if the shape may be dragged by the user."""
- return True
-
- def SetShape(self, sh):
- self._handlerShape = sh
-
- def GetCanvas(self):
- """Get the internal canvas."""
- return self._canvas
-
- def GetBranchStyle(self):
- return self._branchStyle
-
- def GetRotation(self):
- """Return the angle of rotation in radians."""
- return self._rotation
-
- def SetRotation(self, rotation):
- self._rotation = rotation
-
- def SetHighlight(self, hi, recurse = False):
- """Set the highlight for a shape. Shape highlighting is unimplemented."""
- self._highlighted = hi
- if recurse:
- for shape in self._children:
- shape.SetHighlight(hi, recurse)
-
- def SetSensitivityFilter(self, sens = OP_ALL, recursive = False):
- """Set the shape to be sensitive or insensitive to specific mouse
- operations.
-
- sens is a bitlist of the following:
-
- * OP_CLICK_LEFT
- * OP_CLICK_RIGHT
- * OP_DRAG_LEFT
- * OP_DRAG_RIGHT
- * OP_ALL (equivalent to a combination of all the above).
- """
- self._draggable = sens & OP_DRAG_LEFT
-
- self._sensitivity = sens
- if recursive:
- for shape in self._children:
- shape.SetSensitivityFilter(sens, True)
-
- def SetDraggable(self, drag, recursive = False):
- """Set the shape to be draggable or not draggable."""
- self._draggable = drag
- if drag:
- self._sensitivity |= OP_DRAG_LEFT
- elif self._sensitivity & OP_DRAG_LEFT:
- self._sensitivity -= OP_DRAG_LEFT
-
- if recursive:
- for shape in self._children:
- shape.SetDraggable(drag, True)
-
- def SetDrawHandles(self, drawH):
- """Set the drawHandles flag for this shape and all descendants.
- If drawH is TRUE (the default), any handles (control points) will
- be drawn. Otherwise, the handles will not be drawn.
- """
- self._drawHandles = drawH
- for shape in self._children:
- shape.SetDrawHandles(drawH)
-
- def SetShadowMode(self, mode, redraw = False):
- """Set the shadow mode (whether a shadow is drawn or not).
- mode can be one of the following:
-
- SHADOW_NONE
- No shadow (the default).
- SHADOW_LEFT
- Shadow on the left side.
- SHADOW_RIGHT
- Shadow on the right side.
- """
- if redraw and self.GetCanvas():
- dc = wx.ClientDC(self.GetCanvas())
- self.GetCanvas().PrepareDC(dc)
- self.Erase(dc)
- self._shadowMode = mode
- self.Draw(dc)
- else:
- self._shadowMode = mode
-
- def SetCanvas(self, theCanvas):
- """Identical to Shape.Attach."""
- self._canvas = theCanvas
- for shape in self._children:
- shape.SetCanvas(theCanvas)
-
- def AddToCanvas(self, theCanvas, addAfter = None):
- """Add the shape to the canvas's shape list.
- If addAfter is non-NULL, will add the shape after this one.
- """
- theCanvas.AddShape(self, addAfter)
-
- lastImage = self
- for object in self._children:
- object.AddToCanvas(theCanvas, lastImage)
- lastImage = object
-
- def InsertInCanvas(self, theCanvas):
- """Insert the shape at the front of the shape list of canvas."""
- theCanvas.InsertShape(self)
-
- lastImage = self
- for object in self._children:
- object.AddToCanvas(theCanvas, lastImage)
- lastImage = object
-
- def RemoveFromCanvas(self, theCanvas):
- """Remove the shape from the canvas."""
- if self.Selected():
- self.Select(False)
- theCanvas.RemoveShape(self)
- for object in self._children:
- object.RemoveFromCanvas(theCanvas)
-
- def ClearAttachments(self):
- """Clear internal custom attachment point shapes (of class
- wxAttachmentPoint).
- """
- self._attachmentPoints = []
-
- def ClearText(self, regionId = 0):
- """Clear the text from the specified text region."""
- if regionId == 0:
- self._text=""
- if regionId<len(self._regions):
- self._regions[regionId].ClearText()
-
- def ClearRegions(self):
- """Clear the ShapeRegions from the shape."""
- self._regions = []
-
- def AddRegion(self, region):
- """Add a region to the shape."""
- self._regions.append(region)
-
- def SetDefaultRegionSize(self):
- """Set the default region to be consistent with the shape size."""
- if not self._regions:
- return
- w, h = self.GetBoundingBoxMax()
- self._regions[0].SetSize(w, h)
-
- def HitTest(self, x, y):
- """Given a point on a canvas, returns TRUE if the point was on the
- shape, and returns the nearest attachment point and distance from
- the given point and target.
- """
- width, height = self.GetBoundingBoxMax()
- if abs(width)<4:
- width = 4.0
- if abs(height)<4:
- height = 4.0
-
- width += 4 # Allowance for inaccurate mousing
- height += 4
-
- left = self._xpos - (width / 2)
- top = self._ypos - (height / 2)
- right = self._xpos + (width / 2)
- bottom = self._ypos + (height / 2)
-
- nearest_attachment = 0
-
- # If within the bounding box, check the attachment points
- # within the object.
- if x >= left and x <= right and y >= top and y <= bottom:
- n = self.GetNumberOfAttachments()
- nearest = 999999
-
- # GetAttachmentPosition[Edge] takes a logical attachment position,
- # i.e. if it's rotated through 90%, position 0 is East-facing.
-
- for i in range(n):
- e = self.GetAttachmentPositionEdge(i)
- if e:
- xp, yp = e
- l = sqrt(((xp - x) * (xp - x)) + (yp - y) * (yp - y))
- if l<nearest:
- nearest = l
- nearest_attachment = i
-
- return nearest_attachment, nearest
- return False
-
- # Format a text string according to the region size, adding
- # strings with positions to region text list
-
- def FormatText(self, dc, s, i = 0):
- """Reformat the given text region; defaults to formatting the
- default region.
- """
- self.ClearText(i)
-
- if not self._regions:
- return
-
- if i>len(self._regions):
- return
-
- region = self._regions[i]
- region._regionText = s
- dc.SetFont(region.GetFont())
-
- w, h = region.GetSize()
-
- stringList = FormatText(dc, s, (w - 2 * self._textMarginX), (h - 2 * self._textMarginY), region.GetFormatMode())
- for s in stringList:
- line = ShapeTextLine(0.0, 0.0, s)
- region.GetFormattedText().append(line)
-
- actualW = w
- actualH = h
- # Don't try to resize an object with more than one image (this
- # case should be dealt with by overriden handlers)
- if (region.GetFormatMode() & FORMAT_SIZE_TO_CONTENTS) and \
- region.GetFormattedText().GetCount() and \
- len(self._regions) == 1 and \
- not Shape.GraphicsInSizeToContents:
-
- actualW, actualH = GetCentredTextExtent(dc, region.GetFormattedText())
- if actualW + 2 * self._textMarginX != w or actualH + 2 * self._textMarginY != h:
- # If we are a descendant of a composite, must make sure
- # the composite gets resized properly
-
- topAncestor = self.GetTopAncestor()
- if topAncestor != self:
- Shape.GraphicsInSizeToContents = True
-
- composite = topAncestor
- composite.Erase(dc)
- self.SetSize(actualW + 2 * self._textMarginX, actualH + 2 * self._textMarginY)
- self.Move(dc, self._xpos, self._ypos)
- composite.CalculateSize()
- if composite.Selected():
- composite.DeleteControlPoints(dc)
- composite.MakeControlPoints()
- composite.MakeMandatoryControlPoints()
- # Where infinite recursion might happen if we didn't stop it
- composite.Draw(dc)
- Shape.GraphicsInSizeToContents = False
- else:
- self.Erase(dc)
-
- self.SetSize(actualW + 2 * self._textMarginX, actualH + 2 * self._textMarginY)
- self.Move(dc, self._xpos, self._ypos)
- self.EraseContents(dc)
- CentreText(dc, region.GetFormattedText(), self._xpos, self._ypos, actualW - 2 * self._textMarginX, actualH - 2 * self._textMarginY, region.GetFormatMode())
- self._formatted = True
-
- def Recentre(self, dc):
- """Do recentring (or other formatting) for all the text regions
- for this shape.
- """
- w, h = self.GetBoundingBoxMin()
- for region in self._regions:
- CentreText(dc, region.GetFormattedText(), self._xpos, self._ypos, w - 2 * self._textMarginX, h - 2 * self._textMarginY, region.GetFormatMode())
-
- def GetPerimeterPoint(self, x1, y1, x2, y2):
- """Get the point at which the line from (x1, y1) to (x2, y2) hits
- the shape. Returns False if the line doesn't hit the perimeter.
- """
- return False
-
- def SetPen(self, the_pen):
- """Set the pen for drawing the shape's outline."""
- self._pen = the_pen
-
- def SetBrush(self, the_brush):
- """Set the brush for filling the shape's shape."""
- self._brush = the_brush
-
- # Get the top - most (non-division) ancestor, or self
- def GetTopAncestor(self):
- """Return the top-most ancestor of this shape (the root of
- the composite).
- """
- if not self.GetParent():
- return self
-
- if isinstance(self.GetParent(), DivisionShape):
- return self
- return self.GetParent().GetTopAncestor()
-
- # Region functions
- def SetFont(self, the_font, regionId = 0):
- """Set the font for the specified text region."""
- self._font = the_font
- if regionId<len(self._regions):
- self._regions[regionId].SetFont(the_font)
-
- def GetFont(self, regionId = 0):
- """Get the font for the specified text region."""
- if regionId >= len(self._regions):
- return None
- return self._regions[regionId].GetFont()
-
- def SetFormatMode(self, mode, regionId = 0):
- """Set the format mode of the default text region. The argument
- can be a bit list of the following:
-
- FORMAT_NONE
- No formatting.
- FORMAT_CENTRE_HORIZ
- Horizontal centring.
- FORMAT_CENTRE_VERT
- Vertical centring.
- """
- if regionId<len(self._regions):
- self._regions[regionId].SetFormatMode(mode)
-
- def GetFormatMode(self, regionId = 0):
- if regionId >= len(self._regions):
- return 0
- return self._regions[regionId].GetFormatMode()
-
- def SetTextColour(self, the_colour, regionId = 0):
- """Set the colour for the specified text region."""
- self._textColour = wx.TheColourDatabase.Find(the_colour)
- self._textColourName = the_colour
-
- if regionId<len(self._regions):
- self._regions[regionId].SetColour(the_colour)
-
- def GetTextColour(self, regionId = 0):
- """Get the colour for the specified text region."""
- if regionId >= len(self._regions):
- return ""
- return self._regions[regionId].GetTextColour()
-
- def SetRegionName(self, name, regionId = 0):
- """Set the name for this region.
- The name for a region is unique within the scope of the whole
- composite, whereas a region id is unique only for a single image.
- """
- if regionId<len(self._regions):
- self._regions[regionId].SetName(name)
-
- def GetRegionName(self, regionId = 0):
- """Get the region's name.
- A region's name can be used to uniquely determine a region within
- an entire composite image hierarchy. See also Shape.SetRegionName.
- """
- if regionId >= len(self._regions):
- return ""
- return self._regions[regionId].GetName()
-
- def GetRegionId(self, name):
- """Get the region's identifier by name.
- This is not unique for within an entire composite, but is unique
- for the image.
- """
- for i, r in enumerate(self._regions):
- if r.GetName() == name:
- return i
- return -1
-
- # Name all _regions in all subimages recursively
- def NameRegions(self, parentName=""):
- """Make unique names for all the regions in a shape or composite shape."""
- n = self.GetNumberOfTextRegions()
- for i in range(n):
- if parentName:
- buff = parentName+"."+str(i)
- else:
- buff = str(i)
- self.SetRegionName(buff, i)
-
- for j, child in enumerate(self._children):
- if parentName:
- buff = parentName+"."+str(j)
- else:
- buff = str(j)
- child.NameRegions(buff)
-
- # Get a region by name, possibly looking recursively into composites
- def FindRegion(self, name):
- """Find the actual image ('this' if non-composite) and region id
- for the given region name.
- """
- id = self.GetRegionId(name)
- if id>-1:
- return self, id
-
- for child in self._children:
- actualImage, regionId = child.FindRegion(name)
- if actualImage:
- return actualImage, regionId
-
- return None,-1
-
- # Finds all region names for this image (composite or simple).
- def FindRegionNames(self):
- """Get a list of all region names for this image (composite or simple)."""
- list = []
- n = self.GetNumberOfTextRegions()
- for i in range(n):
- list.append(self.GetRegionName(i))
-
- for child in self._children:
- list += child.FindRegionNames()
-
- return list
-
- def AssignNewIds(self):
- """Assign new ids to this image and its children."""
- self._id = wx.NewId()
- for child in self._children:
- child.AssignNewIds()
-
- def OnDraw(self, dc):
- pass
-
- def OnMoveLinks(self, dc):
- # Want to set the ends of all attached links
- # to point to / from this object
-
- for line in self._lines:
- line.GetEventHandler().OnMoveLink(dc)
-
- def OnDrawContents(self, dc):
- if not self._regions:
- return
-
- bound_x, bound_y = self.GetBoundingBoxMin()
-
- if self._pen:
- dc.SetPen(self._pen)
-
- region = self._regions[0]
- if region.GetFont():
- dc.SetFont(region.GetFont())
-
- dc.SetTextForeground(region.GetActualColourObject())
- dc.SetBackgroundMode(wx.TRANSPARENT)
- if not self._formatted:
- CentreText(dc, region.GetFormattedText(), self._xpos, self._ypos, bound_x - 2 * self._textMarginX, bound_y - 2 * self._textMarginY, region.GetFormatMode())
- self._formatted = True
-
- if not self.GetDisableLabel():
- DrawFormattedText(dc, region.GetFormattedText(), self._xpos, self._ypos, bound_x - 2 * self._textMarginX, bound_y - 2 * self._textMarginY, region.GetFormatMode())
-
-
- def DrawContents(self, dc):
- """Draw the internal graphic of the shape (such as text).
-
- Do not override this function: override OnDrawContents, which
- is called by this function.
- """
- self.GetEventHandler().OnDrawContents(dc)
-
- def OnSize(self, x, y):
- pass
-
- def OnMovePre(self, dc, x, y, old_x, old_y, display = True):
- return True
-
- def OnErase(self, dc):
- if not self._visible:
- return
-
- # Erase links
- for line in self._lines:
- line.GetEventHandler().OnErase(dc)
-
- self.GetEventHandler().OnEraseContents(dc)
-
- def OnEraseContents(self, dc):
- if not self._visible:
- return
-
- xp, yp = self.GetX(), self.GetY()
- minX, minY = self.GetBoundingBoxMin()
- maxX, maxY = self.GetBoundingBoxMax()
-
- topLeftX = xp - maxX / 2 - 2
- topLeftY = yp - maxY / 2 - 2
-
- penWidth = 0
- if self._pen:
- penWidth = self._pen.GetWidth()
-
- dc.SetPen(self.GetBackgroundPen())
- dc.SetBrush(self.GetBackgroundBrush())
-
- dc.DrawRectangle(topLeftX - penWidth, topLeftY - penWidth, maxX + penWidth * 2 + 4, maxY + penWidth * 2 + 4)
-
- def EraseLinks(self, dc, attachment=-1, recurse = False):
- """Erase links attached to this shape, but do not repair damage
- caused to other shapes.
- """
- if not self._visible:
- return
-
- for line in self._lines:
- if attachment==-1 or (line.GetTo() == self and line.GetAttachmentTo() == attachment or line.GetFrom() == self and line.GetAttachmentFrom() == attachment):
- line.GetEventHandler().OnErase(dc)
-
- if recurse:
- for child in self._children:
- child.EraseLinks(dc, attachment, recurse)
-
- def DrawLinks(self, dc, attachment=-1, recurse = False):
- """Draws any lines linked to this shape."""
- if not self._visible:
- return
-
- for line in self._lines:
- if attachment==-1 or (line.GetTo() == self and line.GetAttachmentTo() == attachment or line.GetFrom() == self and line.GetAttachmentFrom() == attachment):
- line.GetEventHandler().Draw(dc)
-
- if recurse:
- for child in self._children:
- child.DrawLinks(dc, attachment, recurse)
-
- # Returns TRUE if pt1 <= pt2 in the sense that one point comes before
- # another on an edge of the shape.
- # attachmentPoint is the attachment point (= side) in question.
-
- # This is the default, rectangular implementation.
- def AttachmentSortTest(self, attachmentPoint, pt1, pt2):
- """Return TRUE if pt1 is less than or equal to pt2, in the sense
- that one point comes before another on an edge of the shape.
-
- attachment is the attachment point (side) in question.
-
- This function is used in Shape.MoveLineToNewAttachment to determine
- the new line ordering.
- """
- physicalAttachment = self.LogicalToPhysicalAttachment(attachmentPoint)
- if physicalAttachment in [0, 2]:
- return pt1.x <= pt2.x
- elif physicalAttachment in [1, 3]:
- return pt1.y <= pt2.y
-
- return False
-
- def MoveLineToNewAttachment(self, dc, to_move, x, y):
- """Move the given line (which must already be attached to the shape)
- to a different attachment point on the shape, or a different order
- on the same attachment.
-
- Calls Shape.AttachmentSortTest and then
- ShapeEvtHandler.OnChangeAttachment.
- """
- if self.GetAttachmentMode() == ATTACHMENT_MODE_NONE:
- return False
-
- # Is (x, y) on this object? If so, find the new attachment point
- # the user has moved the point to
- hit = self.HitTest(x, y)
- if not hit:
- return False
-
- newAttachment, distance = hit
-
- self.EraseLinks(dc)
-
- if to_move.GetTo() == self:
- oldAttachment = to_move.GetAttachmentTo()
- else:
- oldAttachment = to_move.GetAttachmentFrom()
-
- # The links in a new ordering
- # First, add all links to the new list
- newOrdering = self._lines[:]
-
- # Delete the line object from the list of links; we're going to move
- # it to another position in the list
- del newOrdering[newOrdering.index(to_move)]
-
- old_x=-99999.9
- old_y=-99999.9
-
- found = False
-
- for line in newOrdering:
- if line.GetTo() == self and oldAttachment == line.GetAttachmentTo() or \
- line.GetFrom() == self and oldAttachment == line.GetAttachmentFrom():
- startX, startY, endX, endY = line.GetEnds()
- if line.GetTo() == self:
- xp = endX
- yp = endY
- else:
- xp = startX
- yp = startY
-
- thisPoint = wx.RealPoint(xp, yp)
- lastPoint = wx.RealPoint(old_x, old_y)
- newPoint = wx.RealPoint(x, y)
-
- if self.AttachmentSortTest(newAttachment, newPoint, thisPoint) and self.AttachmentSortTest(newAttachment, lastPoint, newPoint):
- found = True
- newOrdering.insert(newOrdering.index(line), to_move)
-
- old_x = xp
- old_y = yp
- if found:
- break
-
- if not found:
- newOrdering.append(to_move)
-
- self.GetEventHandler().OnChangeAttachment(newAttachment, to_move, newOrdering)
- return True
-
- def OnChangeAttachment(self, attachment, line, ordering):
- if line.GetTo() == self:
- line.SetAttachmentTo(attachment)
- else:
- line.SetAttachmentFrom(attachment)
-
- self.ApplyAttachmentOrdering(ordering)
-
- dc = wx.ClientDC(self.GetCanvas())
- self.GetCanvas().PrepareDC(dc)
- self.MoveLinks(dc)
-
- if not self.GetCanvas().GetQuickEditMode():
- self.GetCanvas().Redraw(dc)
-
- # Reorders the lines according to the given list
- def ApplyAttachmentOrdering(self, linesToSort):
- """Apply the line ordering in linesToSort to the shape, to reorder
- the way lines are attached.
- """
- linesStore = self._lines[:]
-
- self._lines = []
-
- for line in linesToSort:
- if line in linesStore:
- del linesStore[linesStore.index(line)]
- self._lines.append(line)
-
- # Now add any lines that haven't been listed in linesToSort
- self._lines += linesStore
-
- def SortLines(self, attachment, linesToSort):
- """ Reorder the lines coming into the node image at this attachment
- position, in the order in which they appear in linesToSort.
-
- Any remaining lines not in the list will be added to the end.
- """
- # This is a temporary store of all the lines at this attachment
- # point. We'll tick them off as we've processed them.
- linesAtThisAttachment = []
-
- for line in self._lines[:]:
- if line.GetTo() == self and line.GetAttachmentTo() == attachment or \
- line.GetFrom() == self and line.GetAttachmentFrom() == attachment:
- linesAtThisAttachment.append(line)
- del self._lines[self._lines.index(line)]
-
- for line in linesToSort:
- if line in linesAtThisAttachment:
- # Done this one
- del linesAtThisAttachment[linesAtThisAttachment.index(line)]
- self._lines.Append(line)
-
- # Now add any lines that haven't been listed in linesToSort
- self._lines += linesAtThisAttachment
-
- def OnHighlight(self, dc):
- pass
-
- def OnLeftClick(self, x, y, keys = 0, attachment = 0):
- if self._sensitivity & OP_CLICK_LEFT != OP_CLICK_LEFT:
- if self._parent:
- attachment, dist = self._parent.HitTest(x, y)
- self._parent.GetEventHandler().OnLeftClick(x, y, keys, attachment)
-
- def OnRightClick(self, x, y, keys = 0, attachment = 0):
- if self._sensitivity & OP_CLICK_RIGHT != OP_CLICK_RIGHT:
- attachment, dist = self._parent.HitTest(x, y)
- self._parent.GetEventHandler().OnRightClick(x, y, keys, attachment)
-
- def OnDragLeft(self, draw, x, y, keys = 0, attachment = 0):
- if self._sensitivity & OP_DRAG_LEFT != OP_DRAG_LEFT:
- if self._parent:
- hit = self._parent.HitTest(x, y)
- if hit:
- attachment, dist = hit
- self._parent.GetEventHandler().OnDragLeft(draw, x, y, keys, attachment)
- return
-
- dc = wx.ClientDC(self.GetCanvas())
- self.GetCanvas().PrepareDC(dc)
- dc.SetLogicalFunction(OGLRBLF)
-
- dottedPen = wx.Pen(wx.Colour(0, 0, 0), 1, wx.DOT)
- dc.SetPen(dottedPen)
- dc.SetBrush(wx.TRANSPARENT_BRUSH)
-
- xx = x + DragOffsetX
- yy = y + DragOffsetY
-
- xx, yy = self._canvas.Snap(xx, yy)
- w, h = self.GetBoundingBoxMax()
- self.GetEventHandler().OnDrawOutline(dc, xx, yy, w, h)
-
- def OnBeginDragLeft(self, x, y, keys = 0, attachment = 0):
- global DragOffsetX, DragOffsetY
-
- if self._sensitivity & OP_DRAG_LEFT != OP_DRAG_LEFT:
- if self._parent:
- hit = self._parent.HitTest(x, y)
- if hit:
- attachment, dist = hit
- self._parent.GetEventHandler().OnBeginDragLeft(x, y, keys, attachment)
- return
-
- DragOffsetX = self._xpos - x
- DragOffsetY = self._ypos - y
-
- dc = wx.ClientDC(self.GetCanvas())
- self.GetCanvas().PrepareDC(dc)
-
- # New policy: don't erase shape until end of drag.
- # self.Erase(dc)
- xx = x + DragOffsetX
- yy = y + DragOffsetY
- xx, yy = self._canvas.Snap(xx, yy)
- dc.SetLogicalFunction(OGLRBLF)
-
- dottedPen = wx.Pen(wx.Colour(0, 0, 0), 1, wx.DOT)
- dc.SetPen(dottedPen)
- dc.SetBrush(wx.TRANSPARENT_BRUSH)
-
- w, h = self.GetBoundingBoxMax()
- self.GetEventHandler().OnDrawOutline(dc, xx, yy, w, h)
- self._canvas.CaptureMouse()
-
- def OnEndDragLeft(self, x, y, keys = 0, attachment = 0):
- if self._canvas.HasCapture():
- self._canvas.ReleaseMouse()
- if self._sensitivity & OP_DRAG_LEFT != OP_DRAG_LEFT:
- if self._parent:
- hit = self._parent.HitTest(x, y)
- if hit:
- attachment, dist = hit
- self._parent.GetEventHandler().OnEndDragLeft(x, y, keys, attachment)
- return
-
- dc = wx.ClientDC(self.GetCanvas())
- self.GetCanvas().PrepareDC(dc)
-
- dc.SetLogicalFunction(wx.COPY)
- xx = x + DragOffsetX
- yy = y + DragOffsetY
- xx, yy = self._canvas.Snap(xx, yy)
-
- # New policy: erase shape at end of drag.
- self.Erase(dc)
-
- self.Move(dc, xx, yy)
- if self._canvas and not self._canvas.GetQuickEditMode():
- self._canvas.Redraw(dc)
-
- def OnDragRight(self, draw, x, y, keys = 0, attachment = 0):
- if self._sensitivity & OP_DRAG_RIGHT != OP_DRAG_RIGHT:
- if self._parent:
- attachment, dist = self._parent.HitTest(x, y)
- self._parent.GetEventHandler().OnDragRight(draw, x, y, keys, attachment)
- return
-
- def OnBeginDragRight(self, x, y, keys = 0, attachment = 0):
- if self._sensitivity & OP_DRAG_RIGHT != OP_DRAG_RIGHT:
- if self._parent:
- attachment, dist = self._parent.HitTest(x, y)
- self._parent.GetEventHandler().OnBeginDragRight(x, y, keys, attachment)
- return
-
- def OnEndDragRight(self, x, y, keys = 0, attachment = 0):
- if self._sensitivity & OP_DRAG_RIGHT != OP_DRAG_RIGHT:
- if self._parent:
- attachment, dist = self._parent.HitTest(x, y)
- self._parent.GetEventHandler().OnEndDragRight(x, y, keys, attachment)
- return
-
- def OnDrawOutline(self, dc, x, y, w, h):
- points = [[x - w / 2, y - h / 2],
- [x + w / 2, y - h / 2],
- [x + w / 2, y + h / 2],
- [x - w / 2, y + h / 2],
- [x - w / 2, y - h / 2],
- ]
-
- #dc.DrawLines([[round(x), round(y)] for x, y in points])
- dc.DrawLines(points)
-
- def Attach(self, can):
- """Set the shape's internal canvas pointer to point to the given canvas."""
- self._canvas = can
-
- def Detach(self):
- """Disassociates the shape from its canvas."""
- self._canvas = None
-
- def Move(self, dc, x, y, display = True):
- """Move the shape to the given position.
- Redraw if display is TRUE.
- """
- old_x = self._xpos
- old_y = self._ypos
-
- if not self.GetEventHandler().OnMovePre(dc, x, y, old_x, old_y, display):
- return
-
- self._xpos, self._ypos = x, y
-
- self.ResetControlPoints()
-
- if display:
- self.Draw(dc)
-
- self.MoveLinks(dc)
-
- self.GetEventHandler().OnMovePost(dc, x, y, old_x, old_y, display)
-
- def MoveLinks(self, dc):
- """Redraw all the lines attached to the shape."""
- self.GetEventHandler().OnMoveLinks(dc)
-
- def Draw(self, dc):
- """Draw the whole shape and any lines attached to it.
-
- Do not override this function: override OnDraw, which is called
- by this function.
- """
- if self._visible:
- self.GetEventHandler().OnDraw(dc)
- self.GetEventHandler().OnDrawContents(dc)
- self.GetEventHandler().OnDrawControlPoints(dc)
- self.GetEventHandler().OnDrawBranches(dc)
-
- def Flash(self):
- """Flash the shape."""
- if self.GetCanvas():
- dc = wx.ClientDC(self.GetCanvas())
- self.GetCanvas.PrepareDC(dc)
-
- dc.SetLogicalFunction(OGLRBLF)
- self.Draw(dc)
- dc.SetLogicalFunction(wx.COPY)
- self.Draw(dc)
-
- def Show(self, show):
- """Set a flag indicating whether the shape should be drawn."""
- self._visible = show
- for child in self._children:
- child.Show(show)
-
- def Erase(self, dc):
- """Erase the shape.
- Does not repair damage caused to other shapes.
- """
- self.GetEventHandler().OnErase(dc)
- self.GetEventHandler().OnEraseControlPoints(dc)
- self.GetEventHandler().OnDrawBranches(dc, erase = True)
-
- def EraseContents(self, dc):
- """Erase the shape contents, that is, the area within the shape's
- minimum bounding box.
- """
- self.GetEventHandler().OnEraseContents(dc)
-
- def AddText(self, string):
- """Add a line of text to the shape's default text region."""
- if not self._regions:
- return
-
- region = self._regions[0]
- region.ClearText()
- new_line = ShapeTextLine(0, 0, string)
- text = region.GetFormattedText()
- text.append(new_line)
-
- self._formatted = False
-
- def SetSize(self, x, y, recursive = True):
- """Set the shape's size."""
- self.SetAttachmentSize(x, y)
- self.SetDefaultRegionSize()
-
- def SetAttachmentSize(self, w, h):
- width, height = self.GetBoundingBoxMin()
- if width == 0:
- scaleX = 1.0
- else:
- scaleX = long(w) / width
- if height == 0:
- scaleY = 1.0
- else:
- scaleY = long(h) / height
-
- for point in self._attachmentPoints:
- point._x = point._x * scaleX
- point._y = point._y * scaleY
-
- # Add line FROM this object
- def AddLine(self, line, other, attachFrom = 0, attachTo = 0, positionFrom=-1, positionTo=-1):
- """Add a line between this shape and the given other shape, at the
- specified attachment points.
-
- The position in the list of lines at each end can also be specified,
- so that the line will be drawn at a particular point on its attachment
- point.
- """
- if positionFrom==-1:
- if not line in self._lines:
- self._lines.append(line)
- else:
- # Don't preserve old ordering if we have new ordering instructions
- try:
- self._lines.remove(line)
- except ValueError:
- pass
- if positionFrom<len(self._lines):
- self._lines.insert(positionFrom, line)
- else:
- self._lines.append(line)
-
- if positionTo==-1:
- if not other in other._lines:
- other._lines.append(line)
- else:
- # Don't preserve old ordering if we have new ordering instructions
- try:
- other._lines.remove(line)
- except ValueError:
- pass
- if positionTo<len(other._lines):
- other._lines.insert(positionTo, line)
- else:
- other._lines.append(line)
-
- line.SetFrom(self)
- line.SetTo(other)
- line.SetAttachments(attachFrom, attachTo)
-
- dc = wx.ClientDC(self._canvas)
- self._canvas.PrepareDC(dc)
- self.MoveLinks(dc)
-
- def RemoveLine(self, line):
- """Remove the given line from the shape's list of attached lines."""
- if line.GetFrom() == self:
- line.GetTo()._lines.remove(line)
- else:
- line.GetFrom()._lines.remove(line)
-
- self._lines.remove(line)
-
- # Default - make 6 control points
- def MakeControlPoints(self):
- """Make a list of control points (draggable handles) appropriate to
- the shape.
- """
- maxX, maxY = self.GetBoundingBoxMax()
- minX, minY = self.GetBoundingBoxMin()
-
- widthMin = minX + CONTROL_POINT_SIZE + 2
- heightMin = minY + CONTROL_POINT_SIZE + 2
-
- # Offsets from main object
- top=-heightMin / 2
- bottom = heightMin / 2 + (maxY - minY)
- left=-widthMin / 2
- right = widthMin / 2 + (maxX - minX)
-
- control = ControlPoint(self._canvas, self, CONTROL_POINT_SIZE, left, top, CONTROL_POINT_DIAGONAL)
- self._canvas.AddShape(control)
- self._controlPoints.append(control)
-
- control = ControlPoint(self._canvas, self, CONTROL_POINT_SIZE, 0, top, CONTROL_POINT_VERTICAL)
- self._canvas.AddShape(control)
- self._controlPoints.append(control)
-
- control = ControlPoint(self._canvas, self, CONTROL_POINT_SIZE, right, top, CONTROL_POINT_DIAGONAL)
- self._canvas.AddShape(control)
- self._controlPoints.append(control)
-
- control = ControlPoint(self._canvas, self, CONTROL_POINT_SIZE, right, 0, CONTROL_POINT_HORIZONTAL)
- self._canvas.AddShape(control)
- self._controlPoints.append(control)
-
- control = ControlPoint(self._canvas, self, CONTROL_POINT_SIZE, right, bottom, CONTROL_POINT_DIAGONAL)
- self._canvas.AddShape(control)
- self._controlPoints.append(control)
-
- control = ControlPoint(self._canvas, self, CONTROL_POINT_SIZE, 0, bottom, CONTROL_POINT_VERTICAL)
- self._canvas.AddShape(control)
- self._controlPoints.append(control)
-
- control = ControlPoint(self._canvas, self, CONTROL_POINT_SIZE, left, bottom, CONTROL_POINT_DIAGONAL)
- self._canvas.AddShape(control)
- self._controlPoints.append(control)
-
- control = ControlPoint(self._canvas, self, CONTROL_POINT_SIZE, left, 0, CONTROL_POINT_HORIZONTAL)
- self._canvas.AddShape(control)
- self._controlPoints.append(control)
-
- def MakeMandatoryControlPoints(self):
- """Make the mandatory control points.
-
- For example, the control point on a dividing line should appear even
- if the divided rectangle shape's handles should not appear (because
- it is the child of a composite, and children are not resizable).
- """
- for child in self._children:
- child.MakeMandatoryControlPoints()
-
- def ResetMandatoryControlPoints(self):
- """Reset the mandatory control points."""
- for child in self._children:
- child.ResetMandatoryControlPoints()
-
- def ResetControlPoints(self):
- """Reset the positions of the control points (for instance when the
- shape's shape has changed).
- """
- self.ResetMandatoryControlPoints()
-
- if len(self._controlPoints) == 0:
- return
-
- maxX, maxY = self.GetBoundingBoxMax()
- minX, minY = self.GetBoundingBoxMin()
-
- widthMin = minX + CONTROL_POINT_SIZE + 2
- heightMin = minY + CONTROL_POINT_SIZE + 2
-
- # Offsets from main object
- top=-heightMin / 2
- bottom = heightMin / 2 + (maxY - minY)
- left=-widthMin / 2
- right = widthMin / 2 + (maxX - minX)
-
- self._controlPoints[0]._xoffset = left
- self._controlPoints[0]._yoffset = top
-
- self._controlPoints[1]._xoffset = 0
- self._controlPoints[1]._yoffset = top
-
- self._controlPoints[2]._xoffset = right
- self._controlPoints[2]._yoffset = top
-
- self._controlPoints[3]._xoffset = right
- self._controlPoints[3]._yoffset = 0
-
- self._controlPoints[4]._xoffset = right
- self._controlPoints[4]._yoffset = bottom
-
- self._controlPoints[5]._xoffset = 0
- self._controlPoints[5]._yoffset = bottom
-
- self._controlPoints[6]._xoffset = left
- self._controlPoints[6]._yoffset = bottom
-
- self._controlPoints[7]._xoffset = left
- self._controlPoints[7]._yoffset = 0
-
- def DeleteControlPoints(self, dc = None):
- """Delete the control points (or handles) for the shape.
-
- Does not redraw the shape.
- """
- for control in self._controlPoints:
- if dc:
- control.GetEventHandler().OnErase(dc)
- self._canvas.RemoveShape(control)
- del control
- self._controlPoints = []
-
- # Children of divisions are contained objects,
- # so stop here
- if not isinstance(self, DivisionShape):
- for child in self._children:
- child.DeleteControlPoints(dc)
-
- def OnDrawControlPoints(self, dc):
- if not self._drawHandles:
- return
-
- dc.SetBrush(wx.BLACK_BRUSH)
- dc.SetPen(wx.BLACK_PEN)
-
- for control in self._controlPoints:
- control.Draw(dc)
-
- # Children of divisions are contained objects,
- # so stop here.
- # This test bypasses the type facility for speed
- # (critical when drawing)
-
- if not isinstance(self, DivisionShape):
- for child in self._children:
- child.GetEventHandler().OnDrawControlPoints(dc)
-
- def OnEraseControlPoints(self, dc):
- for control in self._controlPoints:
- control.Erase(dc)
-
- if not isinstance(self, DivisionShape):
- for child in self._children:
- child.GetEventHandler().OnEraseControlPoints(dc)
-
- def Select(self, select, dc = None):
- """Select or deselect the given shape, drawing or erasing control points
- (handles) as necessary.
- """
- self._selected = select
- if select:
- self.MakeControlPoints()
- # Children of divisions are contained objects,
- # so stop here
- if not isinstance(self, DivisionShape):
- for child in self._children:
- child.MakeMandatoryControlPoints()
- if dc:
- self.GetEventHandler().OnDrawControlPoints(dc)
- else:
- self.DeleteControlPoints(dc)
- if not isinstance(self, DivisionShape):
- for child in self._children:
- child.DeleteControlPoints(dc)
-
- def Selected(self):
- """TRUE if the shape is currently selected."""
- return self._selected
-
- def AncestorSelected(self):
- """TRUE if the shape's ancestor is currently selected."""
- if self._selected:
- return True
- if not self.GetParent():
- return False
- return self.GetParent().AncestorSelected()
-
- def GetNumberOfAttachments(self):
- """Get the number of attachment points for this shape."""
- # Should return the MAXIMUM attachment point id here,
- # so higher-level functions can iterate through all attachments,
- # even if they're not contiguous.
-
- if len(self._attachmentPoints) == 0:
- return 4
- else:
- maxN = 3
- for point in self._attachmentPoints:
- if point._id>maxN:
- maxN = point._id
- return maxN + 1
-
- def AttachmentIsValid(self, attachment):
- """TRUE if attachment is a valid attachment point."""
- if len(self._attachmentPoints) == 0:
- return attachment in range(4)
-
- for point in self._attachmentPoints:
- if point._id == attachment:
- return True
- return False
-
- def GetAttachmentPosition(self, attachment, nth = 0, no_arcs = 1, line = None):
- """Get the position at which the given attachment point should be drawn.
-
- If attachment isn't found among the attachment points of the shape,
- returns None.
- """
- if self._attachmentMode == ATTACHMENT_MODE_NONE:
- return self._xpos, self._ypos
- elif self._attachmentMode == ATTACHMENT_MODE_BRANCHING:
- pt, stemPt = self.GetBranchingAttachmentPoint(attachment, nth)
- return pt.x, pt.y
- elif self._attachmentMode == ATTACHMENT_MODE_EDGE:
- if len(self._attachmentPoints):
- for point in self._attachmentPoints:
- if point._id == attachment:
- return self._xpos + point._x, self._ypos + point._y
- return None
- else:
- # Assume is rectangular
- w, h = self.GetBoundingBoxMax()
- top = self._ypos + h / 2
- bottom = self._ypos - h / 2
- left = self._xpos - w / 2
- right = self._xpos + w / 2
-
- # wtf?
- line and line.IsEnd(self)
-
- physicalAttachment = self.LogicalToPhysicalAttachment(attachment)
-
- # Simplified code
- if physicalAttachment == 0:
- pt = self.CalcSimpleAttachment((left, bottom), (right, bottom), nth, no_arcs, line)
- elif physicalAttachment == 1:
- pt = self.CalcSimpleAttachment((right, bottom), (right, top), nth, no_arcs, line)
- elif physicalAttachment == 2:
- pt = self.CalcSimpleAttachment((left, top), (right, top), nth, no_arcs, line)
- elif physicalAttachment == 3:
- pt = self.CalcSimpleAttachment((left, bottom), (left, top), nth, no_arcs, line)
- else:
- return None
- return pt[0], pt[1]
- return None
-
- def GetBoundingBoxMax(self):
- """Get the maximum bounding box for the shape, taking into account
- external features such as shadows.
- """
- ww, hh = self.GetBoundingBoxMin()
- if self._shadowMode != SHADOW_NONE:
- ww += self._shadowOffsetX
- hh += self._shadowOffsetY
- return ww, hh
-
- def GetBoundingBoxMin(self):
- """Get the minimum bounding box for the shape, that defines the area
- available for drawing the contents (such as text).
-
- Must be overridden.
- """
- return 0, 0
-
- def HasDescendant(self, image):
- """TRUE if image is a descendant of this composite."""
- if image == self:
- return True
- for child in self._children:
- if child.HasDescendant(image):
- return True
- return False
-
- # Clears points from a list of wxRealPoints, and clears list
- # Useless in python? /pi
- def ClearPointList(self, list):
- list = []
-
- # Assuming the attachment lies along a vertical or horizontal line,
- # calculate the position on that point.
- def CalcSimpleAttachment(self, pt1, pt2, nth, noArcs, line):
- """Assuming the attachment lies along a vertical or horizontal line,
- calculate the position on that point.
-
- Parameters:
-
- pt1
- The first point of the line repesenting the edge of the shape.
-
- pt2
- The second point of the line representing the edge of the shape.
-
- nth
- The position on the edge (for example there may be 6 lines at
- this attachment point, and this may be the 2nd line.
-
- noArcs
- The number of lines at this edge.
-
- line
- The line shape.
-
- Remarks
-
- This function expects the line to be either vertical or horizontal,
- and determines which.
- """
- isEnd = line and line.IsEnd(self)
-
- # Are we horizontal or vertical?
- isHorizontal = RoughlyEqual(pt1[1], pt2[1])
-
- if isHorizontal:
- if pt1[0]>pt2[0]:
- firstPoint = pt2
- secondPoint = pt1
- else:
- firstPoint = pt1
- secondPoint = pt2
-
- if self._spaceAttachments:
- if line and line.GetAlignmentType(isEnd) == LINE_ALIGNMENT_TO_NEXT_HANDLE:
- # Align line according to the next handle along
- point = line.GetNextControlPoint(self)
- if point[0]<firstPoint[0]:
- x = firstPoint[0]
- elif point[0]>secondPoint[0]:
- x = secondPoint[0]
- else:
- x = point[0]
- else:
- x = firstPoint[0] + (nth + 1) * (secondPoint[0] - firstPoint[0]) / (noArcs + 1)
- else:
- x = (secondPoint[0] - firstPoint[0]) / 2 # Midpoint
- y = pt1[1]
- else:
- assert RoughlyEqual(pt1[0], pt2[0])
-
- if pt1[1]>pt2[1]:
- firstPoint = pt2
- secondPoint = pt1
- else:
- firstPoint = pt1
- secondPoint = pt2
-
- if self._spaceAttachments:
- if line and line.GetAlignmentType(isEnd) == LINE_ALIGNMENT_TO_NEXT_HANDLE:
- # Align line according to the next handle along
- point = line.GetNextControlPoint(self)
- if point[1]<firstPoint[1]:
- y = firstPoint[1]
- elif point[1]>secondPoint[1]:
- y = secondPoint[1]
- else:
- y = point[1]
- else:
- y = firstPoint[1] + (nth + 1) * (secondPoint[1] - firstPoint[1]) / (noArcs + 1)
- else:
- y = (secondPoint[1] - firstPoint[1]) / 2 # Midpoint
- x = pt1[0]
-
- return x, y
-
- # Return the zero-based position in m_lines of line
- def GetLinePosition(self, line):
- """Get the zero-based position of line in the list of lines
- for this shape.
- """
- try:
- return self._lines.index(line)
- except:
- return 0
-
-
- # |________|
- # | <- root
- # | <- neck
- # shoulder1 ->---------<- shoulder2
- # | | | | |
- # <- branching attachment point N-1
-
- def GetBranchingAttachmentInfo(self, attachment):
- """Get information about where branching connections go.
-
- Returns FALSE if there are no lines at this attachment.
- """
- physicalAttachment = self.LogicalToPhysicalAttachment(attachment)
-
- # Number of lines at this attachment
- lineCount = self.GetAttachmentLineCount(attachment)
-
- if not lineCount:
- return False
-
- totalBranchLength = self._branchSpacing * (lineCount - 1)
- root = self.GetBranchingAttachmentRoot(attachment)
-
- neck = wx.RealPoint()
- shoulder1 = wx.RealPoint()
- shoulder2 = wx.RealPoint()
-
- # Assume that we have attachment points 0 to 3: top, right, bottom, left
- if physicalAttachment == 0:
- neck.x = self.GetX()
- neck.y = root.y - self._branchNeckLength
-
- shoulder1.x = root.x - totalBranchLength / 2
- shoulder2.x = root.x + totalBranchLength / 2
-
- shoulder1.y = neck.y
- shoulder2.y = neck.y
- elif physicalAttachment == 1:
- neck.x = root.x + self._branchNeckLength
- neck.y = root.y
-
- shoulder1.x = neck.x
- shoulder2.x = neck.x
-
- shoulder1.y = neck.y - totalBranchLength / 2
- shoulder1.y = neck.y + totalBranchLength / 2
- elif physicalAttachment == 2:
- neck.x = self.GetX()
- neck.y = root.y + self._branchNeckLength
-
- shoulder1.x = root.x - totalBranchLength / 2
- shoulder2.x = root.x + totalBranchLength / 2
-
- shoulder1.y = neck.y
- shoulder2.y = neck.y
- elif physicalAttachment == 3:
- neck.x = root.x - self._branchNeckLength
- neck.y = root.y
-
- shoulder1.x = neck.x
- shoulder2.x = neck.x
-
- shoulder1.y = neck.y - totalBranchLength / 2
- shoulder2.y = neck.y + totalBranchLength / 2
- else:
- raise "Unrecognised attachment point in GetBranchingAttachmentInfo"
- return root, neck, shoulder1, shoulder2
-
- def GetBranchingAttachmentPoint(self, attachment, n):
- physicalAttachment = self.LogicalToPhysicalAttachment(attachment)
-
- root, neck, shoulder1, shoulder2 = self.GetBranchingAttachmentInfo(attachment)
- pt = wx.RealPoint()
- stemPt = wx.RealPoint()
-
- if physicalAttachment == 0:
- pt.y = neck.y - self._branchStemLength
- pt.x = shoulder1.x + n * self._branchSpacing
-
- stemPt.x = pt.x
- stemPt.y = neck.y
- elif physicalAttachment == 2:
- pt.y = neck.y + self._branchStemLength
- pt.x = shoulder1.x + n * self._branchStemLength
-
- stemPt.x = pt.x
- stemPt.y = neck.y
- elif physicalAttachment == 1:
- pt.x = neck.x + self._branchStemLength
- pt.y = shoulder1.y + n * self._branchSpacing
-
- stemPt.x = neck.x
- stemPt.y = pt.y
- elif physicalAttachment == 3:
- pt.x = neck.x - self._branchStemLength
- pt.y = shoulder1.y + n * self._branchSpacing
-
- stemPt.x = neck.x
- stemPt.y = pt.y
- else:
- raise "Unrecognised attachment point in GetBranchingAttachmentPoint"
-
- return pt, stemPt
-
- def GetAttachmentLineCount(self, attachment):
- """Get the number of lines at this attachment position."""
- count = 0
- for lineShape in self._lines:
- if lineShape.GetFrom() == self and lineShape.GetAttachmentFrom() == attachment:
- count += 1
- elif lineShape.GetTo() == self and lineShape.GetAttachmentTo() == attachment:
- count += 1
- return count
-
- def GetBranchingAttachmentRoot(self, attachment):
- """Get the root point at the given attachment."""
- physicalAttachment = self.LogicalToPhysicalAttachment(attachment)
-
- root = wx.RealPoint()
-
- width, height = self.GetBoundingBoxMax()
-
- # Assume that we have attachment points 0 to 3: top, right, bottom, left
- if physicalAttachment == 0:
- root.x = self.GetX()
- root.y = self.GetY() - height / 2
- elif physicalAttachment == 1:
- root.x = self.GetX() + width / 2
- root.y = self.GetY()
- elif physicalAttachment == 2:
- root.x = self.GetX()
- root.y = self.GetY() + height / 2
- elif physicalAttachment == 3:
- root.x = self.GetX() - width / 2
- root.y = self.GetY()
- else:
- raise "Unrecognised attachment point in GetBranchingAttachmentRoot"
-
- return root
-
- # Draw or erase the branches (not the actual arcs though)
- def OnDrawBranchesAttachment(self, dc, attachment, erase = False):
- count = self.GetAttachmentLineCount(attachment)
- if count == 0:
- return
-
- root, neck, shoulder1, shoulder2 = self.GetBranchingAttachmentInfo(attachment)
-
- if erase:
- dc.SetPen(wx.WHITE_PEN)
- dc.SetBrush(wx.WHITE_BRUSH)
- else:
- dc.SetPen(wx.BLACK_PEN)
- dc.SetBrush(wx.BLACK_BRUSH)
-
- # Draw neck
- dc.DrawLine(root, neck)
-
- if count>1:
- # Draw shoulder-to-shoulder line
- dc.DrawLine(shoulder1, shoulder2)
- # Draw all the little branches
- for i in range(count):
- pt, stemPt = self.GetBranchingAttachmentPoint(attachment, i)
- dc.DrawLine(stemPt, pt)
-
- if self.GetBranchStyle() & BRANCHING_ATTACHMENT_BLOB and count>1:
- blobSize = 6
- dc.DrawEllipse(stemPt.x - blobSize / 2, stemPt.y - blobSize / 2, blobSize, blobSize)
-
- def OnDrawBranches(self, dc, erase = False):
- if self._attachmentMode != ATTACHMENT_MODE_BRANCHING:
- return
- for i in range(self.GetNumberOfAttachments()):
- self.OnDrawBranchesAttachment(dc, i, erase)
-
- def GetAttachmentPositionEdge(self, attachment, nth = 0, no_arcs = 1, line = None):
- """ Only get the attachment position at the _edge_ of the shape,
- ignoring branching mode. This is used e.g. to indicate the edge of
- interest, not the point on the attachment branch.
- """
- oldMode = self._attachmentMode
-
- # Calculate as if to edge, not branch
- if self._attachmentMode == ATTACHMENT_MODE_BRANCHING:
- self._attachmentMode = ATTACHMENT_MODE_EDGE
- res = self.GetAttachmentPosition(attachment, nth, no_arcs, line)
- self._attachmentMode = oldMode
-
- return res
-
- def PhysicalToLogicalAttachment(self, physicalAttachment):
- """ Rotate the standard attachment point from physical
- (0 is always North) to logical (0 -> 1 if rotated by 90 degrees)
- """
- if RoughlyEqual(self.GetRotation(), 0):
- i = physicalAttachment
- elif RoughlyEqual(self.GetRotation(), pi / 2):
- i = physicalAttachment - 1
- elif RoughlyEqual(self.GetRotation(), pi):
- i = physicalAttachment - 2
- elif RoughlyEqual(self.GetRotation(), 3 * pi / 2):
- i = physicalAttachment - 3
- else:
- # Can't handle -- assume the same
- return physicalAttachment
-
- if i<0:
- i += 4
-
- return i
-
- def LogicalToPhysicalAttachment(self, logicalAttachment):
- """Rotate the standard attachment point from logical
- to physical (0 is always North).
- """
- if RoughlyEqual(self.GetRotation(), 0):
- i = logicalAttachment
- elif RoughlyEqual(self.GetRotation(), pi / 2):
- i = logicalAttachment + 1
- elif RoughlyEqual(self.GetRotation(), pi):
- i = logicalAttachment + 2
- elif RoughlyEqual(self.GetRotation(), 3 * pi / 2):
- i = logicalAttachment + 3
- else:
- return logicalAttachment
-
- if i>3:
- i -= 4
-
- return i
-
- def Rotate(self, x, y, theta):
- """Rotate about the given axis by the given amount in radians."""
- self._rotation = theta
- if self._rotation<0:
- self._rotation += 2 * pi
- elif self._rotation>2 * pi:
- self._rotation -= 2 * pi
-
- def GetBackgroundPen(self):
- """Return pen of the right colour for the background."""
- if self.GetCanvas():
- return wx.Pen(self.GetCanvas().GetBackgroundColour(), 1, wx.SOLID)
- return WhiteBackgroundPen
-
- def GetBackgroundBrush(self):
- """Return brush of the right colour for the background."""
- if self.GetCanvas():
- return wx.Brush(self.GetCanvas().GetBackgroundColour(), wx.SOLID)
- return WhiteBackgroundBrush
-
- def GetX(self):
- """Get the x position of the centre of the shape."""
- return self._xpos
-
- def GetY(self):
- """Get the y position of the centre of the shape."""
- return self._ypos
-
- def SetX(self, x):
- """Set the x position of the shape."""
- self._xpos = x
-
- def SetY(self, y):
- """Set the y position of the shape."""
- self._ypos = y
-
- def GetParent(self):
- """Return the parent of this shape, if it is part of a composite."""
- return self._parent
-
- def SetParent(self, p):
- self._parent = p
-
- def GetChildren(self):
- """Return the list of children for this shape."""
- return self._children
-
- def GetDrawHandles(self):
- """Return the list of drawhandles."""
- return self._drawHandles
-
- def GetEventHandler(self):
- """Return the event handler for this shape."""
- return self._eventHandler
-
- def SetEventHandler(self, handler):
- """Set the event handler for this shape."""
- self._eventHandler = handler
-
- def Recompute(self):
- """Recomputes any constraints associated with the shape.
-
- Normally applicable to CompositeShapes only, but harmless for
- other classes of Shape.
- """
- return True
-
- def IsHighlighted(self):
- """TRUE if the shape is highlighted. Shape highlighting is unimplemented."""
- return self._highlighted
-
- def GetSensitivityFilter(self):
- """Return the sensitivity filter, a bitlist of values.
-
- See Shape.SetSensitivityFilter.
- """
- return self._sensitivity
-
- def SetFixedSize(self, x, y):
- """Set the shape to be fixed size."""
- self._fixedWidth = x
- self._fixedHeight = y
-
- def GetFixedSize(self):
- """Return flags indicating whether the shape is of fixed size in
- either direction.
- """
- return self._fixedWidth, self._fixedHeight
-
- def GetFixedWidth(self):
- """TRUE if the shape cannot be resized in the horizontal plane."""
- return self._fixedWidth
-
- def GetFixedHeight(self):
- """TRUE if the shape cannot be resized in the vertical plane."""
- return self._fixedHeight
-
- def SetSpaceAttachments(self, sp):
- """Indicate whether lines should be spaced out evenly at the point
- they touch the node (sp = True), or whether they should join at a single
- point (sp = False).
- """
- self._spaceAttachments = sp
-
- def GetSpaceAttachments(self):
- """Return whether lines should be spaced out evenly at the point they
- touch the node (True), or whether they should join at a single point
- (False).
- """
- return self._spaceAttachments
-
- def SetCentreResize(self, cr):
- """Specify whether the shape is to be resized from the centre (the
- centre stands still) or from the corner or side being dragged (the
- other corner or side stands still).
- """
- self._centreResize = cr
-
- def GetCentreResize(self):
- """TRUE if the shape is to be resized from the centre (the centre stands
- still), or FALSE if from the corner or side being dragged (the other
- corner or side stands still)
- """
- return self._centreResize
-
- def SetMaintainAspectRatio(self, ar):
- """Set whether a shape that resizes should not change the aspect ratio
- (width and height should be in the original proportion).
- """
- self._maintainAspectRatio = ar
-
- def GetMaintainAspectRatio(self):
- """TRUE if shape keeps aspect ratio during resize."""
- return self._maintainAspectRatio
-
- def GetLines(self):
- """Return the list of lines connected to this shape."""
- return self._lines
-
- def SetDisableLabel(self, flag):
- """Set flag to TRUE to stop the default region being shown."""
- self._disableLabel = flag
-
- def GetDisableLabel(self):
- """TRUE if the default region will not be shown, FALSE otherwise."""
- return self._disableLabel
-
- def SetAttachmentMode(self, mode):
- """Set the attachment mode.
-
- If TRUE, attachment points will be significant when drawing lines to
- and from this shape.
- If FALSE, lines will be drawn as if to the centre of the shape.
- """
- self._attachmentMode = mode
-
- def GetAttachmentMode(self):
- """Return the attachment mode.
-
- See Shape.SetAttachmentMode.
- """
- return self._attachmentMode
-
- def SetId(self, i):
- """Set the integer identifier for this shape."""
- self._id = i
-
- def GetId(self):
- """Return the integer identifier for this shape."""
- return self._id
-
- def IsShown(self):
- """TRUE if the shape is in a visible state, FALSE otherwise.
-
- Note that this has nothing to do with whether the window is hidden
- or the shape has scrolled off the canvas; it refers to the internal
- visibility flag.
- """
- return self._visible
-
- def GetPen(self):
- """Return the pen used for drawing the shape's outline."""
- return self._pen
-
- def GetBrush(self):
- """Return the brush used for filling the shape."""
- return self._brush
-
- def GetNumberOfTextRegions(self):
- """Return the number of text regions for this shape."""
- return len(self._regions)
-
- def GetRegions(self):
- """Return the list of ShapeRegions."""
- return self._regions
-
- # Control points ('handles') redirect control to the actual shape, to
- # make it easier to override sizing behaviour.
- def OnSizingDragLeft(self, pt, draw, x, y, keys = 0, attachment = 0):
- bound_x, bound_y = self.GetBoundingBoxMin()
-
- dc = wx.ClientDC(self.GetCanvas())
- self.GetCanvas().PrepareDC(dc)
-
- dc.SetLogicalFunction(OGLRBLF)
-
- dottedPen = wx.Pen(wx.Colour(0, 0, 0), 1, wx.DOT)
- dc.SetPen(dottedPen)
- dc.SetBrush(wx.TRANSPARENT_BRUSH)
-
- if self.GetCentreResize():
- # Maintain the same centre point
- new_width = 2.0 * abs(x - self.GetX())
- new_height = 2.0 * abs(y - self.GetY())
-
- # Constrain sizing according to what control point you're dragging
- if pt._type == CONTROL_POINT_HORIZONTAL:
- if self.GetMaintainAspectRatio():
- new_height = bound_y * (new_width / bound_x)
- else:
- new_height = bound_y
- elif pt._type == CONTROL_POINT_VERTICAL:
- if self.GetMaintainAspectRatio():
- new_width = bound_x * (new_height / bound_y)
- else:
- new_width = bound_x
- elif pt._type == CONTROL_POINT_DIAGONAL and (keys & KEY_SHIFT):
- new_height = bound_y * (new_width / bound_x)
-
- if self.GetFixedWidth():
- new_width = bound_x
-
- if self.GetFixedHeight():
- new_height = bound_y
-
- pt._controlPointDragEndWidth = new_width
- pt._controlPointDragEndHeight = new_height
-
- self.GetEventHandler().OnDrawOutline(dc, self.GetX(), self.GetY(), new_width, new_height)
- else:
- # Don't maintain the same centre point
- newX1 = min(pt._controlPointDragStartX, x)
- newY1 = min(pt._controlPointDragStartY, y)
- newX2 = max(pt._controlPointDragStartX, x)
- newY2 = max(pt._controlPointDragStartY, y)
- if pt._type == CONTROL_POINT_HORIZONTAL:
- newY1 = pt._controlPointDragStartY
- newY2 = newY1 + pt._controlPointDragStartHeight
- elif pt._type == CONTROL_POINT_VERTICAL:
- newX1 = pt._controlPointDragStartX
- newX2 = newX1 + pt._controlPointDragStartWidth
- elif pt._type == CONTROL_POINT_DIAGONAL and (keys & KEY_SHIFT or self.GetMaintainAspectRatio()):
- newH = (newX2 - newX1) * (pt._controlPointDragStartHeight / pt._controlPointDragStartWidth)
- if self.GetY()>pt._controlPointDragStartY:
- newY2 = newY1 + newH
- else:
- newY1 = newY2 - newH
-
- newWidth = newX2 - newX1
- newHeight = newY2 - newY1
-
- if pt._type == CONTROL_POINT_VERTICAL and self.GetMaintainAspectRatio():
- newWidth = bound_x * (newHeight / bound_y)
-
- if pt._type == CONTROL_POINT_HORIZONTAL and self.GetMaintainAspectRatio():
- newHeight = bound_y * (newWidth / bound_x)
-
- pt._controlPointDragPosX = newX1 + newWidth / 2
- pt._controlPointDragPosY = newY1 + newHeight / 2
- if self.GetFixedWidth():
- newWidth = bound_x
-
- if self.GetFixedHeight():
- newHeight = bound_y
-
- pt._controlPointDragEndWidth = newWidth
- pt._controlPointDragEndHeight = newHeight
- self.GetEventHandler().OnDrawOutline(dc, pt._controlPointDragPosX, pt._controlPointDragPosY, newWidth, newHeight)
-
- def OnSizingBeginDragLeft(self, pt, x, y, keys = 0, attachment = 0):
- self._canvas.CaptureMouse()
-
- dc = wx.ClientDC(self.GetCanvas())
- self.GetCanvas().PrepareDC(dc)
-
- dc.SetLogicalFunction(OGLRBLF)
-
- bound_x, bound_y = self.GetBoundingBoxMin()
- self.GetEventHandler().OnEndSize(bound_x, bound_y)
-
- # Choose the 'opposite corner' of the object as the stationary
- # point in case this is non-centring resizing.
- if pt.GetX()<self.GetX():
- pt._controlPointDragStartX = self.GetX() + bound_x / 2
- else:
- pt._controlPointDragStartX = self.GetX() - bound_x / 2
-
- if pt.GetY()<self.GetY():
- pt._controlPointDragStartY = self.GetY() + bound_y / 2
- else:
- pt._controlPointDragStartY = self.GetY() - bound_y / 2
-
- if pt._type == CONTROL_POINT_HORIZONTAL:
- pt._controlPointDragStartY = self.GetY() - bound_y / 2
- elif pt._type == CONTROL_POINT_VERTICAL:
- pt._controlPointDragStartX = self.GetX() - bound_x / 2
-
- # We may require the old width and height
- pt._controlPointDragStartWidth = bound_x
- pt._controlPointDragStartHeight = bound_y
-
- dottedPen = wx.Pen(wx.Colour(0, 0, 0), 1, wx.DOT)
- dc.SetPen(dottedPen)
- dc.SetBrush(wx.TRANSPARENT_BRUSH)
-
- if self.GetCentreResize():
- new_width = 2.0 * abs(x - self.GetX())
- new_height = 2.0 * abs(y - self.GetY())
-
- # Constrain sizing according to what control point you're dragging
- if pt._type == CONTROL_POINT_HORIZONTAL:
- if self.GetMaintainAspectRatio():
- new_height = bound_y * (new_width / bound_x)
- else:
- new_height = bound_y
- elif pt._type == CONTROL_POINT_VERTICAL:
- if self.GetMaintainAspectRatio():
- new_width = bound_x * (new_height / bound_y)
- else:
- new_width = bound_x
- elif pt._type == CONTROL_POINT_DIAGONAL and (keys & KEY_SHIFT):
- new_height = bound_y * (new_width / bound_x)
-
- if self.GetFixedWidth():
- new_width = bound_x
-
- if self.GetFixedHeight():
- new_height = bound_y
-
- pt._controlPointDragEndWidth = new_width
- pt._controlPointDragEndHeight = new_height
- self.GetEventHandler().OnDrawOutline(dc, self.GetX(), self.GetY(), new_width, new_height)
- else:
- # Don't maintain the same centre point
- newX1 = min(pt._controlPointDragStartX, x)
- newY1 = min(pt._controlPointDragStartY, y)
- newX2 = max(pt._controlPointDragStartX, x)
- newY2 = max(pt._controlPointDragStartY, y)
- if pt._type == CONTROL_POINT_HORIZONTAL:
- newY1 = pt._controlPointDragStartY
- newY2 = newY1 + pt._controlPointDragStartHeight
- elif pt._type == CONTROL_POINT_VERTICAL:
- newX1 = pt._controlPointDragStartX
- newX2 = newX1 + pt._controlPointDragStartWidth
- elif pt._type == CONTROL_POINT_DIAGONAL and (keys & KEYS or self.GetMaintainAspectRatio()):
- newH = (newX2 - newX1) * (pt._controlPointDragStartHeight / pt._controlPointDragStartWidth)
- if pt.GetY()>pt._controlPointDragStartY:
- newY2 = newY1 + newH
- else:
- newY1 = newY2 - newH
-
- newWidth = newX2 - newX1
- newHeight = newY2 - newY1
-
- if pt._type == CONTROL_POINT_VERTICAL and self.GetMaintainAspectRatio():
- newWidth = bound_x * (newHeight / bound_y)
-
- if pt._type == CONTROL_POINT_HORIZONTAL and self.GetMaintainAspectRatio():
- newHeight = bound_y * (newWidth / bound_x)
-
- pt._controlPointDragPosX = newX1 + newWidth / 2
- pt._controlPointDragPosY = newY1 + newHeight / 2
- if self.GetFixedWidth():
- newWidth = bound_x
-
- if self.GetFixedHeight():
- newHeight = bound_y
-
- pt._controlPointDragEndWidth = newWidth
- pt._controlPointDragEndHeight = newHeight
- self.GetEventHandler().OnDrawOutline(dc, pt._controlPointDragPosX, pt._controlPointDragPosY, newWidth, newHeight)
-
- def OnSizingEndDragLeft(self, pt, x, y, keys = 0, attachment = 0):
- dc = wx.ClientDC(self.GetCanvas())
- self.GetCanvas().PrepareDC(dc)
-
- if self._canvas.HasCapture():
- self._canvas.ReleaseMouse()
- dc.SetLogicalFunction(wx.COPY)
- self.Recompute()
- self.ResetControlPoints()
-
- self.Erase(dc)
-
- self.SetSize(pt._controlPointDragEndWidth, pt._controlPointDragEndHeight)
-
- # The next operation could destroy this control point (it does for
- # label objects, via formatting the text), so save all values we're
- # going to use, or we'll be accessing garbage.
-
- #return
-
- if self.GetCentreResize():
- self.Move(dc, self.GetX(), self.GetY())
- else:
- self.Move(dc, pt._controlPointDragPosX, pt._controlPointDragPosY)
-
- # Recursively redraw links if we have a composite
- if len(self.GetChildren()):
- self.DrawLinks(dc,-1, True)
-
- width, height = self.GetBoundingBoxMax()
- self.GetEventHandler().OnEndSize(width, height)
-
- if not self._canvas.GetQuickEditMode() and pt._eraseObject:
- self._canvas.Redraw(dc)
-
-
-
-class RectangleShape(Shape):
- """
- The wxRectangleShape has rounded or square corners.
-
- Derived from:
- Shape
- """
- def __init__(self, w = 0.0, h = 0.0):
- Shape.__init__(self)
- self._width = w
- self._height = h
- self._cornerRadius = 0.0
- self.SetDefaultRegionSize()
-
- def OnDraw(self, dc):
- x1 = self._xpos - self._width / 2
- y1 = self._ypos - self._height / 2
-
- if self._shadowMode != SHADOW_NONE:
- if self._shadowBrush:
- dc.SetBrush(self._shadowBrush)
- dc.SetPen(TransparentPen)
-
- if self._cornerRadius:
- dc.DrawRoundedRectangle(x1 + self._shadowOffsetX, y1 + self._shadowOffsetY, self._width, self._height, self._cornerRadius)
- else:
- dc.DrawRectangle(x1 + self._shadowOffsetX, y1 + self._shadowOffsetY, self._width, self._height)
-
- if self._pen:
- if self._pen.GetWidth() == 0:
- dc.SetPen(TransparentPen)
- else:
- dc.SetPen(self._pen)
- if self._brush:
- dc.SetBrush(self._brush)
-
- if self._cornerRadius:
- dc.DrawRoundedRectangle(x1, y1, self._width, self._height, self._cornerRadius)
- else:
- dc.DrawRectangle(x1, y1, self._width, self._height)
-
- def GetBoundingBoxMin(self):
- return self._width, self._height
-
- def SetSize(self, x, y, recursive = False):
- self.SetAttachmentSize(x, y)
- self._width = max(x, 1)
- self._height = max(y, 1)
- self.SetDefaultRegionSize()
-
- def GetCornerRadius(self):
- """Get the radius of the rectangle's rounded corners."""
- return self._cornerRadius
-
- def SetCornerRadius(self, rad):
- """Set the radius of the rectangle's rounded corners.
-
- If the radius is zero, a non-rounded rectangle will be drawn.
- If the radius is negative, the value is the proportion of the smaller
- dimension of the rectangle.
- """
- self._cornerRadius = rad
-
- # Assume (x1, y1) is centre of box (most generally, line end at box)
- def GetPerimeterPoint(self, x1, y1, x2, y2):
- bound_x, bound_y = self.GetBoundingBoxMax()
- return FindEndForBox(bound_x, bound_y, self._xpos, self._ypos, x2, y2)
-
- def GetWidth(self):
- return self._width
-
- def GetHeight(self):
- return self._height
-
- def SetWidth(self, w):
- self._width = w
-
- def SetHeight(self, h):
- self._height = h
-
-
-
-class PolygonShape(Shape):
- """A PolygonShape's shape is defined by a number of points passed to
- the object's constructor. It can be used to create new shapes such as
- diamonds and triangles.
- """
- def __init__(self):
- Shape.__init__(self)
-
- self._points = None
- self._originalPoints = None
-
- def Create(self, the_points = None):
- """Takes a list of wx.RealPoints or tuples; each point is an offset
- from the centre.
- """
- self.ClearPoints()
-
- if not the_points:
- self._originalPoints = []
- self._points = []
- else:
- self._originalPoints = the_points
-
- # Duplicate the list of points
- self._points = []
- for point in the_points:
- new_point = wx.Point(point[0], point[1])
- self._points.append(new_point)
- self.CalculateBoundingBox()
- self._originalWidth = self._boundWidth
- self._originalHeight = self._boundHeight
- self.SetDefaultRegionSize()
-
- def ClearPoints(self):
- self._points = []
- self._originalPoints = []
-
- # Width and height. Centre of object is centre of box
- def GetBoundingBoxMin(self):
- return self._boundWidth, self._boundHeight
-
- def GetPoints(self):
- """Return the internal list of polygon vertices."""
- return self._points
-
- def GetOriginalPoints(self):
- return self._originalPoints
-
- def GetOriginalWidth(self):
- return self._originalWidth
-
- def GetOriginalHeight(self):
- return self._originalHeight
-
- def SetOriginalWidth(self, w):
- self._originalWidth = w
-
- def SetOriginalHeight(self, h):
- self._originalHeight = h
-
- def CalculateBoundingBox(self):
- # Calculate bounding box at construction (and presumably resize) time
- left = 10000
- right=-10000
- top = 10000
- bottom=-10000
-
- for point in self._points:
- if point.x<left:
- left = point.x
- if point.x>right:
- right = point.x
-
- if point.y<top:
- top = point.y
- if point.y>bottom:
- bottom = point.y
-
- self._boundWidth = right - left
- self._boundHeight = bottom - top
-
- def CalculatePolygonCentre(self):
- """Recalculates the centre of the polygon, and
- readjusts the point offsets accordingly.
- Necessary since the centre of the polygon
- is expected to be the real centre of the bounding
- box.
- """
- left = 10000
- right=-10000
- top = 10000
- bottom=-10000
-
- for point in self._points:
- if point.x<left:
- left = point.x
- if point.x>right:
- right = point.x
-
- if point.y<top:
- top = point.y
- if point.y>bottom:
- bottom = point.y
-
- bwidth = right - left
- bheight = bottom - top
-
- newCentreX = left + bwidth / 2
- newCentreY = top + bheight / 2
-
- for point in self._points:
- point.x -= newCentreX
- point.y -= newCentreY
- self._xpos += newCentreX
- self._ypos += newCentreY
-
- def HitTest(self, x, y):
- # Imagine four lines radiating from this point. If all of these lines
- # hit the polygon, we're inside it, otherwise we're not. Obviously
- # we'd need more radiating lines to be sure of correct results for
- # very strange (concave) shapes.
- endPointsX = [x, x + 1000, x, x - 1000]
- endPointsY = [y - 1000, y, y + 1000, y]
-
- xpoints = []
- ypoints = []
-
- for point in self._points:
- xpoints.append(point.x + self._xpos)
- ypoints.append(point.y + self._ypos)
-
- # We assume it's inside the polygon UNLESS one or more
- # lines don't hit the outline.
- isContained = True
-
- for i in range(4):
- if not PolylineHitTest(xpoints, ypoints, x, y, endPointsX[i], endPointsY[i]):
- isContained = False
-
- if not isContained:
- return False
-
- nearest_attachment = 0
-
- # If a hit, check the attachment points within the object
- nearest = 999999
-
- for i in range(self.GetNumberOfAttachments()):
- e = self.GetAttachmentPositionEdge(i)
- if e:
- xp, yp = e
- l = sqrt((xp - x) * (xp - x) + (yp - y) * (yp - y))
- if l<nearest:
- nearest = l
- nearest_attachment = i
-
- return nearest_attachment, nearest
-
- # Really need to be able to reset the shape! Otherwise, if the
- # points ever go to zero, we've lost it, and can't resize.
- def SetSize(self, new_width, new_height, recursive = True):
- self.SetAttachmentSize(new_width, new_height)
-
- # Multiply all points by proportion of new size to old size
- x_proportion = abs(new_width / self._originalWidth)
- y_proportion = abs(new_height / self._originalHeight)
-
- for i in range(max(len(self._points), len(self._originalPoints))):
- self._points[i].x = self._originalPoints[i][0] * x_proportion
- self._points[i].y = self._originalPoints[i][1] * y_proportion
-
- self._boundWidth = abs(new_width)
- self._boundHeight = abs(new_height)
- self.SetDefaultRegionSize()
-
- # Make the original points the same as the working points
- def UpdateOriginalPoints(self):
- """If we've changed the shape, must make the original points match the
- working points with this function.
- """
- self._originalPoints = []
-
- for point in self._points:
- original_point = wx.RealPoint(point.x, point.y)
- self._originalPoints.append(original_point)
-
- self.CalculateBoundingBox()
- self._originalWidth = self._boundWidth
- self._originalHeight = self._boundHeight
-
- def AddPolygonPoint(self, pos):
- """Add a control point after the given point."""
- try:
- firstPoint = self._points[pos]
- except ValueError:
- firstPoint = self._points[0]
-
- try:
- secondPoint = self._points[pos + 1]
- except ValueError:
- secondPoint = self._points[0]
-
- x = (secondPoint.x - firstPoint.x) / 2 + firstPoint.x
- y = (secondPoint.y - firstPoint.y) / 2 + firstPoint.y
- point = wx.RealPoint(x, y)
-
- if pos >= len(self._points) - 1:
- self._points.append(point)
- else:
- self._points.insert(pos + 1, point)
-
- self.UpdateOriginalPoints()
-
- if self._selected:
- self.DeleteControlPoints()
- self.MakeControlPoints()
-
- def DeletePolygonPoint(self, pos):
- """Delete the given control point."""
- if pos<len(self._points):
- del self._points[pos]
- self.UpdateOriginalPoints()
- if self._selected:
- self.DeleteControlPoints()
- self.MakeControlPoints()
-
- # Assume (x1, y1) is centre of box (most generally, line end at box)
- def GetPerimeterPoint(self, x1, y1, x2, y2):
- # First check for situation where the line is vertical,
- # and we would want to connect to a point on that vertical --
- # oglFindEndForPolyline can't cope with this (the arrow
- # gets drawn to the wrong place).
- if self._attachmentMode == ATTACHMENT_MODE_NONE and x1 == x2:
- # Look for the point we'd be connecting to. This is
- # a heuristic...
- for point in self._points:
- if point.x == 0:
- if y2>y1 and point.y>0:
- return point.x + self._xpos, point.y + self._ypos
- elif y2<y1 and point.y<0:
- return point.x + self._xpos, point.y + self._ypos
-
- xpoints = []
- ypoints = []
- for point in self._points:
- xpoints.append(point.x + self._xpos)
- ypoints.append(point.y + self._ypos)
-
- return FindEndForPolyline(xpoints, ypoints, x1, y1, x2, y2)
-
- def OnDraw(self, dc):
- if self._shadowMode != SHADOW_NONE:
- if self._shadowBrush:
- dc.SetBrush(self._shadowBrush)
- dc.SetPen(TransparentPen)
-
- dc.DrawPolygon(self._points, self._xpos + self._shadowOffsetX, self._ypos, self._shadowOffsetY)
-
- if self._pen:
- if self._pen.GetWidth() == 0:
- dc.SetPen(TransparentPen)
- else:
- dc.SetPen(self._pen)
- if self._brush:
- dc.SetBrush(self._brush)
- dc.DrawPolygon(self._points, self._xpos, self._ypos)
-
- def OnDrawOutline(self, dc, x, y, w, h):
- dc.SetBrush(wx.TRANSPARENT_BRUSH)
- # Multiply all points by proportion of new size to old size
- x_proportion = abs(w / self._originalWidth)
- y_proportion = abs(h / self._originalHeight)
-
- intPoints = []
- for point in self._originalPoints:
- intPoints.append(wx.Point(x_proportion * point[0], y_proportion * point[1]))
- dc.DrawPolygon(intPoints, x, y)
-
- # Make as many control points as there are vertices
- def MakeControlPoints(self):
- for point in self._points:
- control = PolygonControlPoint(self._canvas, self, CONTROL_POINT_SIZE, point, point.x, point.y)
- self._canvas.AddShape(control)
- self._controlPoints.append(control)
-
- def ResetControlPoints(self):
- for i in range(min(len(self._points), len(self._controlPoints))):
- point = self._points[i]
- self._controlPoints[i]._xoffset = point.x
- self._controlPoints[i]._yoffset = point.y
- self._controlPoints[i].polygonVertex = point
-
- def GetNumberOfAttachments(self):
- maxN = max(len(self._points) - 1, 0)
- for point in self._attachmentPoints:
- if point._id>maxN:
- maxN = point._id
- return maxN + 1
-
- def GetAttachmentPosition(self, attachment, nth = 0, no_arcs = 1, line = None):
- if self._attachmentMode == ATTACHMENT_MODE_EDGE and self._points and attachment<len(self._points):
- point = self._points[0]
- return point.x + self._xpos, point.y + self._ypos
- return Shape.GetAttachmentPosition(self, attachment, nth, no_arcs, line)
-
- def AttachmentIsValid(self, attachment):
- if not self._points:
- return False
-
- if attachment >= 0 and attachment<len(self._points):
- return True
-
- for point in self._attachmentPoints:
- if point._id == attachment:
- return True
-
- return False
-
- # Rotate about the given axis by the given amount in radians
- def Rotate(self, x, y, theta):
- actualTheta = theta - self._rotation
-
- # Rotate attachment points
- sinTheta = sin(actualTheta)
- cosTheta = cos(actualTheta)
-
- for point in self._attachmentPoints:
- x1 = point._x
- y1 = point._y
-
- point._x = x1 * cosTheta - y1 * sinTheta + x * (1 - cosTheta) + y * sinTheta
- point._y = x1 * sinTheta + y1 * cosTheta + y * (1 - cosTheta) + x * sinTheta
-
- for point in self._points:
- x1 = point.x
- y1 = point.y
-
- point.x = x1 * cosTheta - y1 * sinTheta + x * (1 - cosTheta) + y * sinTheta
- point.y = x1 * sinTheta + y1 * cosTheta + y * (1 - cosTheta) + x * sinTheta
-
- for point in self._originalPoints:
- x1 = point.x
- y1 = point.y
-
- point.x = x1 * cosTheta - y1 * sinTheta + x * (1 - cosTheta) + y * sinTheta
- point.y = x1 * sinTheta + y1 * cosTheta + y * (1 - cosTheta) + x * sinTheta
-
- self._rotation = theta
-
- self.CalculatePolygonCentre()
- self.CalculateBoundingBox()
- self.ResetControlPoints()
-
- # Control points ('handles') redirect control to the actual shape, to
- # make it easier to override sizing behaviour.
- def OnSizingDragLeft(self, pt, draw, x, y, keys = 0, attachment = 0):
- dc = wx.ClientDC(self.GetCanvas())
- self.GetCanvas().PrepareDC(dc)
-
- dc.SetLogicalFunction(OGLRBLF)
-
- dottedPen = wx.Pen(wx.Colour(0, 0, 0), 1, wx.DOT)
- dc.SetPen(dottedPen)
- dc.SetBrush(wx.TRANSPARENT_BRUSH)
-
- # Code for CTRL-drag in C++ version commented out
-
- pt.CalculateNewSize(x, y)
-
- self.GetEventHandler().OnDrawOutline(dc, self.GetX(), self.GetY(), pt.GetNewSize().x, pt.GetNewSize().y)
-
- def OnSizingBeginDragLeft(self, pt, x, y, keys = 0, attachment = 0):
- dc = wx.ClientDC(self.GetCanvas())
- self.GetCanvas().PrepareDC(dc)
-
- self.Erase(dc)
-
- dc.SetLogicalFunction(OGLRBLF)
-
- bound_x, bound_y = self.GetBoundingBoxMin()
-
- dist = sqrt((x - self.GetX()) * (x - self.GetX()) + (y - self.GetY()) * (y - self.GetY()))
-
- pt._originalDistance = dist
- pt._originalSize.x = bound_x
- pt._originalSize.y = bound_y
-
- if pt._originalDistance == 0:
- pt._originalDistance = 0.0001
-
- dottedPen = wx.Pen(wx.Colour(0, 0, 0), 1, wx.DOT)
- dc.SetPen(dottedPen)
- dc.SetBrush(wx.TRANSPARENT_BRUSH)
-
- # Code for CTRL-drag in C++ version commented out
-
- pt.CalculateNewSize(x, y)
-
- self.GetEventHandler().OnDrawOutline(dc, self.GetX(), self.GetY(), pt.GetNewSize().x, pt.GetNewSize().y)
-
- self._canvas.CaptureMouse()
-
- def OnSizingEndDragLeft(self, pt, x, y, keys = 0, attachment = 0):
- dc = wx.ClientDC(self.GetCanvas())
- self.GetCanvas().PrepareDC(dc)
-
- if self._canvas.HasCapture():
- self._canvas.ReleaseMouse()
- dc.SetLogicalFunction(wx.COPY)
-
- # If we're changing shape, must reset the original points
- if keys & KEY_CTRL:
- self.CalculateBoundingBox()
- self.CalculatePolygonCentre()
- else:
- self.SetSize(pt.GetNewSize().x, pt.GetNewSize().y)
-
- self.Recompute()
- self.ResetControlPoints()
- self.Move(dc, self.GetX(), self.GetY())
- if not self._canvas.GetQuickEditMode():
- self._canvas.Redraw(dc)
-
-
-
-class EllipseShape(Shape):
- """The EllipseShape behaves similarly to the RectangleShape but is
- elliptical.
-
- Derived from:
- wxShape
- """
- def __init__(self, w, h):
- Shape.__init__(self)
- self._width = w
- self._height = h
- self.SetDefaultRegionSize()
-
- def GetBoundingBoxMin(self):
- return self._width, self._height
-
- def GetPerimeterPoint(self, x1, y1, x2, y2):
- bound_x, bound_y = self.GetBoundingBoxMax()
-
- return DrawArcToEllipse(self._xpos, self._ypos, bound_x, bound_y, x2, y2, x1, y1)
-
- def GetWidth(self):
- return self._width
-
- def GetHeight(self):
- return self._height
-
- def SetWidth(self, w):
- self._width = w
-
- def SetHeight(self, h):
- self._height = h
-
- def OnDraw(self, dc):
- if self._shadowMode != SHADOW_NONE:
- if self._shadowBrush:
- dc.SetBrush(self._shadowBrush)
- dc.SetPen(TransparentPen)
- dc.DrawEllipse(self._xpos - self.GetWidth() / 2 + self._shadowOffsetX,
- self._ypos - self.GetHeight() / 2 + self._shadowOffsetY,
- self.GetWidth(), self.GetHeight())
-
- if self._pen:
- if self._pen.GetWidth() == 0:
- dc.SetPen(TransparentPen)
- else:
- dc.SetPen(self._pen)
- if self._brush:
- dc.SetBrush(self._brush)
- dc.DrawEllipse(self._xpos - self.GetWidth() / 2, self._ypos - self.GetHeight() / 2, self.GetWidth(), self.GetHeight())
-
- def SetSize(self, x, y, recursive = True):
- self.SetAttachmentSize(x, y)
- self._width = x
- self._height = y
- self.SetDefaultRegionSize()
-
- def GetNumberOfAttachments(self):
- return Shape.GetNumberOfAttachments(self)
-
- # There are 4 attachment points on an ellipse - 0 = top, 1 = right,
- # 2 = bottom, 3 = left.
- def GetAttachmentPosition(self, attachment, nth = 0, no_arcs = 1, line = None):
- if self._attachmentMode == ATTACHMENT_MODE_BRANCHING:
- return Shape.GetAttachmentPosition(self, attachment, nth, no_arcs, line)
-
- if self._attachmentMode != ATTACHMENT_MODE_NONE:
- top = self._ypos + self._height / 2
- bottom = self._ypos - self._height / 2
- left = self._xpos - self._width / 2
- right = self._xpos + self._width / 2
-
- physicalAttachment = self.LogicalToPhysicalAttachment(attachment)
-
- if physicalAttachment == 0:
- if self._spaceAttachments:
- x = left + (nth + 1) * self._width / (no_arcs + 1)
- else:
- x = self._xpos
- y = top
- # We now have the point on the bounding box: but get the point
- # on the ellipse by imagining a vertical line from
- # (x, self._ypos - self_height - 500) to (x, self._ypos) intersecting
- # the ellipse.
-
- return DrawArcToEllipse(self._xpos, self._ypos, self._width, self._height, x, self._ypos - self._height - 500, x, self._ypos)
- elif physicalAttachment == 1:
- x = right
- if self._spaceAttachments:
- y = bottom + (nth + 1) * self._height / (no_arcs + 1)
- else:
- y = self._ypos
- return DrawArcToEllipse(self._xpos, self._ypos, self._width, self._height, self._xpos + self._width + 500, y, self._xpos, y)
- elif physicalAttachment == 2:
- if self._spaceAttachments:
- x = left + (nth + 1) * self._width / (no_arcs + 1)
- else:
- x = self._xpos
- y = bottom
- return DrawArcToEllipse(self._xpos, self._ypos, self._width, self._height, x, self._ypos + self._height + 500, x, self._ypos)
- elif physicalAttachment == 3:
- x = left
- if self._spaceAttachments:
- y = bottom + (nth + 1) * self._height / (no_arcs + 1)
- else:
- y = self._ypos
- return DrawArcToEllipse(self._xpos, self._ypos, self._width, self._height, self._xpos - self._width - 500, y, self._xpos, y)
- else:
- return Shape.GetAttachmentPosition(self, attachment, x, y, nth, no_arcs, line)
- else:
- return self._xpos, self._ypos
-
-
-
-class CircleShape(EllipseShape):
- """An EllipseShape whose width and height are the same."""
- def __init__(self, diameter):
- EllipseShape.__init__(self, diameter, diameter)
- self.SetMaintainAspectRatio(True)
-
- def GetPerimeterPoint(self, x1, y1, x2, y2):
- return FindEndForCircle(self._width / 2, self._xpos, self._ypos, x2, y2)
-
-
-
-class TextShape(RectangleShape):
- """As wxRectangleShape, but only the text is displayed."""
- def __init__(self, width, height):
- RectangleShape.__init__(self, width, height)
-
- def OnDraw(self, dc):
- pass
-
-
-
-class ShapeRegion(object):
- """Object region."""
- def __init__(self, region = None):
- if region:
- self._regionText = region._regionText
- self._regionName = region._regionName
- self._textColour = region._textColour
-
- self._font = region._font
- self._minHeight = region._minHeight
- self._minWidth = region._minWidth
- self._width = region._width
- self._height = region._height
- self._x = region._x
- self._y = region._y
-
- self._regionProportionX = region._regionProportionX
- self._regionProportionY = region._regionProportionY
- self._formatMode = region._formatMode
- self._actualColourObject = region._actualColourObject
- self._actualPenObject = None
- self._penStyle = region._penStyle
- self._penColour = region._penColour
-
- self.ClearText()
- for line in region._formattedText:
- new_line = ShapeTextLine(line.GetX(), line.GetY(), line.GetText())
- self._formattedText.append(new_line)
- else:
- self._regionText=""
- self._font = NormalFont
- self._minHeight = 5.0
- self._minWidth = 5.0
- self._width = 0.0
- self._height = 0.0
- self._x = 0.0
- self._y = 0.0
-
- self._regionProportionX=-1.0
- self._regionProportionY=-1.0
- self._formatMode = FORMAT_CENTRE_HORIZ | FORMAT_CENTRE_VERT
- self._regionName=""
- self._textColour="BLACK"
- self._penColour="BLACK"
- self._penStyle = wx.SOLID
- self._actualColourObject = wx.TheColourDatabase.Find("BLACK")
- self._actualPenObject = None
-
- self._formattedText = []
-
- def ClearText(self):
- self._formattedText = []
-
- def SetFont(self, f):
- self._font = f
-
- def SetMinSize(self, w, h):
- self._minWidth = w
- self._minHeight = h
-
- def SetSize(self, w, h):
- self._width = w
- self._height = h
-
- def SetPosition(self, xp, yp):
- self._x = xp
- self._y = yp
-
- def SetProportions(self, xp, yp):
- self._regionProportionX = xp
- self._regionProportionY = yp
-
- def SetFormatMode(self, mode):
- self._formatMode = mode
-
- def SetColour(self, col):
- self._textColour = col
- self._actualColourObject = col
-
- def GetActualColourObject(self):
- self._actualColourObject = wx.TheColourDatabase.Find(self.GetColour())
- return self._actualColourObject
-
- def SetPenColour(self, col):
- self._penColour = col
- self._actualPenObject = None
-
- # Returns NULL if the pen is invisible
- # (different to pen being transparent; indicates that
- # region boundary should not be drawn.)
- def GetActualPen(self):
- if self._actualPenObject:
- return self._actualPenObject
-
- if not self._penColour:
- return None
- if self._penColour=="Invisible":
- return None
- self._actualPenObject = wx.ThePenList.FindOrCreatePen(self._penColour, 1, self._penStyle)
- return self._actualPenObject
-
- def SetText(self, s):
- self._regionText = s
-
- def SetName(self, s):
- self._regionName = s
-
- def GetText(self):
- return self._regionText
-
- def GetFont(self):
- return self._font
-
- def GetMinSize(self):
- return self._minWidth, self._minHeight
-
- def GetProportion(self):
- return self._regionProportionX, self._regionProportionY
-
- def GetSize(self):
- return self._width, self._height
-
- def GetPosition(self):
- return self._x, self._y
-
- def GetFormatMode(self):
- return self._formatMode
-
- def GetName(self):
- return self._regionName
-
- def GetColour(self):
- return self._textColour
-
- def GetFormattedText(self):
- return self._formattedText
-
- def GetPenColour(self):
- return self._penColour
-
- def GetPenStyle(self):
- return self._penStyle
-
- def SetPenStyle(self, style):
- self._penStyle = style
- self._actualPenObject = None
-
- def GetWidth(self):
- return self._width
-
- def GetHeight(self):
- return self._height
-
-
-
-class ControlPoint(RectangleShape):
- def __init__(self, theCanvas, object, size, the_xoffset, the_yoffset, the_type):
- RectangleShape.__init__(self, size, size)
-
- self._canvas = theCanvas
- self._shape = object
- self._xoffset = the_xoffset
- self._yoffset = the_yoffset
- self._type = the_type
- self.SetPen(BlackForegroundPen)
- self.SetBrush(wx.BLACK_BRUSH)
- self._oldCursor = None
- self._visible = True
- self._eraseObject = True
-
- # Don't even attempt to draw any text - waste of time
- def OnDrawContents(self, dc):
- pass
-
- def OnDraw(self, dc):
- self._xpos = self._shape.GetX() + self._xoffset
- self._ypos = self._shape.GetY() + self._yoffset
- RectangleShape.OnDraw(self, dc)
-
- def OnErase(self, dc):
- RectangleShape.OnErase(self, dc)
-
- # Implement resizing of canvas object
- def OnDragLeft(self, draw, x, y, keys = 0, attachment = 0):
- self._shape.GetEventHandler().OnSizingDragLeft(self, draw, x, y, keys, attachment)
-
- def OnBeginDragLeft(self, x, y, keys = 0, attachment = 0):
- self._shape.GetEventHandler().OnSizingBeginDragLeft(self, x, y, keys, attachment)
-
- def OnEndDragLeft(self, x, y, keys = 0, attachment = 0):
- self._shape.GetEventHandler().OnSizingEndDragLeft(self, x, y, keys, attachment)
-
- def GetNumberOfAttachments(self):
- return 1
-
- def GetAttachmentPosition(self, attachment, nth = 0, no_arcs = 1, line = None):
- return self._xpos, self._ypos
-
- def SetEraseObject(self, er):
- self._eraseObject = er
-
-
-class PolygonControlPoint(ControlPoint):
- def __init__(self, theCanvas, object, size, vertex, the_xoffset, the_yoffset):
- ControlPoint.__init__(self, theCanvas, object, size, the_xoffset, the_yoffset, 0)
- self._polygonVertex = vertex
- self._originalDistance = 0.0
- self._newSize = wx.RealPoint()
- self._originalSize = wx.RealPoint()
-
- def GetNewSize(self):
- return self._newSize
-
- # Calculate what new size would be, at end of resize
- def CalculateNewSize(self, x, y):
- bound_x, bound_y = self.GetShape().GetBoundingBoxMax()
- dist = sqrt((x - self._shape.GetX()) * (x - self._shape.GetX()) + (y - self._shape.GetY()) * (y - self._shape.GetY()))
-
- self._newSize.x = dist / self._originalDistance * self._originalSize.x
- self._newSize.y = dist / self._originalDistance * self._originalSize.y
-
- # Implement resizing polygon or moving the vertex
- def OnDragLeft(self, draw, x, y, keys = 0, attachment = 0):
- self._shape.GetEventHandler().OnSizingDragLeft(self, draw, x, y, keys, attachment)
-
- def OnBeginDragLeft(self, x, y, keys = 0, attachment = 0):
- self._shape.GetEventHandler().OnSizingBeginDragLeft(self, x, y, keys, attachment)
-
- def OnEndDragLeft(self, x, y, keys = 0, attachment = 0):
- self._shape.GetEventHandler().OnSizingEndDragLeft(self, x, y, keys, attachment)
-
-from canvas import *
-from lines import *
-from composit import *