""" It removes "from __future__ import division", fixes a couple of bugs and adds a lot of whitespace. Since I also removed an instance of [::-1] for list reversing, I think this ought to work on older pythons (I have not tested though). """ git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@27884 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
		
			
				
	
	
		
			1429 lines
		
	
	
		
			51 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			1429 lines
		
	
	
		
			51 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
# -*- coding: iso-8859-1 -*-
 | 
						|
#----------------------------------------------------------------------------
 | 
						|
# Name:         composit.py
 | 
						|
# Purpose:      Composite class
 | 
						|
#
 | 
						|
# 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
 | 
						|
#----------------------------------------------------------------------------
 | 
						|
 | 
						|
import sys
 | 
						|
import wx
 | 
						|
 | 
						|
from _basic import RectangleShape, Shape, ControlPoint
 | 
						|
from _oglmisc import *
 | 
						|
 | 
						|
KEY_SHIFT, KEY_CTRL = 1, 2
 | 
						|
 | 
						|
_objectStartX = 0.0
 | 
						|
_objectStartY = 0.0
 | 
						|
 | 
						|
CONSTRAINT_CENTRED_VERTICALLY   = 1
 | 
						|
CONSTRAINT_CENTRED_HORIZONTALLY = 2
 | 
						|
CONSTRAINT_CENTRED_BOTH         = 3
 | 
						|
CONSTRAINT_LEFT_OF              = 4
 | 
						|
CONSTRAINT_RIGHT_OF             = 5
 | 
						|
CONSTRAINT_ABOVE                = 6
 | 
						|
CONSTRAINT_BELOW                = 7
 | 
						|
CONSTRAINT_ALIGNED_TOP          = 8
 | 
						|
CONSTRAINT_ALIGNED_BOTTOM       = 9
 | 
						|
CONSTRAINT_ALIGNED_LEFT         = 10
 | 
						|
CONSTRAINT_ALIGNED_RIGHT        = 11
 | 
						|
 | 
						|
# Like aligned, but with the objects centred on the respective edge
 | 
						|
# of the reference object.
 | 
						|
CONSTRAINT_MIDALIGNED_TOP       = 12
 | 
						|
CONSTRAINT_MIDALIGNED_BOTTOM    = 13
 | 
						|
CONSTRAINT_MIDALIGNED_LEFT      = 14
 | 
						|
CONSTRAINT_MIDALIGNED_RIGHT     = 15
 | 
						|
 | 
						|
 | 
						|
# Backwards compatibility names.  These should be removed eventually.
 | 
						|
gyCONSTRAINT_CENTRED_VERTICALLY   = CONSTRAINT_CENTRED_VERTICALLY   
 | 
						|
gyCONSTRAINT_CENTRED_HORIZONTALLY = CONSTRAINT_CENTRED_HORIZONTALLY 
 | 
						|
gyCONSTRAINT_CENTRED_BOTH         = CONSTRAINT_CENTRED_BOTH         
 | 
						|
gyCONSTRAINT_LEFT_OF              = CONSTRAINT_LEFT_OF              
 | 
						|
gyCONSTRAINT_RIGHT_OF             = CONSTRAINT_RIGHT_OF             
 | 
						|
gyCONSTRAINT_ABOVE                = CONSTRAINT_ABOVE                
 | 
						|
gyCONSTRAINT_BELOW                = CONSTRAINT_BELOW                
 | 
						|
gyCONSTRAINT_ALIGNED_TOP          = CONSTRAINT_ALIGNED_TOP          
 | 
						|
gyCONSTRAINT_ALIGNED_BOTTOM       = CONSTRAINT_ALIGNED_BOTTOM       
 | 
						|
gyCONSTRAINT_ALIGNED_LEFT         = CONSTRAINT_ALIGNED_LEFT         
 | 
						|
gyCONSTRAINT_ALIGNED_RIGHT        = CONSTRAINT_ALIGNED_RIGHT        
 | 
						|
gyCONSTRAINT_MIDALIGNED_TOP       = CONSTRAINT_MIDALIGNED_TOP       
 | 
						|
gyCONSTRAINT_MIDALIGNED_BOTTOM    = CONSTRAINT_MIDALIGNED_BOTTOM    
 | 
						|
gyCONSTRAINT_MIDALIGNED_LEFT      = CONSTRAINT_MIDALIGNED_LEFT      
 | 
						|
gyCONSTRAINT_MIDALIGNED_RIGHT     = CONSTRAINT_MIDALIGNED_RIGHT     
 | 
						|
 | 
						|
 | 
						|
 | 
						|
class ConstraintType(object):
 | 
						|
    def __init__(self, theType, theName, thePhrase):
 | 
						|
        self._type = theType
 | 
						|
        self._name = theName
 | 
						|
        self._phrase = thePhrase
 | 
						|
 | 
						|
 | 
						|
 | 
						|
