X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/6033bbc1ff95fb69b65b081d03b4a679dd958e75..f847103a32507f629c581fa900d95e97dfe16df0:/wxPython/wx/lib/ogl/canvas.py diff --git a/wxPython/wx/lib/ogl/canvas.py b/wxPython/wx/lib/ogl/canvas.py new file mode 100644 index 0000000000..aaafd4d1e8 --- /dev/null +++ b/wxPython/wx/lib/ogl/canvas.py @@ -0,0 +1,360 @@ +# -*- coding: iso-8859-1 -*- +#---------------------------------------------------------------------------- +# Name: canvas.py +# Purpose: The canvas 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 wx +from lines import LineShape +from composit import * + +NoDragging, StartDraggingLeft, ContinueDraggingLeft, StartDraggingRight, ContinueDraggingRight = 0, 1, 2, 3, 4 + +KEY_SHIFT, KEY_CTRL = 1, 2 + + + +# Helper function: True if 'contains' wholly contains 'contained'. +def WhollyContains(contains, contained): + xp1, yp1 = contains.GetX(), contains.GetY() + xp2, yp2 = contained.GetX(), contained.GetY() + + w1, h1 = contains.GetBoundingBoxMax() + w2, h2 = contained.GetBoundingBoxMax() + + left1 = xp1-w1 / 2.0 + top1 = yp1-h1 / 2.0 + right1 = xp1 + w1 / 2.0 + bottom1 = yp1 + h1 / 2.0 + + left2 = xp2-w2 / 2.0 + top2 = yp2-h2 / 2.0 + right2 = xp2 + w2 / 2.0 + bottom2 = yp2 + h2 / 2.0 + + return ((left1 <= left2) and (top1 <= top2) and (right1 >= right2) and (bottom1 >= bottom2)) + + + +class ShapeCanvas(wx.ScrolledWindow): + def __init__(self, parent = None, id=-1, pos = wx.DefaultPosition, size = wx.DefaultSize, style = wx.BORDER, name="ShapeCanvas"): + wx.ScrolledWindow.__init__(self, parent, id, pos, size, style, name) + + self._shapeDiagram = None + self._dragState = NoDragging + self._draggedShape = None + self._oldDragX = 0 + self._oldDragY = 0 + self._firstDragX = 0 + self._firstDragY = 0 + self._checkTolerance = True + + wx.EVT_PAINT(self, self.OnPaint) + wx.EVT_MOUSE_EVENTS(self, self.OnMouseEvent) + + def SetDiagram(self, diag): + self._shapeDiagram = diag + + def GetDiagram(self): + return self._shapeDiagram + + def OnPaint(self, evt): + dc = wx.PaintDC(self) + self.PrepareDC(dc) + + dc.SetBackground(wx.Brush(self.GetBackgroundColour(), wx.SOLID)) + dc.Clear() + + if self.GetDiagram(): + self.GetDiagram().Redraw(dc) + + def OnMouseEvent(self, evt): + dc = wx.ClientDC(self) + self.PrepareDC(dc) + + x, y = evt.GetLogicalPosition(dc) + + keys = 0 + if evt.ShiftDown(): + keys |= KEY_SHIFT + if evt.ControlDown(): + keys |= KEY_CTRL + + dragging = evt.Dragging() + + # Check if we're within the tolerance for mouse movements. + # If we're very close to the position we started dragging + # from, this may not be an intentional drag at all. + if dragging: + dx = abs(dc.LogicalToDeviceX(x-self._firstDragX)) + dy = abs(dc.LogicalToDeviceY(y-self._firstDragY)) + if self._checkTolerance and (dx <= self.GetDiagram().GetMouseTolerance()) and (dy <= self.GetDiagram().GetMouseTolerance()): + return + # If we've ignored the tolerance once, then ALWAYS ignore + # tolerance in this drag, even if we come back within + # the tolerance range. + self._checkTolerance = False + + # Dragging - note that the effect of dragging is left entirely up + # to the object, so no movement is done unless explicitly done by + # object. + if dragging and self._draggedShape and self._dragState == StartDraggingLeft: + self._dragState = ContinueDraggingLeft + + # If the object isn't m_draggable, transfer message to canvas + if self._draggedShape.Draggable(): + self._draggedShape.GetEventHandler().OnBeginDragLeft(x, y, keys, self._draggedAttachment) + else: + self._draggedShape = None + self.OnBeginDragLeft(x, y, keys) + + self._oldDragX, self._oldDragY = x, y + + elif dragging and self._draggedShape and self._dragState == ContinueDraggingLeft: + # Continue dragging + self._draggedShape.GetEventHandler().OnDragLeft(False, self._oldDragX, self._oldDragY, keys, self._draggedAttachment) + self._draggedShape.GetEventHandler().OnDragLeft(True, x, y, keys, self._draggedAttachment) + self._oldDragX, self._oldDragY = x, y + + elif evt.LeftUp and self._draggedShape and self._dragState == ContinueDraggingLeft: + self._dragState = NoDragging + self._checkTolerance = True + + self._draggedShape.GetEventHandler().OnDragLeft(False, self._oldDragX, self._oldDragY, keys, self._draggedAttachment) + self._draggedShape.GetEventHandler().OnEndDragLeft(x, y, keys, self._draggedAttachment) + self._draggedShape = None + + elif dragging and self._draggedShape and self._dragState == StartDraggingRight: + self._dragState = ContinueDraggingRight + if self._draggedShape.Draggable: + self._draggedShape.GetEventHandler().OnBeginDragRight(x, y, keys, self._draggedAttachment) + else: + self._draggedShape = None + self.OnBeginDragRight(x, y, keys) + self._oldDragX, self._oldDragY = x, y + + elif dragging and self._draggedShape and self._dragState == ContinueDraggingRight: + # Continue dragging + self._draggedShape.GetEventHandler().OnDragRight(False, self._oldDragX, self._oldDragY, keys, self._draggedAttachment) + self._draggedShape.GetEventHandler().OnDragRight(True, x, y, keys, self._draggedAttachment) + self._oldDragX, self._oldDragY = x, y + + elif evt.RightUp() and self._draggedShape and self._dragState == ContinueDraggingRight: + self._dragState = NoDragging + self._checkTolerance = True + + self._draggedShape.GetEventHandler().OnDragRight(False, self._oldDragX, self._oldDragY, keys, self._draggedAttachment) + self._draggedShape.GetEventHandler().OnEndDragRight(x, y, keys, self._draggedAttachment) + self._draggedShape = None + + # All following events sent to canvas, not object + elif dragging and not self._draggedShape and self._dragState == StartDraggingLeft: + self._dragState = ContinueDraggingLeft + self.OnBeginDragLeft(x, y, keys) + self._oldDragX, self._oldDragY = x, y + + elif dragging and not self._draggedShape and self._dragState == ContinueDraggingLeft: + # Continue dragging + self.OnDragLeft(False, self._oldDragX, self._oldDragY, keys) + self.OnDragLeft(True, x, y, keys) + self._oldDragX, self._oldDragY = x, y + + elif evt.LeftUp() and not self._draggedShape and self._dragState == ContinueDraggingLeft: + self._dragState = NoDragging + self._checkTolerance = True + + self.OnDragLeft(False, self._oldDragX, self._oldDragY, keys) + self.OnEndDragLeft(x, y, keys) + self._draggedShape = None + + elif dragging and not self._draggedShape and self._dragState == StartDraggingRight: + self._dragState = ContinueDraggingRight + self.OnBeginDragRight(x, y, keys) + self._oldDragX, self._oldDragY = x, y + + elif dragging and not self._draggedShape and self._dragState == ContinueDraggingRight: + # Continue dragging + self.OnDragRight(False, self._oldDragX, self._oldDragY, keys) + self.OnDragRight(True, x, y, keys) + self._oldDragX, self._oldDragY = x, y + + elif evt.RightUp() and not self._draggedShape and self._dragState == ContinueDraggingRight: + self._dragState = NoDragging + self._checkTolerance = True + + self.OnDragRight(False, self._oldDragX, self._oldDragY, keys) + self.OnEndDragRight(x, y, keys) + self._draggedShape = None + + # Non-dragging events + elif evt.IsButton(): + self._checkTolerance = True + + # Find the nearest object + attachment = 0 + + nearest_object, attachment = self.FindShape(x, y) + if nearest_object: # Object event + if evt.LeftDown(): + self._draggedShape = nearest_object + self._draggedAttachment = attachment + self._dragState = StartDraggingLeft + self._firstDragX = x + self._firstDragY = y + + elif evt.LeftUp(): + # N.B. Only register a click if the same object was + # identified for down *and* up. + if nearest_object == self._draggedShape: + nearest_object.GetEventHandler().OnLeftClick(x, y, keys, attachment) + self._draggedShape = None + self._dragState = NoDragging + + elif evt.LeftDClick(): + nearest_object.GetEventHandler().OnLeftDoubleClick(x, y, keys, attachment) + self._draggedShape = None + self._dragState = NoDragging + + elif evt.RightDown(): + self._draggedShape = nearest_object + self._draggedAttachment = attachment + self._dragState = StartDraggingRight + self._firstDragX = x + self._firstDragY = y + + elif evt.RightUp(): + if nearest_object == self._draggedShape: + nearest_object.GetEventHandler().OnRightClick(x, y, keys, attachment) + self._draggedShape = None + self._dragState = NoDragging + + else: # Canvas event + if evt.LeftDown(): + self._draggedShape = None + self._dragState = StartDraggingLeft + self._firstDragX = x + self._firstDragY = y + + elif evt.LeftUp(): + self.OnLeftClick(x, y, keys) + self._draggedShape = None + self._dragState = NoDragging + + elif evt.RightDown(): + self._draggedShape = None + self._dragState = StartDraggingRight + self._firstDragX = x + self._firstDragY = y + + elif evt.RightUp(): + self.OnRightClick(x, y, keys) + self._draggedShape = None + self._dragState = NoDragging + + def FindShape(self, x, y, info = None, notObject = None): + nearest = 100000.0 + nearest_attachment = 0 + nearest_object = None + + # Go backward through the object list, since we want: + # (a) to have the control points drawn LAST to overlay + # the other objects + # (b) to find the control points FIRST if they exist + + for object in self.GetDiagram().GetShapeList()[::-1]: + # First pass for lines, which might be inside a container, so we + # want lines to take priority over containers. This first loop + # could fail if we clickout side a line, so then we'll + # try other shapes. + if object.IsShown() and \ + isinstance(object, LineShape) and \ + object.HitTest(x, y) and \ + ((info == None) or isinstance(object, info)) and \ + (not notObject or not notObject.HasDescendant(object)): + temp_attachment, dist = object.HitTest(x, y) + # A line is trickier to spot than a normal object. + # For a line, since it's the diagonal of the box + # we use for the hit test, we may have several + # lines in the box and therefore we need to be able + # to specify the nearest point to the centre of the line + # as our hit criterion, to give the user some room for + # manouevre. + if dist