X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/6033bbc1ff95fb69b65b081d03b4a679dd958e75..f847103a32507f629c581fa900d95e97dfe16df0:/wxPython/wx/lib/ogl/composit.py diff --git a/wxPython/wx/lib/ogl/composit.py b/wxPython/wx/lib/ogl/composit.py new file mode 100644 index 0000000000..8d53b9db95 --- /dev/null +++ b/wxPython/wx/lib/ogl/composit.py @@ -0,0 +1,1410 @@ +# -*- coding: iso-8859-1 -*- +#---------------------------------------------------------------------------- +# Name: composit.py +# Purpose: Composite class +# +# Author: Pierre Hjälm (from C++ original by Julian Smart) +# +# Created: 20040508 +# RCS-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 + + + +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)) + +