ConstraintTypes = [
 | 
						|
    [CONSTRAINT_CENTRED_VERTICALLY,
 | 
						|
        ConstraintType(CONSTRAINT_CENTRED_VERTICALLY, "Centre vertically", "centred vertically w.r.t.")],
 | 
						|
 | 
						|
    [CONSTRAINT_CENTRED_HORIZONTALLY,
 | 
						|
        ConstraintType(CONSTRAINT_CENTRED_HORIZONTALLY, "Centre horizontally", "centred horizontally w.r.t.")],
 | 
						|
 | 
						|
    [CONSTRAINT_CENTRED_BOTH,
 | 
						|
        ConstraintType(CONSTRAINT_CENTRED_BOTH, "Centre", "centred w.r.t.")],
 | 
						|
 | 
						|
    [CONSTRAINT_LEFT_OF,
 | 
						|
        ConstraintType(CONSTRAINT_LEFT_OF, "Left of", "left of")],
 | 
						|
 | 
						|
    [CONSTRAINT_RIGHT_OF,
 | 
						|
        ConstraintType(CONSTRAINT_RIGHT_OF, "Right of", "right of")],
 | 
						|
 | 
						|
    [CONSTRAINT_ABOVE,
 | 
						|
        ConstraintType(CONSTRAINT_ABOVE, "Above", "above")],
 | 
						|
 | 
						|
    [CONSTRAINT_BELOW,
 | 
						|
        ConstraintType(CONSTRAINT_BELOW, "Below", "below")],
 | 
						|
 | 
						|
    # Alignment
 | 
						|
    [CONSTRAINT_ALIGNED_TOP,
 | 
						|
        ConstraintType(CONSTRAINT_ALIGNED_TOP, "Top-aligned", "aligned to the top of")],
 | 
						|
 | 
						|
    [CONSTRAINT_ALIGNED_BOTTOM,
 | 
						|
        ConstraintType(CONSTRAINT_ALIGNED_BOTTOM, "Bottom-aligned", "aligned to the bottom of")],
 | 
						|
 | 
						|
    [CONSTRAINT_ALIGNED_LEFT,
 | 
						|
        ConstraintType(CONSTRAINT_ALIGNED_LEFT, "Left-aligned", "aligned to the left of")],
 | 
						|
 | 
						|
    [CONSTRAINT_ALIGNED_RIGHT,
 | 
						|
        ConstraintType(CONSTRAINT_ALIGNED_RIGHT, "Right-aligned", "aligned to the right of")],
 | 
						|
 | 
						|
    # Mid-alignment
 | 
						|
    [CONSTRAINT_MIDALIGNED_TOP,
 | 
						|
        ConstraintType(CONSTRAINT_MIDALIGNED_TOP, "Top-midaligned", "centred on the top of")],
 | 
						|
 | 
						|
    [CONSTRAINT_MIDALIGNED_BOTTOM,
 | 
						|
        ConstraintType(CONSTRAINT_MIDALIGNED_BOTTOM, "Bottom-midaligned", "centred on the bottom of")],
 | 
						|
 | 
						|
    [CONSTRAINT_MIDALIGNED_LEFT,
 | 
						|
        ConstraintType(CONSTRAINT_MIDALIGNED_LEFT, "Left-midaligned", "centred on the left of")],
 | 
						|
 | 
						|
    [CONSTRAINT_MIDALIGNED_RIGHT,
 | 
						|
        ConstraintType(CONSTRAINT_MIDALIGNED_RIGHT, "Right-midaligned", "centred on the right of")]
 | 
						|
    ]
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
class Constraint(object):
 | 
						|
    """A Constraint object helps specify how child shapes are laid out with
 | 
						|
    respect to siblings and parents.
 | 
						|
 | 
						|
    Derived from:
 | 
						|
      wxObject
 | 
						|
    """
 | 
						|
    def __init__(self, type, constraining, constrained):
 | 
						|
        self._xSpacing = 0.0
 | 
						|
        self._ySpacing = 0.0
 | 
						|
 | 
						|
        self._constraintType = type
 | 
						|
        self._constraintingObject = constraining
 | 
						|
 | 
						|
        self._constraintId = 0
 | 
						|
        self._constraintName = "noname"
 | 
						|
 | 
						|
        self._constrainedObjects = constrained[:]
 | 
						|
 | 
						|
    def __repr__(self):
 | 
						|
        return "<%s.%s>" % (self.__class__.__module__, self.__class__.__name__)
 | 
						|
 | 
						|
    def SetSpacing(self, x, y):
 | 
						|
        """Sets the horizontal and vertical spacing for the constraint."""
 | 
						|
        self._xSpacing = x
 | 
						|
        self._ySpacing = y
 | 
						|
        
 | 
						|
    def Equals(self, a, b):
 | 
						|
        """Return TRUE if x and y are approximately equal (for the purposes
 | 
						|
        of evaluating the constraint).
 | 
						|
        """
 | 
						|
        marg = 0.5
 | 
						|
 | 
						|
        return b <= a + marg and b >= a - marg
 | 
						|
 | 
						|
    def Evaluate(self):
 | 
						|
        """Evaluate this constraint and return TRUE if anything changed."""
 | 
						|
        maxWidth, maxHeight = self._constraintingObject.GetBoundingBoxMax()
 | 
						|
        minWidth, minHeight = self._constraintingObject.GetBoundingBoxMin()
 | 
						|
        x = self._constraintingObject.GetX()
 | 
						|
        y = self._constraintingObject.GetY()
 | 
						|
 | 
						|
        dc = wx.ClientDC(self._constraintingObject.GetCanvas())
 | 
						|
        self._constraintingObject.GetCanvas().PrepareDC(dc)
 | 
						|
 | 
						|
        if self._constraintType == CONSTRAINT_CENTRED_VERTICALLY:
 | 
						|
            n = len(self._constrainedObjects)
 | 
						|
            totalObjectHeight = 0.0
 | 
						|
            for constrainedObject in self._constrainedObjects:
 | 
						|
                width2, height2 = constrainedObject.GetBoundingBoxMax()
 | 
						|
                totalObjectHeight += height2
 | 
						|
 | 
						|
            # Check if within the constraining object...
 | 
						|
            if totalObjectHeight + (n + 1) * self._ySpacing <= minHeight:
 | 
						|
                spacingY = (minHeight - totalObjectHeight) / (n + 1.0)
 | 
						|
                startY = y - minHeight / 2.0
 | 
						|
            else: # Otherwise, use default spacing
 | 
						|
                spacingY = self._ySpacing
 | 
						|
                startY = y - (totalObjectHeight + (n + 1) * spacingY) / 2.0
 | 
						|
 | 
						|
            # Now position the objects
 | 
						|
            changed = False
 | 
						|
            for constrainedObject in self._constrainedObjects:
 | 
						|
                width2, height2 = constrainedObject.GetBoundingBoxMax()
 | 
						|
                startY += spacingY + height2 / 2.0
 | 
						|
                if not self.Equals(startY, constrainedObject.GetY()):
 | 
						|
                    constrainedObject.Move(dc, constrainedObject.GetX(), startY, False)
 | 
						|
                    changed = True
 | 
						|
                startY += height2 / 2.0
 | 
						|
            return changed
 | 
						|
        elif self._constraintType == CONSTRAINT_CENTRED_HORIZONTALLY:
 | 
						|
            n = len(self._constrainedObjects)
 | 
						|
            totalObjectWidth = 0.0
 | 
						|
            for constrainedObject in self._constrainedObjects:
 | 
						|
                width2, height2 = constrainedObject.GetBoundingBoxMax()
 | 
						|
                totalObjectWidth += width2
 | 
						|
 | 
						|
            # Check if within the constraining object...
 | 
						|
            if totalObjectWidth + (n + 1) * self._xSpacing <= minWidth:
 | 
						|
                spacingX = (minWidth - totalObjectWidth) / (n + 1.0)
 | 
						|
                startX = x - minWidth / 2.0
 | 
						|
            else: # Otherwise, use default spacing
 | 
						|
                spacingX = self._xSpacing
 | 
						|
                startX = x - (totalObjectWidth + (n + 1) * spacingX) / 2.0
 | 
						|
 | 
						|
            # Now position the objects
 | 
						|
            changed = False
 | 
						|
            for constrainedObject in self._constrainedObjects:
 | 
						|
                width2, height2 = constrainedObject.GetBoundingBoxMax()
 | 
						|
                startX += spacingX + width2 / 2.0
 | 
						|
                if not self.Equals(startX, constrainedObject.GetX()):
 | 
						|
                    constrainedObject.Move(dc, startX, constrainedObject.GetY(), False)
 | 
						|
                    changed = True
 | 
						|
                startX += width2 / 2.0
 | 
						|
            return changed
 | 
						|
        elif self._constraintType == CONSTRAINT_CENTRED_BOTH:
 | 
						|
            n = len(self._constrainedObjects)
 | 
						|
            totalObjectWidth = 0.0
 | 
						|
            totalObjectHeight = 0.0
 | 
						|
 | 
						|
            for constrainedObject in self._constrainedObjects:
 | 
						|
                width2, height2 = constrainedObject.GetBoundingBoxMax()
 | 
						|
                totalObjectWidth += width2
 | 
						|
                totalObjectHeight += height2
 | 
						|
 | 
						|
            # Check if within the constraining object...
 | 
						|
            if totalObjectHeight + (n + 1) * self._xSpacing <= minWidth:
 | 
						|
                spacingX = (minWidth - totalObjectWidth) / (n + 1.0)
 | 
						|
                startX = x - minWidth / 2.0
 | 
						|
            else: # Otherwise, use default spacing
 | 
						|
                spacingX = self._xSpacing
 | 
						|
                startX = x - (totalObjectWidth + (n + 1) * spacingX) / 2.0
 | 
						|
 | 
						|
            # Check if within the constraining object...
 | 
						|
            if totalObjectHeight + (n + 1) * self._ySpacing <= minHeight:
 | 
						|
                spacingY = (minHeight - totalObjectHeight) / (n + 1.0)
 | 
						|
                startY = y - minHeight / 2.0
 | 
						|
            else: # Otherwise, use default spacing
 | 
						|
                spacingY = self._ySpacing
 | 
						|
                startY = y - (totalObjectHeight + (n + 1) * spacingY) / 2.0
 | 
						|
 | 
						|
            # Now position the objects
 | 
						|
            changed = False
 | 
						|
            for constrainedObject in self._constrainedObjects:
 | 
						|
                width2, height2 = constrainedObject.GetBoundingBoxMax()
 | 
						|
                startX += spacingX + width2 / 2.0
 | 
						|
                startY += spacingY + height2 / 2.0
 | 
						|
 | 
						|
                if not self.Equals(startX, constrainedObject.GetX()) or not self.Equals(startY, constrainedObject.GetY()):
 | 
						|
                    constrainedObject.Move(dc, startX, startY, False)
 | 
						|
                    changed = True
 | 
						|
 | 
						|
                startX += width2 / 2.0
 | 
						|
                startY += height2 / 2.0
 | 
						|
            return changed
 | 
						|
        elif self._constraintType == CONSTRAINT_LEFT_OF:
 | 
						|
            changed = False
 | 
						|
            for constrainedObject in self._constrainedObjects:
 | 
						|
                width2, height2 = constrainedObject.GetBoundingBoxMax()
 | 
						|
 | 
						|
                x3 = x - minWidth / 2.0 - width2 / 2.0 - self._xSpacing
 | 
						|
                if not self.Equals(x3, constrainedObject.GetX()):
 | 
						|
                    changed = True
 | 
						|
                    constrainedObject.Move(dc, x3, constrainedObject.GetY(), False)
 | 
						|
            return changed
 | 
						|
        elif self._constraintType == CONSTRAINT_RIGHT_OF:
 | 
						|
            changed = False
 | 
						|
 | 
						|
            for constrainedObject in self._constrainedObjects:
 | 
						|
                width2, height2 = constrainedObject.GetBoundingBoxMax()
 | 
						|
                x3 = x + minWidth / 2.0 + width2 / 2.0 + self._xSpacing
 | 
						|
                if not self.Equals(x3, constrainedObject.GetX()):
 | 
						|
                    constrainedObject.Move(dc, x3, constrainedObject.GetY(), False)
 | 
						|
                    changed = True
 | 
						|
            return changed
 | 
						|
        elif self._constraintType == CONSTRAINT_ABOVE:
 | 
						|
            changed = False
 | 
						|
 | 
						|
            for constrainedObject in self._constrainedObjects:
 | 
						|
                width2, height2 = constrainedObject.GetBoundingBoxMax()
 | 
						|
 | 
						|
                y3 = y - minHeight / 2.0 - height2 / 2.0 - self._ySpacing
 | 
						|
                if not self.Equals(y3, constrainedObject.GetY()):
 | 
						|
                    changed = True
 | 
						|
                    constrainedObject.Move(dc, constrainedObject.GetX(), y3, False)
 | 
						|
            return changed
 | 
						|
        elif self._constraintType == CONSTRAINT_BELOW:
 | 
						|
            changed = False
 | 
						|
 | 
						|
            for constrainedObject in self._constrainedObjects:
 | 
						|
                width2, height2 = constrainedObject.GetBoundingBoxMax()
 | 
						|
 | 
						|
                y3 = y + minHeight / 2.0 + height2 / 2.0 + self._ySpacing
 | 
						|
                if not self.Equals(y3, constrainedObject.GetY()):
 | 
						|
                    changed = True
 | 
						|
                    constrainedObject.Move(dc, constrainedObject.GetX(), y3, False)
 | 
						|
            return changed
 | 
						|
        elif self._constraintType == CONSTRAINT_ALIGNED_LEFT:
 | 
						|
            changed = False
 | 
						|
            for constrainedObject in self._constrainedObjects:
 | 
						|
                width2, height2 = constrainedObject.GetBoundingBoxMax()
 | 
						|
                x3 = x - minWidth / 2.0 + width2 / 2.0 + self._xSpacing
 | 
						|
                if not self.Equals(x3, constrainedObject.GetX()):
 | 
						|
                    changed = True
 | 
						|
                    constrainedObject.Move(dc, x3, constrainedObject.GetY(), False)
 | 
						|
            return changed
 | 
						|
        elif self._constraintType == CONSTRAINT_ALIGNED_RIGHT:
 | 
						|
            changed = False
 | 
						|
            for constrainedObject in self._constrainedObjects:
 | 
						|
                width2, height2 = constrainedObject.GetBoundingBoxMax()
 | 
						|
                x3 = x + minWidth / 2.0 - width2 / 2.0 - self._xSpacing
 | 
						|
                if not self.Equals(x3, constrainedObject.GetX()):
 | 
						|
                    changed = True
 | 
						|
                    constrainedObject.Move(dc, x3, constrainedObject.GetY(), False)
 | 
						|
            return changed
 | 
						|
        elif self._constraintType == CONSTRAINT_ALIGNED_TOP:
 | 
						|
            changed = False
 | 
						|
            for constrainedObject in self._constrainedObjects:
 | 
						|
                width2, height2 = constrainedObject.GetBoundingBoxMax()
 | 
						|
                y3 = y -  minHeight / 2.0 + height2 / 2.0 + self._ySpacing
 | 
						|
                if not self.Equals(y3, constrainedObject.GetY()):
 | 
						|
                    changed = True
 | 
						|
                    constrainedObject.Move(dc, constrainedObject.GetX(), y3, False)
 | 
						|
            return changed
 | 
						|
        elif self._constraintType == CONSTRAINT_ALIGNED_BOTTOM:
 | 
						|
            changed = False
 | 
						|
            for constrainedObject in self._constrainedObjects:
 | 
						|
                width2, height2 = constrainedObject.GetBoundingBoxMax()
 | 
						|
                y3 = y + minHeight / 2.0 - height2 / 2.0 - self._ySpacing
 | 
						|
                if not self.Equals(y3, constrainedObject.GetY()):
 | 
						|
                    changed = True
 | 
						|
                    constrainedObject.Move(dc, constrainedObject.GetX(), y3, False)
 | 
						|
            return changed
 | 
						|
        elif self._constraintType == CONSTRAINT_MIDALIGNED_LEFT:
 | 
						|
            changed = False
 | 
						|
            for constrainedObject in self._constrainedObjects:
 | 
						|
                x3 = x - minWidth / 2.0
 | 
						|
                if not self.Equals(x3, constrainedObject.GetX()):
 | 
						|
                    changed = True
 | 
						|
                    constrainedObject.Move(dc, x3, constrainedObject.GetY(), False)
 | 
						|
            return changed
 | 
						|
        elif self._constraintType == CONSTRAINT_MIDALIGNED_RIGHT:
 | 
						|
            changed = False
 | 
						|
            for constrainedObject in self._constrainedObjects:
 | 
						|
                x3 = x + minWidth / 2.0
 | 
						|
                if not self.Equals(x3, constrainedObject.GetX()):
 | 
						|
                    changed = True
 | 
						|
                    constrainedObject.Move(dc, x3, constrainedObject.GetY(), False)
 | 
						|
            return changed
 | 
						|
        elif self._constraintType == CONSTRAINT_MIDALIGNED_TOP:
 | 
						|
            changed = False
 | 
						|
            for constrainedObject in self._constrainedObjects:
 | 
						|
                y3 = y - minHeight / 2.0
 | 
						|
                if not self.Equals(y3, constrainedObject.GetY()):
 | 
						|
                    changed = True
 | 
						|
                    constrainedObject.Move(dc, constrainedObject.GetX(), y3, False)
 | 
						|
            return changed
 | 
						|
        elif self._constraintType == CONSTRAINT_MIDALIGNED_BOTTOM:
 | 
						|
            changed = False
 | 
						|
            for constrainedObject in self._constrainedObjects:
 | 
						|
                y3 = y + minHeight / 2.0
 | 
						|
                if not self.Equals(y3, constrainedObject.GetY()):
 | 
						|
                    changed = True
 | 
						|
                    constrainedObject.Move(dc, constrainedObject.GetX(), y3, False)
 | 
						|
            return changed
 | 
						|
        
 | 
						|
        return False
 | 
						|
    
 | 
						|
