# -*- 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 #---------------------------------------------------------------------------- from __future__ import division 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) startY = y-minHeight / 2 else: # Otherwise, use default spacing spacingY = self._ySpacing startY = y-(totalObjectHeight + (n + 1) * spacingY) / 2 # Now position the objects changed = False for constrainedObject in self._constrainedObjects: width2, height2 = constrainedObject.GetBoundingBoxMax() startY += spacingY + height2 / 2 if not self.Equals(startY, constrainedObject.GetY()): constrainedObject.Move(dc, constrainedObject.GetX(), startY, False) changed = True startY += height2 / 2 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._xSpacingmaxX: maxX = child.GetX() + w / 2 if child.GetX()-w / 2maxY: maxY = child.GetY() + h / 2 if child.GetY()-h / 2= 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 y1 = self.GetY()-self.GetHeight() / 2 x2 = self.GetX() + self.GetWidth() / 2 y2 = self.GetY() + self.GetHeight() / 2 # 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 y1 = self.GetY()-self.GetHeight() / 2 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 newXPos2 = self.GetX() newYPos2 = y1 + 3 * self.GetHeight() / 4 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) self.Move(dc, newXPos1, newYPos1) newDivision.SetSize(oldWidth, oldHeight / 2) 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 newYPos1 = self.GetY() newXPos2 = x1 + 3 * self.GetWidth() / 4 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, oldHeight) self.Move(dc, newXPos1, newYPos1) newDivision.SetSize(oldWidth / 2, 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 direction = CONTROL_POINT_HORIZONTAL elif self._handleSide == DIVISION_SIDE_TOP: y=-maxY / 2 direction = CONTROL_POINT_VERTICAL elif self._handleSide == DIVISION_SIDE_RIGHT: x = maxX / 2 direction = CONTROL_POINT_HORIZONTAL elif self._handleSide == DIVISION_SIDE_BOTTOM: y = maxY / 2 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 node._yoffset = 0.0 if self._handleSide == DIVISION_SIDE_TOP and node: node._xoffset = 0.0 node._yoffset=-maxY / 2 if self._handleSide == DIVISION_SIDE_RIGHT and node: node._xoffset = maxX / 2 node._yoffset = 0.0 if self._handleSide == DIVISION_SIDE_BOTTOM and node: node._xoffset = 0.0 node._yoffset = maxY / 2 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 if left >= x2: return False if test: return True newW = x2-left newX = left + newW / 2 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 if top >= y2: return False if test: return True newH = y2-top newY = top + newH / 2 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 if right <= x1: return False if test: return True newW = right-x1 newX = x1 + newW / 2 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 if bottom <= y1: return False if test: return True newH = bottom-y1 newY = y1 + newH / 2 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))