OGLConstraint = wx._core._deprecated(Constraint,
 | 
						|
                     "The OGLConstraint name is deprecated, use `ogl.Constraint` instead.")
 | 
						|
 | 
						|
 | 
						|
class CompositeShape(RectangleShape):
 | 
						|
    """This is an object with a list of child objects, and a list of size
 | 
						|
    and positioning constraints between the children.
 | 
						|
 | 
						|
    Derived from:
 | 
						|
      wxRectangleShape
 | 
						|
    """
 | 
						|
    def __init__(self):
 | 
						|
        RectangleShape.__init__(self, 100.0, 100.0)
 | 
						|
 | 
						|
        self._oldX = self._xpos
 | 
						|
        self._oldY = self._ypos
 | 
						|
 | 
						|
        self._constraints = [] 
 | 
						|
        self._divisions = [] # In case it's a container
 | 
						|
        
 | 
						|
    def OnDraw(self, dc):
 | 
						|
        x1 = self._xpos - self._width / 2.0
 | 
						|
        y1 = self._ypos - self._height / 2.0
 | 
						|
 | 
						|
        if self._shadowMode != SHADOW_NONE:
 | 
						|
            if self._shadowBrush:
 | 
						|
                dc.SetBrush(self._shadowBrush)
 | 
						|
            dc.SetPen(wx.Pen(wx.WHITE, 1, wx.TRANSPARENT))
 | 
						|
 | 
						|
            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)
 | 
						|
 | 
						|
        # For debug purposes /pi
 | 
						|
        #dc.DrawRectangle(x1, y1, self._width, self._height)
 | 
						|
        
 | 
						|
    def OnDrawContents(self, dc):
 | 
						|
        for object in self._children:
 | 
						|
            object.Draw(dc)
 | 
						|
            object.DrawLinks(dc)
 | 
						|
 | 
						|
        Shape.OnDrawContents(self, dc)
 | 
						|
 | 
						|
    def OnMovePre(self, dc, x, y, old_x, old_y, display = True):
 | 
						|
        diffX = x - old_x
 | 
						|
        diffY = y - old_y
 | 
						|
 | 
						|
        for object in self._children:
 | 
						|
            object.Erase(dc)
 | 
						|
            object.Move(dc, object.GetX() + diffX, object.GetY() + diffY, display)
 | 
						|
 | 
						|
        return True
 | 
						|
 | 
						|
    def OnErase(self, dc):
 | 
						|
        RectangleShape.OnErase(self, dc)
 | 
						|
        for object in self._children:
 | 
						|
            object.Erase(dc)
 | 
						|
 | 
						|
    def OnDragLeft(self, draw, x, y, keys = 0, attachment = 0):
 | 
						|
        xx, yy = self._canvas.Snap(x, y)
 | 
						|
        offsetX = xx - _objectStartX
 | 
						|
        offsetY = yy - _objectStartY
 | 
						|
 | 
						|
        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)
 | 
						|
 | 
						|
        self.GetEventHandler().OnDrawOutline(dc, self.GetX() + offsetX, self.GetY() + offsetY, self.GetWidth(), self.GetHeight())
 | 
						|
 | 
						|
    def OnBeginDragLeft(self, x, y, keys = 0, attachment = 0):
 | 
						|
        global _objectStartX, _objectStartY
 | 
						|
 | 
						|
        _objectStartX = x
 | 
						|
        _objectStartY = y
 | 
						|
 | 
						|
        dc = wx.ClientDC(self.GetCanvas())
 | 
						|
        self.GetCanvas().PrepareDC(dc)
 | 
						|
 | 
						|
        #self.Erase(dc)
 | 
						|
        
 | 
						|
        dc.SetLogicalFunction(OGLRBLF)
 | 
						|
        dottedPen = wx.Pen(wx.Colour(0, 0, 0), 1, wx.DOT)
 | 
						|
        dc.SetPen(dottedPen)
 | 
						|
        dc.SetBrush(wx.TRANSPARENT_BRUSH)
 | 
						|
        self._canvas.CaptureMouse()
 | 
						|
 | 
						|
        xx, yy = self._canvas.Snap(x, y)
 | 
						|
        offsetX = xx - _objectStartX
 | 
						|
        offsetY = yy - _objectStartY
 | 
						|
 | 
						|
        self.GetEventHandler().OnDrawOutline(dc, self.GetX() + offsetX, self.GetY() + offsetY, self.GetWidth(), self.GetHeight())
 | 
						|
 | 
						|
    def OnEndDragLeft(self, x, y, keys = 0, attachment = 0):
 | 
						|
        dc = wx.ClientDC(self.GetCanvas())
 | 
						|
        self.GetCanvas().PrepareDC(dc)
 | 
						|
 | 
						|
        if self._canvas.HasCapture():
 | 
						|
            self._canvas.ReleaseMouse()
 | 
						|
 | 
						|
        if not self._draggable:
 | 
						|
            if self._parent:
 | 
						|
                self._parent.GetEventHandler().OnEndDragLeft(x, y, keys, 0)
 | 
						|
            return
 | 
						|
            
 | 
						|
        self.Erase(dc)
 | 
						|
        
 | 
						|
        dc.SetLogicalFunction(wx.COPY)
 | 
						|
        
 | 
						|
        xx, yy = self._canvas.Snap(x, y)
 | 
						|
        offsetX = xx - _objectStartX
 | 
						|
        offsetY = yy - _objectStartY
 | 
						|
 | 
						|
        self.Move(dc, self.GetX() + offsetX, self.GetY() + offsetY)
 | 
						|
 | 
						|
        if self._canvas and not self._canvas.GetQuickEditMode():
 | 
						|
            self._canvas.Redraw(dc)
 | 
						|
 | 
						|
    def OnRightClick(self, x, y, keys = 0, attachment = 0):
 | 
						|
        # If we get a ctrl-right click, this means send the message to
 | 
						|
        # the division, so we can invoke a user interface for dealing
 | 
						|
        # with regions.
 | 
						|
        if keys & KEY_CTRL:
 | 
						|
            for division in self._divisions:
 | 
						|
                hit = division.HitTest(x, y)
 | 
						|
                if hit:
 | 
						|
                    division.GetEventHandler().OnRightClick(x, y, keys, hit[0])
 | 
						|
                    break
 | 
						|
 | 
						|
    def SetSize(self, w, h, recursive = True):
 | 
						|
        self.SetAttachmentSize(w, h)
 | 
						|
 | 
						|
        xScale = float(w) / max(1, self.GetWidth())
 | 
						|
        yScale = float(h) / max(1, self.GetHeight())
 | 
						|
 | 
						|
        self._width = w
 | 
						|
        self._height = h
 | 
						|
 | 
						|
        if not recursive:
 | 
						|
            return
 | 
						|
 | 
						|
        dc = wx.ClientDC(self.GetCanvas())
 | 
						|
        self.GetCanvas().PrepareDC(dc)
 | 
						|
 | 
						|
        for object in self._children:
 | 
						|
            # Scale the position first
 | 
						|
            newX = (object.GetX() - self.GetX()) * xScale + self.GetX()
 | 
						|
            newY = (object.GetY() - self.GetY()) * yScale + self.GetY()
 | 
						|
            object.Show(False)
 | 
						|
            object.Move(dc, newX, newY)
 | 
						|
            object.Show(True)
 | 
						|
 | 
						|
            # Now set the scaled size
 | 
						|
            xbound, ybound = object.GetBoundingBoxMax()
 | 
						|
            if not object.GetFixedWidth():
 | 
						|
                xbound *= xScale
 | 
						|
            if not object.GetFixedHeight():
 | 
						|
                ybound *= yScale
 | 
						|
            object.SetSize(xbound, ybound)
 | 
						|
 | 
						|
        self.SetDefaultRegionSize()
 | 
						|
 | 
						|
    def AddChild(self, child, addAfter = None):
 | 
						|
        """Adds a child shape to the composite.
 | 
						|
 | 
						|
        If addAfter is not None, the shape will be added after this shape.
 | 
						|
        """
 | 
						|
        self._children.append(child)
 | 
						|
        child.SetParent(self)
 | 
						|
        if self._canvas:
 | 
						|
            # Ensure we add at the right position
 | 
						|
            if addAfter:
 | 
						|
                child.RemoveFromCanvas(self._canvas)
 | 
						|
            child.AddToCanvas(self._canvas, addAfter)
 | 
						|
 | 
						|
    def RemoveChild(self, child):
 | 
						|
        """Removes the child from the composite and any constraint
 | 
						|
        relationships, but does not delete the child.
 | 
						|
        """
 | 
						|
        self._children.remove(child)
 | 
						|
        self._divisions.remove(child)
 | 
						|
        self.RemoveChildFromConstraints(child)
 | 
						|
        child.SetParent(None)
 | 
						|
 | 
						|
    def DeleteConstraintsInvolvingChild(self, child):
 | 
						|
        """This function deletes constraints which mention the given child.
 | 
						|
 | 
						|
        Used when deleting a child from the composite.
 | 
						|
        """
 | 
						|
        for constraint in self._constraints:
 | 
						|
            if constraint._constrainingObject == child or child in constraint._constrainedObjects:
 | 
						|
                self._constraints.remove(constraint)
 | 
						|
 | 
						|
    def RemoveChildFromConstraints(self, child):
 | 
						|
        for constraint in self._constraints:
 | 
						|
            if child in constraint._constrainedObjects:
 | 
						|
                constraint._constrainedObjects.remove(child)
 | 
						|
            if constraint._constrainingObject == child:
 | 
						|
                constraint._constrainingObject = None
 | 
						|
 | 
						|
            # Delete the constraint if no participants left
 | 
						|
            if not constraint._constrainingObject:
 | 
						|
                self._constraints.remove(constraint)
 | 
						|
 | 
						|
    def AddConstraint(self, constraint):
 | 
						|
        """Adds a constraint to the composite."""
 | 
						|
        self._constraints.append(constraint)
 | 
						|
        if constraint._constraintId == 0:
 | 
						|
            constraint._constraintId = wx.NewId()
 | 
						|
        return constraint
 | 
						|
 | 
						|
    def AddSimpleConstraint(self, type, constraining, constrained):
 | 
						|
        """Add a constraint of the given type to the composite.
 | 
						|
 | 
						|
        constraining is the shape doing the constraining
 | 
						|
        constrained is a list of shapes being constrained
 | 
						|
        """
 | 
						|
        constraint = Constraint(type, constraining, constrained)
 | 
						|
        if constraint._constraintId == 0:
 | 
						|
            constraint._constraintId = wx.NewId()
 | 
						|
        self._constraints.append(constraint)
 | 
						|
        return constraint
 | 
						|
 | 
						|
    def FindConstraint(self, cId):
 | 
						|
        """Finds the constraint with the given id.
 | 
						|
 | 
						|
        Returns a tuple of the constraint and the actual composite the
 | 
						|
        constraint was in, in case that composite was a descendant of
 | 
						|
        this composit.
 | 
						|
 | 
						|
        Returns None if not found.
 | 
						|
        """
 | 
						|
        for constraint in self._constraints:
 | 
						|
            if constraint._constraintId == cId:
 | 
						|
                return constraint, self
 | 
						|
 | 
						|
        # If not found, try children
 | 
						|
        for child in self._children:
 | 
						|
            if isinstance(child, CompositeShape):
 | 
						|
                constraint = child.FindConstraint(cId)
 | 
						|
                if constraint:
 | 
						|
                    return constraint[0], child
 | 
						|
 | 
						|
        return None
 | 
						|
 | 
						|
    def DeleteConstraint(self, constraint):
 | 
						|
        """Deletes constraint from composite."""
 | 
						|
        self._constraints.remove(constraint)
 | 
						|
 | 
						|
    def CalculateSize(self):
 | 
						|
        """Calculates the size and position of the composite based on
 | 
						|
        child sizes and positions.
 | 
						|
        """
 | 
						|
        maxX = -999999.9
 | 
						|
        maxY = -999999.9
 | 
						|
        minX = 999999.9
 | 
						|
        minY = 999999.9
 | 
						|
 | 
						|
        for child in self._children:
 | 
						|
            # Recalculate size of composite objects because may not conform
 | 
						|
            # to size it was set to - depends on the children.
 | 
						|
            if isinstance(child, CompositeShape):
 | 
						|
                child.CalculateSize()
 | 
						|
 | 
						|
            w, h = child.GetBoundingBoxMax()
 | 
						|
            if child.GetX() + w / 2.0 > maxX:
 | 
						|
                maxX = child.GetX() + w / 2.0
 | 
						|
            if child.GetX() - w / 2.0 < minX:
 | 
						|
                minX = child.GetX() - w / 2.0
 | 
						|
            if child.GetY() + h / 2.0 > maxY:
 | 
						|
                maxY = child.GetY() + h / 2.0
 | 
						|
            if child.GetY() - h / 2.0 < minY:
 | 
						|
                minY = child.GetY() - h / 2.0
 | 
						|
 | 
						|
        self._width = maxX - minX
 | 
						|
        self._height = maxY - minY
 | 
						|
        self._xpos = self._width / 2.0 + minX
 | 
						|
        self._ypos = self._height / 2.0 + minY
 | 
						|
 | 
						|
    def Recompute(self):
 | 
						|
        """Recomputes any constraints associated with the object. If FALSE is
 | 
						|
        returned, the constraints could not be satisfied (there was an
 | 
						|
        inconsistency).
 | 
						|
        """
 | 
						|
        noIterations = 0
 | 
						|
        changed = True
 | 
						|
        while changed and noIterations < 500:
 | 
						|
            changed = self.Constrain()
 | 
						|
            noIterations += 1
 | 
						|
 | 
						|
        return not changed
 | 
						|
 | 
						|
    def Constrain(self):
 | 
						|
        self.CalculateSize()
 | 
						|
 | 
						|
        changed = False
 | 
						|
        for child in self._children:
 | 
						|
            if isinstance(child, CompositeShape) and child.Constrain():
 | 
						|
                changed = True
 | 
						|
 | 
						|
        for constraint in self._constraints:
 | 
						|
            if constraint.Evaluate():
 | 
						|
                changed = True
 | 
						|
 | 
						|
        return changed
 | 
						|
 | 
						|
    def MakeContainer(self):
 | 
						|
        """Makes this composite into a container by creating one child
 | 
						|
        DivisionShape.
 | 
						|
        """
 | 
						|
        division = self.OnCreateDivision()
 | 
						|
        self._divisions.append(division)
 | 
						|
        self.AddChild(division)
 | 
						|
 | 
						|
        division.SetSize(self._width, self._height)
 | 
						|
 | 
						|
        dc = wx.ClientDC(self.GetCanvas())
 | 
						|
        self.GetCanvas().PrepareDC(dc)
 | 
						|
        
 | 
						|
        division.Move(dc, self.GetX(), self.GetY())
 | 
						|
        self.Recompute()
 | 
						|
        division.Show(True)
 | 
						|
 | 
						|
    def OnCreateDivision(self):
 | 
						|
        return DivisionShape()
 | 
						|
 | 
						|
    def FindContainerImage(self):
 | 
						|
        """Finds the image used to visualize a container. This is any child of
 | 
						|
        the composite that is not in the divisions list.
 | 
						|
        """
 | 
						|
        for child in self._children:
 | 
						|
            if child in self._divisions:
 | 
						|
                return child
 | 
						|
 | 
						|
        return None
 | 
						|
 | 
						|
    def ContainsDivision(self, division):
 | 
						|
        """Returns TRUE if division is a descendant of this container."""
 | 
						|
        if division in self._divisions:
 | 
						|
            return True
 | 
						|
 | 
						|
        for child in self._children:
 | 
						|
            if isinstance(child, CompositeShape):
 | 
						|
                return child.ContainsDivision(division)
 | 
						|
 | 
						|
        return False
 | 
						|
 | 
						|
    def GetDivisions(self):
 | 
						|
        """Return the list of divisions."""
 | 
						|
        return self._divisions
 | 
						|
 | 
						|
    def GetConstraints(self):
 | 
						|
        """Return the list of constraints."""
 | 
						|
        return self._constraints
 | 
						|
 | 
						|
 | 
						|
#  A division object is a composite with special properties,
 | 
						|
#  to be used for containment. It's a subdivision of a container.
 | 
						|
#  A containing node image consists of a composite with a main child shape
 | 
						|
#  such as rounded rectangle, plus a list of division objects.
 | 
						|
#  It needs to be a composite because a division contains pieces
 | 
						|
#  of diagram.
 | 
						|
#  NOTE a container has at least one wxDivisionShape for consistency.
 | 
						|
#  This can be subdivided, so it turns into two objects, then each of
 | 
						|
#  these can be subdivided, etc.
 | 
						|
 | 
						|
DIVISION_SIDE_NONE      =0
 | 
						|
DIVISION_SIDE_LEFT      =1
 | 
						|
DIVISION_SIDE_TOP       =2
 | 
						|
DIVISION_SIDE_RIGHT     =3
 | 
						|
DIVISION_SIDE_BOTTOM    =4
 | 
						|
 | 
						|
originalX = 0.0
 | 
						|
originalY = 0.0
 | 
						|
originalW = 0.0
 | 
						|
originalH = 0.0
 | 
						|
 | 
						|
 | 
						|
 | 
						|
class DivisionControlPoint(ControlPoint):
 | 
						|
    def __init__(self, the_canvas, object, size, the_xoffset, the_yoffset, the_type):
 | 
						|
        ControlPoint.__init__(self, the_canvas, object, size, the_xoffset, the_yoffset, the_type)
 | 
						|
        self.SetEraseObject(False)
 | 
						|
 | 
						|
    # Implement resizing of canvas object
 | 
						|
    def OnDragLeft(self, draw, x, y, keys = 0, attachment = 0):
 | 
						|
        ControlPoint.OnDragLeft(self, draw, x, y, keys, attachment)
 | 
						|
 | 
						|
    def OnBeginDragLeft(self, x, y, keys = 0, attachment = 0):
 | 
						|
        global originalX, originalY, originalW, originalH
 | 
						|
 | 
						|
        originalX = self._shape.GetX()
 | 
						|
        originalY = self._shape.GetY()
 | 
						|
        originalW = self._shape.GetWidth()
 | 
						|
        originalH = self._shape.GetHeight()
 | 
						|
 | 
						|
        ControlPoint.OnBeginDragLeft(self, x, y, keys, attachment)
 | 
						|
 | 
						|
    def OnEndDragLeft(self, x, y, keys = 0, attachment = 0):
 | 
						|
        ControlPoint.OnEndDragLeft(self, x, y, keys, attachment)
 | 
						|
 | 
						|
        dc = wx.ClientDC(self.GetCanvas())
 | 
						|
        self.GetCanvas().PrepareDC(dc)
 | 
						|
 | 
						|
        division = self._shape
 | 
						|
        divisionParent = division.GetParent()
 | 
						|
 | 
						|
        # Need to check it's within the bounds of the parent composite
 | 
						|
        x1 = divisionParent.GetX() - divisionParent.GetWidth() / 2.0
 | 
						|
        y1 = divisionParent.GetY() - divisionParent.GetHeight() / 2.0
 | 
						|
        x2 = divisionParent.GetX() + divisionParent.GetWidth() / 2.0
 | 
						|
        y2 = divisionParent.GetY() + divisionParent.GetHeight() / 2.0
 | 
						|
 | 
						|
        # Need to check it has not made the division zero or negative
 | 
						|
        # width / height
 | 
						|
        dx1 = division.GetX() - division.GetWidth() / 2.0
 | 
						|
        dy1 = division.GetY() - division.GetHeight() / 2.0
 | 
						|
        dx2 = division.GetX() + division.GetWidth() / 2.0
 | 
						|
        dy2 = division.GetY() + division.GetHeight() / 2.0
 | 
						|
 | 
						|
        success = True
 | 
						|
        if division.GetHandleSide() == DIVISION_SIDE_LEFT:
 | 
						|
            if x <= x1 or x >= x2 or x >= dx2:
 | 
						|
                success = False
 | 
						|
            # Try it out first...
 | 
						|
            elif not division.ResizeAdjoining(DIVISION_SIDE_LEFT, x, True):
 | 
						|
                success = False
 | 
						|
            else:
 | 
						|
                division.ResizeAdjoining(DIVISION_SIDE_LEFT, x, False)
 | 
						|
        elif division.GetHandleSide() == DIVISION_SIDE_TOP:
 | 
						|
            if y <= y1 or y >= y2 or y >= dy2:
 | 
						|
                success = False
 | 
						|
            elif not division.ResizeAdjoining(DIVISION_SIDE_TOP, y, True):
 | 
						|
                success = False
 | 
						|
            else:
 | 
						|
                division.ResizingAdjoining(DIVISION_SIDE_TOP, y, False)
 | 
						|
        elif division.GetHandleSide() == DIVISION_SIDE_RIGHT:
 | 
						|
            if x <= x1 or x >= x2 or x <= dx1:
 | 
						|
                success = False
 | 
						|
            elif not division.ResizeAdjoining(DIVISION_SIDE_RIGHT, x, True):
 | 
						|
                success = False
 | 
						|
            else:
 | 
						|
                division.ResizeAdjoining(DIVISION_SIDE_RIGHT, x, False)
 | 
						|
        elif division.GetHandleSide() == DIVISION_SIDE_BOTTOM:
 | 
						|
            if y <= y1 or y >= y2 or y <= dy1:
 | 
						|
                success = False
 | 
						|
            elif not division.ResizeAdjoining(DIVISION_SIDE_BOTTOM, y, True):
 | 
						|
                success = False
 | 
						|
            else:
 | 
						|
                division.ResizeAdjoining(DIVISION_SIDE_BOTTOM, y, False)
 | 
						|
 | 
						|
        if not success:
 | 
						|
            division.SetSize(originalW, originalH)
 | 
						|
            division.Move(dc, originalX, originalY)
 | 
						|
 | 
						|
        divisionParent.Draw(dc)
 | 
						|
        division.GetEventHandler().OnDrawControlPoints(dc)
 | 
						|
 | 
						|
 | 
						|
 | 
						|
DIVISION_MENU_SPLIT_HORIZONTALLY    =1
 | 
						|
DIVISION_MENU_SPLIT_VERTICALLY      =2
 | 
						|
DIVISION_MENU_EDIT_LEFT_EDGE        =3
 | 
						|
DIVISION_MENU_EDIT_TOP_EDGE         =4
 | 
						|
DIVISION_MENU_EDIT_RIGHT_EDGE       =5
 | 
						|
DIVISION_MENU_EDIT_BOTTOM_EDGE      =6
 | 
						|
DIVISION_MENU_DELETE_ALL            =7
 | 
						|
    
 | 
						|
 | 
						|
 | 
						|
class PopupDivisionMenu(wx.Menu):
 | 
						|
    def __init__(self):
 | 
						|
        wx.Menu.__init__(self)
 | 
						|
        self.Append(DIVISION_MENU_SPLIT_HORIZONTALLY,"Split horizontally")
 | 
						|
        self.Append(DIVISION_MENU_SPLIT_VERTICALLY,"Split vertically")
 | 
						|
        self.AppendSeparator()
 | 
						|
        self.Append(DIVISION_MENU_EDIT_LEFT_EDGE,"Edit left edge")
 | 
						|
        self.Append(DIVISION_MENU_EDIT_TOP_EDGE,"Edit top edge")
 | 
						|
 | 
						|
        wx.EVT_MENU_RANGE(self, DIVISION_MENU_SPLIT_HORIZONTALLY, DIVISION_MENU_EDIT_BOTTOM_EDGE, self.OnMenu)
 | 
						|
 | 
						|
    def SetClientData(self, data):
 | 
						|
        self._clientData = data
 | 
						|
 | 
						|
    def GetClientData(self):
 | 
						|
        return self._clientData
 | 
						|
    
 | 
						|
    def OnMenu(self, event):
 | 
						|
        division = self.GetClientData()
 | 
						|
        if event.GetId() == DIVISION_MENU_SPLIT_HORIZONTALLY:
 | 
						|
            division.Divide(wx.HORIZONTAL)
 | 
						|
        elif event.GetId() == DIVISION_MENU_SPLIT_VERTICALLY:
 | 
						|
            division.Divide(wx.VERTICAL)
 | 
						|
        elif event.GetId() == DIVISION_MENU_EDIT_LEFT_EDGE:
 | 
						|
            division.EditEdge(DIVISION_SIDE_LEFT)
 | 
						|
        elif event.GetId() == DIVISION_MENU_EDIT_TOP_EDGE:
 | 
						|
            division.EditEdge(DIVISION_SIDE_TOP)
 | 
						|
            
 | 
						|
 | 
						|
 | 
						|
class DivisionShape(CompositeShape):
 | 
						|
    """A division shape is like a composite in that it can contain further
 | 
						|
    objects, but is used exclusively to divide another shape into regions,
 | 
						|
    or divisions. A wxDivisionShape is never free-standing.
 | 
						|
 | 
						|
    Derived from:
 | 
						|
      wxCompositeShape
 | 
						|
    """
 | 
						|
    def __init__(self):
 | 
						|
        CompositeShape.__init__(self)
 | 
						|
        self.SetSensitivityFilter(OP_CLICK_LEFT | OP_CLICK_RIGHT | OP_DRAG_RIGHT)
 | 
						|
        self.SetCentreResize(False)
 | 
						|
        self.SetAttachmentMode(True)
 | 
						|
        self._leftSide = None
 | 
						|
        self._rightSide = None
 | 
						|
        self._topSide = None
 | 
						|
        self._bottomSide = None
 | 
						|
        self._handleSide = DIVISION_SIDE_NONE
 | 
						|
        self._leftSidePen = wx.BLACK_PEN
 | 
						|
        self._topSidePen = wx.BLACK_PEN
 | 
						|
        self._leftSideColour = "BLACK"
 | 
						|
        self._topSideColour = "BLACK"
 | 
						|
        self._leftSideStyle = "Solid"
 | 
						|
        self._topSideStyle = "Solid"
 | 
						|
        self.ClearRegions()
 | 
						|
 | 
						|
    def SetLeftSide(self, shape):
 | 
						|
        """Set the the division on the left side of this division."""
 | 
						|
        self._leftSide = shape
 | 
						|
 | 
						|
    def SetTopSide(self, shape):
 | 
						|
        """Set the the division on the top side of this division."""
 | 
						|
        self._topSide = shape
 | 
						|
        
 | 
						|
    def SetRightSide(self, shape):
 | 
						|
        """Set the the division on the right side of this division."""
 | 
						|
        self._rightSide = shape
 | 
						|
        
 | 
						|
    def SetBottomSide(self, shape):
 | 
						|
        """Set the the division on the bottom side of this division."""
 | 
						|
        self._bottomSide = shape
 | 
						|
 | 
						|
    def GetLeftSide(self):
 | 
						|
        """Return the division on the left side of this division."""
 | 
						|
        return self._leftSide
 | 
						|
    
 | 
						|
    def GetTopSide(self):
 | 
						|
        """Return the division on the top side of this division."""
 | 
						|
        return self._topSide
 | 
						|
    
 | 
						|
    def GetRightSide(self):
 | 
						|
        """Return the division on the right side of this division."""
 | 
						|
        return self._rightSide
 | 
						|
    
 | 
						|
    def GetBottomSide(self):
 | 
						|
        """Return the division on the bottom side of this division."""
 | 
						|
        return self._bottomSide
 | 
						|
 | 
						|
    def SetHandleSide(self, side):
 | 
						|
        """Sets the side which the handle appears on.
 | 
						|
 | 
						|
        Either DIVISION_SIDE_LEFT or DIVISION_SIDE_TOP.
 | 
						|
        """
 | 
						|
        self._handleSide = side
 | 
						|
 | 
						|
    def GetHandleSide(self):
 | 
						|
        """Return the side which the handle appears on."""
 | 
						|
        return self._handleSide
 | 
						|
 | 
						|
    def SetLeftSidePen(self, pen):
 | 
						|
        """Set the colour for drawing the left side of the division."""
 | 
						|
        self._leftSidePen = pen
 | 
						|
        
 | 
						|
    def SetTopSidePen(self, pen):
 | 
						|
        """Set the colour for drawing the top side of the division."""
 | 
						|
        self._topSidePen = pen
 | 
						|
        
 | 
						|
    def GetLeftSidePen(self):
 | 
						|
        """Return the pen used for drawing the left side of the division."""
 | 
						|
        return self._leftSidePen
 | 
						|
 | 
						|
    def GetTopSidePen(self):
 | 
						|
        """Return the pen used for drawing the top side of the division."""
 | 
						|
        return self._topSidePen
 | 
						|
 | 
						|
    def GetLeftSideColour(self):
 | 
						|
        """Return the colour used for drawing the left side of the division."""
 | 
						|
        return self._leftSideColour
 | 
						|
    
 | 
						|
    def GetTopSideColour(self):
 | 
						|
        """Return the colour used for drawing the top side of the division."""
 | 
						|
        return self._topSideColour
 | 
						|
 | 
						|
    def SetLeftSideColour(self, colour):
 | 
						|
        """Set the colour for drawing the left side of the division."""
 | 
						|
        self._leftSideColour = colour
 | 
						|
        
 | 
						|
    def SetTopSideColour(self, colour):
 | 
						|
        """Set the colour for drawing the top side of the division."""
 | 
						|
        self._topSideColour = colour
 | 
						|
        
 | 
						|
    def GetLeftSideStyle(self):
 | 
						|
        """Return the style used for the left side of the division."""
 | 
						|
        return self._leftSideStyle
 | 
						|
    
 | 
						|
    def GetTopSideStyle(self):
 | 
						|
        """Return the style used for the top side of the division."""
 | 
						|
        return self._topSideStyle
 | 
						|
 | 
						|
    def SetLeftSideStyle(self, style):
 | 
						|
        self._leftSideStyle = style
 | 
						|
        
 | 
						|
    def SetTopSideStyle(self, style):
 | 
						|
        self._lefttopStyle = style
 | 
						|
        
 | 
						|
    def OnDraw(self, dc):
 | 
						|
        dc.SetBrush(wx.TRANSPARENT_BRUSH)
 | 
						|
        dc.SetBackgroundMode(wx.TRANSPARENT)
 | 
						|
 | 
						|
        x1 = self.GetX() - self.GetWidth() / 2.0
 | 
						|
        y1 = self.GetY() - self.GetHeight() / 2.0
 | 
						|
        x2 = self.GetX() + self.GetWidth() / 2.0
 | 
						|
        y2 = self.GetY() + self.GetHeight() / 2.0
 | 
						|
 | 
						|
        # Should subtract 1 pixel if drawing under Windows
 | 
						|
        if sys.platform[:3] == "win":
 | 
						|
            y2 -= 1
 | 
						|
 | 
						|
        if self._leftSide:
 | 
						|
            dc.SetPen(self._leftSidePen)
 | 
						|
            dc.DrawLine(x1, y2, x1, y1)
 | 
						|
 | 
						|
        if self._topSide:
 | 
						|
            dc.SetPen(self._topSidePen)
 | 
						|
            dc.DrawLine(x1, y1, x2, y1)
 | 
						|
 | 
						|
        # For testing purposes, draw a rectangle so we know
 | 
						|
        # how big the division is.
 | 
						|
        #dc.SetBrush(wx.RED_BRUSH)
 | 
						|
        #dc.DrawRectangle(x1, y1, self.GetWidth(), self.GetHeight())
 | 
						|
        
 | 
						|
    def OnDrawContents(self, dc):
 | 
						|
        CompositeShape.OnDrawContents(self, dc)
 | 
						|
 | 
						|
    def OnMovePre(self, dc, x, y, oldx, oldy, display = True):
 | 
						|
        diffX = x - oldx
 | 
						|
        diffY = y - oldy
 | 
						|
        for object in self._children:
 | 
						|
            object.Erase(dc)
 | 
						|
            object.Move(dc, object.GetX() + diffX, object.GetY() + diffY, display)
 | 
						|
        return True
 | 
						|
 | 
						|
    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
 | 
						|
        Shape.OnDragLeft(self, draw, x, y, keys, attachment)
 | 
						|
 | 
						|
    def OnBeginDragLeft(self, 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().OnBeginDragLeft(x, y, keys, attachment)
 | 
						|
            return
 | 
						|
        Shape.OnBeginDragLeft(x, y, keys, attachment)
 | 
						|
            
 | 
						|
    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)
 | 
						|
 | 
						|
        self._xpos, self._ypos = self._canvas.Snap(self._xpos, self._ypos)
 | 
						|
        self.GetEventHandler().OnMovePre(dc, x, y, self._oldX, self._oldY)
 | 
						|
 | 
						|
        self.ResetControlPoints()
 | 
						|
        self.Draw(dc)
 | 
						|
        self.MoveLinks(dc)
 | 
						|
        self.GetEventHandler().OnDrawControlPoints(dc)
 | 
						|
 | 
						|
        if self._canvas and not self._canvas.GetQuickEditMode():
 | 
						|
            self._canvas.Redraw(dc)
 | 
						|
 | 
						|
    def SetSize(self, w, h, recursive = True):
 | 
						|
        self._width = w
 | 
						|
        self._height = h
 | 
						|
        RectangleShape.SetSize(self, w, h, recursive)
 | 
						|
 | 
						|
    def CalculateSize(self):
 | 
						|
        pass
 | 
						|
 | 
						|
    # Experimental
 | 
						|
    def OnRightClick(self, x, y, keys = 0, attachment = 0):
 | 
						|
        if keys & KEY_CTRL:
 | 
						|
            self.PopupMenu(x, y)
 | 
						|
        else:
 | 
						|
            if self._parent:
 | 
						|
                hit = self._parent.HitTest(x, y)
 | 
						|
                if hit:
 | 
						|
                    attachment, dist = hit
 | 
						|
                self._parent.GetEventHandler().OnRightClick(x, y, keys, attachment)
 | 
						|
 | 
						|
    # Divide wx.HORIZONTALly or wx.VERTICALly
 | 
						|
    def Divide(self, direction):
 | 
						|
        """Divide this division into two further divisions,
 | 
						|
        horizontally (direction is wxHORIZONTAL) or
 | 
						|
        vertically (direction is wxVERTICAL).
 | 
						|
        """
 | 
						|
        # Calculate existing top-left, bottom-right
 | 
						|
        x1 = self.GetX() - self.GetWidth() / 2.0
 | 
						|
        y1 = self.GetY() - self.GetHeight() / 2.0
 | 
						|
 | 
						|
        compositeParent = self.GetParent()
 | 
						|
        oldWidth = self.GetWidth()
 | 
						|
        oldHeight = self.GetHeight()
 | 
						|
        if self.Selected():
 | 
						|
            self.Select(False)
 | 
						|
 | 
						|
        dc = wx.ClientDC(self.GetCanvas())
 | 
						|
        self.GetCanvas().PrepareDC(dc)
 | 
						|
 | 
						|
        if direction == wx.VERTICAL:
 | 
						|
            # Dividing vertically means notionally putting a horizontal
 | 
						|
            # line through it.
 | 
						|
            # Break existing piece into two.
 | 
						|
            newXPos1 = self.GetX()
 | 
						|
            newYPos1 = y1 + self.GetHeight() / 4.0
 | 
						|
            newXPos2 = self.GetX()
 | 
						|
            newYPos2 = y1 + 3 * self.GetHeight() / 4.0
 | 
						|
            newDivision = compositeParent.OnCreateDivision()
 | 
						|
            newDivision.Show(True)
 | 
						|
 | 
						|
            self.Erase(dc)
 | 
						|
 | 
						|
            # Anything adjoining the bottom of this division now adjoins the
 | 
						|
            # bottom of the new division.
 | 
						|
            for obj in compositeParent.GetDivisions():
 | 
						|
                if obj.GetTopSide() == self:
 | 
						|
                    obj.SetTopSide(newDivision)
 | 
						|
 | 
						|
            newDivision.SetTopSide(self)
 | 
						|
            newDivision.SetBottomSide(self._bottomSide)
 | 
						|
            newDivision.SetLeftSide(self._leftSide)
 | 
						|
            newDivision.SetRightSide(self._rightSide)
 | 
						|
            self._bottomSide = newDivision
 | 
						|
 | 
						|
            compositeParent.GetDivisions().append(newDivision)
 | 
						|
 | 
						|
            # CHANGE: Need to insert this division at start of divisions in the
 | 
						|
            # object list, because e.g.:
 | 
						|
            # 1) Add division
 | 
						|
            # 2) Add contained object
 | 
						|
            # 3) Add division
 | 
						|
            # Division is now receiving mouse events _before_ the contained
 | 
						|
            # object, because it was added last (on top of all others)
 | 
						|
 | 
						|
            # Add after the image that visualizes the container
 | 
						|
            compositeParent.AddChild(newDivision, compositeParent.FindContainerImage())
 | 
						|
 | 
						|
            self._handleSide = DIVISION_SIDE_BOTTOM
 | 
						|
            newDivision.SetHandleSide(DIVISION_SIDE_TOP)
 | 
						|
 | 
						|
            self.SetSize(oldWidth, oldHeight / 2.0)
 | 
						|
            self.Move(dc, newXPos1, newYPos1)
 | 
						|
 | 
						|
            newDivision.SetSize(oldWidth, oldHeight / 2.0)
 | 
						|
            newDivision.Move(dc, newXPos2, newYPos2)
 | 
						|
        else:
 | 
						|
            # Dividing horizontally means notionally putting a vertical line
 | 
						|
            # through it.
 | 
						|
            # Break existing piece into two.
 | 
						|
            newXPos1 = x1 + self.GetWidth() / 4.0
 | 
						|
            newYPos1 = self.GetY()
 | 
						|
            newXPos2 = x1 + 3 * self.GetWidth() / 4.0
 | 
						|
            newYPos2 = self.GetY()
 | 
						|
            newDivision = compositeParent.OnCreateDivision()
 | 
						|
            newDivision.Show(True)
 | 
						|
 | 
						|
            self.Erase(dc)
 | 
						|
 | 
						|
            # Anything adjoining the left of this division now adjoins the
 | 
						|
            # left of the new division.
 | 
						|
            for obj in compositeParent.GetDivisions():
 | 
						|
                if obj.GetLeftSide() == self:
 | 
						|
                    obj.SetLeftSide(newDivision)
 | 
						|
 | 
						|
            newDivision.SetTopSide(self._topSide)
 | 
						|
            newDivision.SetBottomSide(self._bottomSide)
 | 
						|
            newDivision.SetLeftSide(self)
 | 
						|
            newDivision.SetRightSide(self._rightSide)
 | 
						|
            self._rightSide = newDivision
 | 
						|
 | 
						|
            compositeParent.GetDivisions().append(newDivision)
 | 
						|
            compositeParent.AddChild(newDivision, compositeParent.FindContainerImage())
 | 
						|
 | 
						|
            self._handleSide = DIVISION_SIDE_RIGHT
 | 
						|
            newDivision.SetHandleSide(DIVISION_SIDE_LEFT)
 | 
						|
 | 
						|
            self.SetSize(oldWidth / 2.0, oldHeight)
 | 
						|
            self.Move(dc, newXPos1, newYPos1)
 | 
						|
 | 
						|
            newDivision.SetSize(oldWidth / 2.0, oldHeight)
 | 
						|
            newDivision.Move(dc, newXPos2, newYPos2)
 | 
						|
 | 
						|
        if compositeParent.Selected():
 | 
						|
            compositeParent.DeleteControlPoints(dc)
 | 
						|
            compositeParent.MakeControlPoints()
 | 
						|
            compositeParent.MakeMandatoryControlPoints()
 | 
						|
 | 
						|
        compositeParent.Draw(dc)
 | 
						|
        return True
 | 
						|
 | 
						|
    def MakeControlPoints(self):
 | 
						|
        self.MakeMandatoryControlPoints()
 | 
						|
 | 
						|
    def MakeMandatoryControlPoints(self):
 | 
						|
        maxX, maxY = self.GetBoundingBoxMax()
 | 
						|
        x = y = 0.0
 | 
						|
        direction = 0
 | 
						|
 | 
						|
        if self._handleSide == DIVISION_SIDE_LEFT:
 | 
						|
            x = -maxX / 2.0
 | 
						|
            direction = CONTROL_POINT_HORIZONTAL
 | 
						|
        elif self._handleSide == DIVISION_SIDE_TOP:
 | 
						|
            y = -maxY / 2.0
 | 
						|
            direction = CONTROL_POINT_VERTICAL
 | 
						|
        elif self._handleSide == DIVISION_SIDE_RIGHT:
 | 
						|
            x = maxX / 2.0
 | 
						|
            direction = CONTROL_POINT_HORIZONTAL
 | 
						|
        elif self._handleSide == DIVISION_SIDE_BOTTOM:
 | 
						|
            y = maxY / 2.0
 | 
						|
            direction = CONTROL_POINT_VERTICAL
 | 
						|
 | 
						|
        if self._handleSide != DIVISION_SIDE_NONE:
 | 
						|
            control = DivisionControlPoint(self._canvas, self, CONTROL_POINT_SIZE, x, y, direction)
 | 
						|
            self._canvas.AddShape(control)
 | 
						|
            self._controlPoints.append(control)
 | 
						|
 | 
						|
    def ResetControlPoints(self):
 | 
						|
        self.ResetMandatoryControlPoints()
 | 
						|
 | 
						|
    def ResetMandatoryControlPoints(self):
 | 
						|
        if not self._controlPoints:
 | 
						|
            return
 | 
						|
 | 
						|
        maxX, maxY = self.GetBoundingBoxMax()
 | 
						|
 | 
						|
        node = self._controlPoints[0]
 | 
						|
 | 
						|
        if self._handleSide == DIVISION_SIDE_LEFT and node:
 | 
						|
            node._xoffset = -maxX / 2.0
 | 
						|
            node._yoffset = 0.0
 | 
						|
 | 
						|
        if self._handleSide == DIVISION_SIDE_TOP and node:
 | 
						|
            node._xoffset = 0.0
 | 
						|
            node._yoffset = -maxY / 2.0
 | 
						|
 | 
						|
        if self._handleSide == DIVISION_SIDE_RIGHT and node:
 | 
						|
            node._xoffset = maxX / 2.0
 | 
						|
            node._yoffset = 0.0
 | 
						|
 | 
						|
        if self._handleSide == DIVISION_SIDE_BOTTOM and node:
 | 
						|
            node._xoffset = 0.0
 | 
						|
            node._yoffset = maxY / 2.0
 | 
						|
 | 
						|
    def AdjustLeft(self, left, test):
 | 
						|
        """Adjust a side.
 | 
						|
 | 
						|
        Returns FALSE if it's not physically possible to adjust it to
 | 
						|
        this point.
 | 
						|
        """
 | 
						|
        x2 = self.GetX() + self.GetWidth() / 2.0
 | 
						|
 | 
						|
        if left >= x2:
 | 
						|
            return False
 | 
						|
 | 
						|
        if test:
 | 
						|
            return True
 | 
						|
 | 
						|
        newW = x2 - left
 | 
						|
        newX = left + newW / 2.0
 | 
						|
        self.SetSize(newW, self.GetHeight())
 | 
						|
 | 
						|
        dc = wx.ClientDC(self.GetCanvas())
 | 
						|
        self.GetCanvas().PrepareDC(dc)
 | 
						|
 | 
						|
        self.Move(dc, newX, self.GetY())
 | 
						|
        return True
 | 
						|
 | 
						|
    def AdjustTop(self, top, test):
 | 
						|
        """Adjust a side.
 | 
						|
 | 
						|
        Returns FALSE if it's not physically possible to adjust it to
 | 
						|
        this point.
 | 
						|
        """
 | 
						|
        y2 = self.GetY() + self.GetHeight() / 2.0
 | 
						|
 | 
						|
        if top >= y2:
 | 
						|
            return False
 | 
						|
 | 
						|
        if test:
 | 
						|
            return True
 | 
						|
 | 
						|
        newH = y2 - top
 | 
						|
        newY = top + newH / 2.0
 | 
						|
        self.SetSize(self.GetWidth(), newH)
 | 
						|
 | 
						|
        dc = wx.ClientDC(self.GetCanvas())
 | 
						|
        self.GetCanvas().PrepareDC(dc)
 | 
						|
 | 
						|
        self.Move(dc, self.GetX(), newY)
 | 
						|
        return True
 | 
						|
 | 
						|
    def AdjustRight(self, right, test):
 | 
						|
        """Adjust a side.
 | 
						|
 | 
						|
        Returns FALSE if it's not physically possible to adjust it to
 | 
						|
        this point.
 | 
						|
        """
 | 
						|
        x1 = self.GetX() - self.GetWidth() / 2.0
 | 
						|
 | 
						|
        if right <= x1:
 | 
						|
            return False
 | 
						|
 | 
						|
        if test:
 | 
						|
            return True
 | 
						|
 | 
						|
        newW = right - x1
 | 
						|
        newX = x1 + newW / 2.0
 | 
						|
        self.SetSize(newW, self.GetHeight())
 | 
						|
 | 
						|
        dc = wx.ClientDC(self.GetCanvas())
 | 
						|
        self.GetCanvas().PrepareDC(dc)
 | 
						|
 | 
						|
        self.Move(dc, newX, self.GetY())
 | 
						|
        return True
 | 
						|
    
 | 
						|
    def AdjustTop(self, top, test):
 | 
						|
        """Adjust a side.
 | 
						|
 | 
						|
        Returns FALSE if it's not physically possible to adjust it to
 | 
						|
        this point.
 | 
						|
        """
 | 
						|
        y1 = self.GetY() - self.GetHeight() / 2.0
 | 
						|
 | 
						|
        if bottom <= y1:
 | 
						|
            return False
 | 
						|
 | 
						|
        if test:
 | 
						|
            return True
 | 
						|
 | 
						|
        newH = bottom - y1
 | 
						|
        newY = y1 + newH / 2.0
 | 
						|
        self.SetSize(self.GetWidth(), newH)
 | 
						|
 | 
						|
        dc = wx.ClientDC(self.GetCanvas())
 | 
						|
        self.GetCanvas().PrepareDC(dc)
 | 
						|
 | 
						|
        self.Move(dc, self.GetX(), newY)
 | 
						|
        return True
 | 
						|
 | 
						|
    # Resize adjoining divisions.
 | 
						|
    
 | 
						|
    # Behaviour should be as follows:
 | 
						|
    # If right edge moves, find all objects whose left edge
 | 
						|
    # adjoins this object, and move left edge accordingly.
 | 
						|
    # If left..., move ... right.
 | 
						|
    # If top..., move ... bottom.
 | 
						|
    # If bottom..., move top.
 | 
						|
    # If size goes to zero or end position is other side of start position,
 | 
						|
    # resize to original size and return.
 | 
						|
    #
 | 
						|
    def ResizeAdjoining(self, side, newPos, test):
 | 
						|
        """Resize adjoining divisions at the given side.
 | 
						|
 | 
						|
        If test is TRUE, just see whether it's possible for each adjoining
 | 
						|
        region, returning FALSE if it's not.
 | 
						|
 | 
						|
        side can be one of:
 | 
						|
 | 
						|
        * DIVISION_SIDE_NONE
 | 
						|
        * DIVISION_SIDE_LEFT
 | 
						|
        * DIVISION_SIDE_TOP
 | 
						|
        * DIVISION_SIDE_RIGHT
 | 
						|
        * DIVISION_SIDE_BOTTOM
 | 
						|
        """
 | 
						|
        divisionParent = self.GetParent()
 | 
						|
        for division in divisionParent.GetDivisions():
 | 
						|
            if side == DIVISION_SIDE_LEFT:
 | 
						|
                if division._rightSide == self:
 | 
						|
                    success = division.AdjustRight(newPos, test)
 | 
						|
                    if not success and test:
 | 
						|
                        return false
 | 
						|
            elif side == DIVISION_SIDE_TOP:
 | 
						|
                if division._bottomSide == self:
 | 
						|
                    success = division.AdjustBottom(newPos, test)
 | 
						|
                    if not success and test:
 | 
						|
                        return False
 | 
						|
            elif side == DIVISION_SIDE_RIGHT:
 | 
						|
                if division._leftSide == self:
 | 
						|
                    success = division.AdjustLeft(newPos, test)
 | 
						|
                    if not success and test:
 | 
						|
                        return False
 | 
						|
            elif side == DIVISION_SIDE_BOTTOM:
 | 
						|
                if division._topSide == self:
 | 
						|
                    success = division.AdjustTop(newPos, test)
 | 
						|
                    if not success and test:
 | 
						|
                        return False
 | 
						|
        return True
 | 
						|
    
 | 
						|
    def EditEdge(self, side):
 | 
						|
        print "EditEdge() not implemented."
 | 
						|
 | 
						|
    def PopupMenu(self, x, y):
 | 
						|
        menu = PopupDivisionMenu()
 | 
						|
        menu.SetClientData(self)
 | 
						|
        if self._leftSide:
 | 
						|
            menu.Enable(DIVISION_MENU_EDIT_LEFT_EDGE, True)
 | 
						|
        else:
 | 
						|
            menu.Enable(DIVISION_MENU_EDIT_LEFT_EDGE, False)
 | 
						|
        if self._topSide:
 | 
						|
            menu.Enable(DIVISION_MENU_EDIT_TOP_EDGE, True)
 | 
						|
        else:
 | 
						|
            menu.Enable(DIVISION_MENU_EDIT_TOP_EDGE, False)
 | 
						|
 | 
						|
        x1, y1 = self._canvas.GetViewStart()
 | 
						|
        unit_x, unit_y = self._canvas.GetScrollPixelsPerUnit()
 | 
						|
 | 
						|
        dc = wx.ClientDC(self.GetCanvas())
 | 
						|
        self.GetCanvas().PrepareDC(dc)
 | 
						|
 | 
						|
        mouse_x = dc.LogicalToDeviceX(x - x1 * unit_x)
 | 
						|
        mouse_y = dc.LogicalToDeviceY(y - y1 * unit_y)
 | 
						|
 | 
						|
        self._canvas.PopupMenu(menu, (mouse_x, mouse_y))
 | 
						|
 | 
						|
        
 |