Forward port recent changes on the 2.8 branch to HEAD
git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@46083 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
170
wxPython/wx/lib/floatcanvas/Utilities/BBox.py
Normal file
170
wxPython/wx/lib/floatcanvas/Utilities/BBox.py
Normal file
@@ -0,0 +1,170 @@
|
||||
"""
|
||||
A Bounding Box object and assorted utilities , subclassed from a numpy array
|
||||
|
||||
"""
|
||||
|
||||
import numpy as N
|
||||
|
||||
class BBox(N.ndarray):
|
||||
"""
|
||||
A Bounding Box object:
|
||||
|
||||
Takes Data as an array. Data is any python sequence that can be turned into a
|
||||
2x2 numpy array of floats:
|
||||
|
||||
[[MinX, MinY ],
|
||||
[MaxX, MaxY ]]
|
||||
|
||||
It is a subclass of numpy.ndarray, so for the most part it can be used as
|
||||
an array, and arrays that fit the above description can be used in its place.
|
||||
|
||||
Usually created by the factory functions:
|
||||
|
||||
asBBox
|
||||
|
||||
and
|
||||
|
||||
fromPoints
|
||||
|
||||
"""
|
||||
def __new__(subtype, data):
|
||||
"""
|
||||
Takes Data as an array. Data is any python sequence that can be turned into a
|
||||
2x2 numpy array of floats:
|
||||
|
||||
[[MinX, MinY ],
|
||||
[MaxX, MaxY ]]
|
||||
|
||||
You don't usually call this directly. BBox objects are created with the factory functions:
|
||||
|
||||
asBBox
|
||||
|
||||
and
|
||||
|
||||
fromPoints
|
||||
|
||||
"""
|
||||
arr = N.array(data, N.float)
|
||||
arr.shape = (2,2)
|
||||
if arr[0,0] > arr[1,0] or arr[0,1] > arr[1,1]:
|
||||
# note: zero sized BB OK.
|
||||
raise ValueError("BBox values not aligned: \n minimum values must be less that maximum values")
|
||||
return N.ndarray.__new__(BBox, shape=arr.shape, dtype=arr.dtype, buffer=arr)
|
||||
|
||||
def Overlaps(self, BB):
|
||||
"""
|
||||
Overlap(BB):
|
||||
|
||||
Tests if the given Bounding Box overlaps with this one.
|
||||
Returns True is the Bounding boxes overlap, False otherwise
|
||||
If they are just touching, returns True
|
||||
"""
|
||||
|
||||
if ( (self[1,0] >= BB[0,0]) and (self[0,0] <= BB[1,0]) and
|
||||
(self[1,1] >= BB[0,1]) and (self[0,1] <= BB[1,1]) ):
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
def Inside(self, BB):
|
||||
"""
|
||||
Inside(BB):
|
||||
|
||||
Tests if the given Bounding Box is entirely inside this one.
|
||||
|
||||
Returns True if it is entirely inside, or touching the
|
||||
border.
|
||||
|
||||
Returns False otherwise
|
||||
"""
|
||||
if ( (BB[0,0] >= self[0,0]) and (BB[1,0] <= self[1,0]) and
|
||||
(BB[0,1] >= self[0,1]) and (BB[1,1] <= self[1,1]) ):
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
def Merge(self, BB):
|
||||
"""
|
||||
Joins this bounding box with the one passed in, maybe making this one bigger
|
||||
|
||||
"""
|
||||
|
||||
if BB[0,0] < self[0,0]: self[0,0] = BB[0,0]
|
||||
if BB[0,1] < self[0,1]: self[0,1] = BB[0,1]
|
||||
if BB[1,0] > self[1,0]: self[1,0] = BB[1,0]
|
||||
if BB[1,1] > self[1,1]: self[1,1] = BB[1,1]
|
||||
|
||||
### This could be used for a make BB from a bunch of BBs
|
||||
|
||||
#~ def _getboundingbox(bboxarray): # lrk: added this
|
||||
#~ # returns the bounding box of a bunch of bounding boxes
|
||||
#~ upperleft = N.minimum.reduce(bboxarray[:,0])
|
||||
#~ lowerright = N.maximum.reduce(bboxarray[:,1])
|
||||
#~ return N.array((upperleft, lowerright), N.float)
|
||||
#~ _getboundingbox = staticmethod(_getboundingbox)
|
||||
|
||||
|
||||
## Save the ndarray __eq__ for internal use.
|
||||
Array__eq__ = N.ndarray.__eq__
|
||||
def __eq__(self, BB):
|
||||
"""
|
||||
__eq__(BB) The equality operator
|
||||
|
||||
A == B if and only if all the entries are the same
|
||||
|
||||
"""
|
||||
return N.all(self.Array__eq__(BB))
|
||||
|
||||
|
||||
def asBBox(data):
|
||||
"""
|
||||
returns a BBox object.
|
||||
|
||||
If object is a BBox, it is returned unaltered
|
||||
|
||||
If object is a numpy array, a BBox object is returned that shares a
|
||||
view of the data with that array
|
||||
|
||||
"""
|
||||
|
||||
if isinstance(data, BBox):
|
||||
return data
|
||||
arr = N.asarray(data, N.float)
|
||||
return N.ndarray.__new__(BBox, shape=arr.shape, dtype=arr.dtype, buffer=arr)
|
||||
|
||||
def fromPoints(Points):
|
||||
"""
|
||||
fromPoints (Points).
|
||||
|
||||
reruns the bounding box of the set of points in Points. Points can
|
||||
be any python object that can be turned into a numpy NX2 array of Floats.
|
||||
|
||||
If a single point is passed in, a zero-size Bounding Box is returned.
|
||||
|
||||
"""
|
||||
Points = N.asarray(Points, N.float).reshape(-1,2)
|
||||
|
||||
arr = N.vstack( (Points.min(0), Points.max(0)) )
|
||||
return N.ndarray.__new__(BBox, shape=arr.shape, dtype=arr.dtype, buffer=arr)
|
||||
|
||||
def fromBBArray(BBarray):
|
||||
"""
|
||||
Builds a BBox object from an array of Bounding Boxes.
|
||||
The resulting Bounding Box encompases all the included BBs.
|
||||
|
||||
The BBarray is in the shape: (Nx2x2) where BBarray[n] is a 2x2 array that represents a BBox
|
||||
"""
|
||||
|
||||
#upperleft = N.minimum.reduce(BBarray[:,0])
|
||||
#lowerright = N.maximum.reduce(BBarray[:,1])
|
||||
|
||||
# BBarray = N.asarray(BBarray, N.float).reshape(-1,2)
|
||||
# arr = N.vstack( (BBarray.min(0), BBarray.max(0)) )
|
||||
BBarray = N.asarray(BBarray, N.float).reshape(-1,2,2)
|
||||
arr = N.vstack( (BBarray[:,0,:].min(0), BBarray[:,1,:].max(0)) )
|
||||
return asBBox(arr)
|
||||
#return asBBox( (upperleft, lowerright) ) * 2
|
||||
|
||||
|
||||
|
||||
|
354
wxPython/wx/lib/floatcanvas/Utilities/BBoxTest.py
Normal file
354
wxPython/wx/lib/floatcanvas/Utilities/BBoxTest.py
Normal file
@@ -0,0 +1,354 @@
|
||||
|
||||
"""
|
||||
Test code for the BBox Object
|
||||
|
||||
"""
|
||||
|
||||
import unittest
|
||||
|
||||
from BBox import *
|
||||
|
||||
class testCreator(unittest.TestCase):
|
||||
def testCreates(self):
|
||||
B = BBox(((0,0),(5,5)))
|
||||
self.failUnless(isinstance(B, BBox))
|
||||
|
||||
def testType(self):
|
||||
B = N.array(((0,0),(5,5)))
|
||||
self.failIf(isinstance(B, BBox))
|
||||
|
||||
def testDataType(self):
|
||||
B = BBox(((0,0),(5,5)))
|
||||
self.failUnless(B.dtype == N.float)
|
||||
|
||||
def testShape(self):
|
||||
B = BBox((0,0,5,5))
|
||||
self.failUnless(B.shape == (2,2))
|
||||
|
||||
def testShape2(self):
|
||||
self.failUnlessRaises(ValueError, BBox, (0,0,5) )
|
||||
|
||||
def testShape3(self):
|
||||
self.failUnlessRaises(ValueError, BBox, (0,0,5,6,7) )
|
||||
|
||||
def testArrayConstruction(self):
|
||||
A = N.array(((4,5),(10,12)), N.float_)
|
||||
B = BBox(A)
|
||||
self.failUnless(isinstance(B, BBox))
|
||||
|
||||
def testMinMax(self):
|
||||
self.failUnlessRaises(ValueError, BBox, (0,0,-1,6) )
|
||||
|
||||
def testMinMax2(self):
|
||||
self.failUnlessRaises(ValueError, BBox, (0,0,1,-6) )
|
||||
|
||||
def testMinMax(self):
|
||||
# OK to have a zero-sized BB
|
||||
B = BBox(((0,0),(0,5)))
|
||||
self.failUnless(isinstance(B, BBox))
|
||||
|
||||
def testMinMax2(self):
|
||||
# OK to have a zero-sized BB
|
||||
B = BBox(((10.0,-34),(10.0,-34.0)))
|
||||
self.failUnless(isinstance(B, BBox))
|
||||
|
||||
def testMinMax3(self):
|
||||
# OK to have a tiny BB
|
||||
B = BBox(((0,0),(1e-20,5)))
|
||||
self.failUnless(isinstance(B, BBox))
|
||||
|
||||
def testMinMax4(self):
|
||||
# Should catch tiny difference
|
||||
self.failUnlessRaises(ValueError, BBox, ((0,0), (-1e-20,5)) )
|
||||
|
||||
class testAsBBox(unittest.TestCase):
|
||||
|
||||
def testPassThrough(self):
|
||||
B = BBox(((0,0),(5,5)))
|
||||
C = asBBox(B)
|
||||
self.failUnless(B is C)
|
||||
|
||||
def testPassThrough2(self):
|
||||
B = (((0,0),(5,5)))
|
||||
C = asBBox(B)
|
||||
self.failIf(B is C)
|
||||
|
||||
def testPassArray(self):
|
||||
# Different data type
|
||||
A = N.array( (((0,0),(5,5))) )
|
||||
C = asBBox(A)
|
||||
self.failIf(A is C)
|
||||
|
||||
def testPassArray2(self):
|
||||
# same data type -- should be a view
|
||||
A = N.array( (((0,0),(5,5))), N.float_ )
|
||||
C = asBBox(A)
|
||||
A[0,0] = -10
|
||||
self.failUnless(C[0,0] == A[0,0])
|
||||
|
||||
class testIntersect(unittest.TestCase):
|
||||
|
||||
def testSame(self):
|
||||
B = BBox(((-23.5, 456),(56, 532.0)))
|
||||
C = BBox(((-23.5, 456),(56, 532.0)))
|
||||
self.failUnless(B.Overlaps(C) )
|
||||
|
||||
def testUpperLeft(self):
|
||||
B = BBox( ( (5, 10),(15, 25) ) )
|
||||
C = BBox( ( (0, 12),(10, 32.0) ) )
|
||||
self.failUnless(B.Overlaps(C) )
|
||||
|
||||
def testUpperRight(self):
|
||||
B = BBox( ( (5, 10),(15, 25) ) )
|
||||
C = BBox( ( (12, 12),(25, 32.0) ) )
|
||||
self.failUnless(B.Overlaps(C) )
|
||||
|
||||
def testLowerRight(self):
|
||||
B = BBox( ( (5, 10),(15, 25) ) )
|
||||
C = BBox( ( (12, 5),(25, 15) ) )
|
||||
self.failUnless(B.Overlaps(C) )
|
||||
|
||||
def testLowerLeft(self):
|
||||
B = BBox( ( (5, 10),(15, 25) ) )
|
||||
C = BBox( ( (-10, 5),(8.5, 15) ) )
|
||||
self.failUnless(B.Overlaps(C) )
|
||||
|
||||
def testBelow(self):
|
||||
B = BBox( ( (5, 10),(15, 25) ) )
|
||||
C = BBox( ( (-10, 5),(8.5, 9.2) ) )
|
||||
self.failIf(B.Overlaps(C) )
|
||||
|
||||
def testAbove(self):
|
||||
B = BBox( ( (5, 10),(15, 25) ) )
|
||||
C = BBox( ( (-10, 25.001),(8.5, 32) ) )
|
||||
self.failIf(B.Overlaps(C) )
|
||||
|
||||
def testLeft(self):
|
||||
B = BBox( ( (5, 10),(15, 25) ) )
|
||||
C = BBox( ( (4, 8),(4.95, 32) ) )
|
||||
self.failIf(B.Overlaps(C) )
|
||||
|
||||
def testRight(self):
|
||||
B = BBox( ( (5, 10),(15, 25) ) )
|
||||
C = BBox( ( (17.1, 8),(17.95, 32) ) )
|
||||
self.failIf(B.Overlaps(C) )
|
||||
|
||||
def testInside(self):
|
||||
B = BBox( ( (-15, -25),(-5, -10) ) )
|
||||
C = BBox( ( (-12, -22), (-6, -8) ) )
|
||||
self.failUnless(B.Overlaps(C) )
|
||||
|
||||
def testOutside(self):
|
||||
B = BBox( ( (-15, -25),(-5, -10) ) )
|
||||
C = BBox( ( (-17, -26), (3, 0) ) )
|
||||
self.failUnless(B.Overlaps(C) )
|
||||
|
||||
def testTouch(self):
|
||||
B = BBox( ( (5, 10),(15, 25) ) )
|
||||
C = BBox( ( (15, 8),(17.95, 32) ) )
|
||||
self.failUnless(B.Overlaps(C) )
|
||||
|
||||
def testCorner(self):
|
||||
B = BBox( ( (5, 10),(15, 25) ) )
|
||||
C = BBox( ( (15, 25),(17.95, 32) ) )
|
||||
self.failUnless(B.Overlaps(C) )
|
||||
|
||||
def testZeroSize(self):
|
||||
B = BBox( ( (5, 10),(15, 25) ) )
|
||||
C = BBox( ( (15, 25),(15, 25) ) )
|
||||
self.failUnless(B.Overlaps(C) )
|
||||
|
||||
def testZeroSize2(self):
|
||||
B = BBox( ( (5, 10),(5, 10) ) )
|
||||
C = BBox( ( (15, 25),(15, 25) ) )
|
||||
self.failIf(B.Overlaps(C) )
|
||||
|
||||
def testZeroSize3(self):
|
||||
B = BBox( ( (5, 10),(5, 10) ) )
|
||||
C = BBox( ( (0, 8),(10, 12) ) )
|
||||
self.failUnless(B.Overlaps(C) )
|
||||
|
||||
def testZeroSize4(self):
|
||||
B = BBox( ( (5, 1),(10, 25) ) )
|
||||
C = BBox( ( (8, 8),(8, 8) ) )
|
||||
self.failUnless(B.Overlaps(C) )
|
||||
|
||||
|
||||
|
||||
class testEquality(unittest.TestCase):
|
||||
def testSame(self):
|
||||
B = BBox( ( (1.0, 2.0), (5.0, 10.0) ) )
|
||||
C = BBox( ( (1.0, 2.0), (5.0, 10.0) ) )
|
||||
self.failUnless(B == C)
|
||||
|
||||
def testIdentical(self):
|
||||
B = BBox( ( (1.0, 2.0), (5.0, 10.0) ) )
|
||||
self.failUnless(B == B)
|
||||
|
||||
def testNotSame(self):
|
||||
B = BBox( ( (1.0, 2.0), (5.0, 10.0) ) )
|
||||
C = BBox( ( (1.0, 2.0), (5.0, 10.1) ) )
|
||||
self.failIf(B == C)
|
||||
|
||||
def testWithArray(self):
|
||||
B = BBox( ( (1.0, 2.0), (5.0, 10.0) ) )
|
||||
C = N.array( ( (1.0, 2.0), (5.0, 10.0) ) )
|
||||
self.failUnless(B == C)
|
||||
|
||||
def testWithArray2(self):
|
||||
B = BBox( ( (1.0, 2.0), (5.0, 10.0) ) )
|
||||
C = N.array( ( (1.0, 2.0), (5.0, 10.0) ) )
|
||||
self.failUnless(C == B)
|
||||
|
||||
def testWithArray2(self):
|
||||
B = BBox( ( (1.0, 2.0), (5.0, 10.0) ) )
|
||||
C = N.array( ( (1.01, 2.0), (5.0, 10.0) ) )
|
||||
self.failIf(C == B)
|
||||
|
||||
class testInside(unittest.TestCase):
|
||||
def testSame(self):
|
||||
B = BBox( ( (1.0, 2.0), (5.0, 10.0) ) )
|
||||
C = BBox( ( (1.0, 2.0), (5.0, 10.0) ) )
|
||||
self.failUnless(B.Inside(C))
|
||||
|
||||
def testPoint(self):
|
||||
B = BBox( ( (1.0, 2.0), (5.0, 10.0) ) )
|
||||
C = BBox( ( (3.0, 4.0), (3.0, 4.0) ) )
|
||||
self.failUnless(B.Inside(C))
|
||||
|
||||
def testPointOutside(self):
|
||||
B = BBox( ( (1.0, 2.0), (5.0, 10.0) ) )
|
||||
C = BBox( ( (-3.0, 4.0), (0.10, 4.0) ) )
|
||||
self.failIf(B.Inside(C))
|
||||
|
||||
def testUpperLeft(self):
|
||||
B = BBox( ( (5, 10),(15, 25) ) )
|
||||
C = BBox( ( (0, 12),(10, 32.0) ) )
|
||||
self.failIf(B.Inside(C) )
|
||||
|
||||
def testUpperRight(self):
|
||||
B = BBox( ( (5, 10),(15, 25) ) )
|
||||
C = BBox( ( (12, 12),(25, 32.0) ) )
|
||||
self.failIf(B.Inside(C) )
|
||||
|
||||
def testLowerRight(self):
|
||||
B = BBox( ( (5, 10),(15, 25) ) )
|
||||
C = BBox( ( (12, 5),(25, 15) ) )
|
||||
self.failIf(B.Inside(C) )
|
||||
|
||||
def testLowerLeft(self):
|
||||
B = BBox( ( (5, 10),(15, 25) ) )
|
||||
C = BBox( ( (-10, 5),(8.5, 15) ) )
|
||||
self.failIf(B.Inside(C) )
|
||||
|
||||
def testBelow(self):
|
||||
B = BBox( ( (5, 10),(15, 25) ) )
|
||||
C = BBox( ( (-10, 5),(8.5, 9.2) ) )
|
||||
self.failIf(B.Inside(C) )
|
||||
|
||||
def testAbove(self):
|
||||
B = BBox( ( (5, 10),(15, 25) ) )
|
||||
C = BBox( ( (-10, 25.001),(8.5, 32) ) )
|
||||
self.failIf(B.Inside(C) )
|
||||
|
||||
def testLeft(self):
|
||||
B = BBox( ( (5, 10),(15, 25) ) )
|
||||
C = BBox( ( (4, 8),(4.95, 32) ) )
|
||||
self.failIf(B.Inside(C) )
|
||||
|
||||
def testRight(self):
|
||||
B = BBox( ( (5, 10),(15, 25) ) )
|
||||
C = BBox( ( (17.1, 8),(17.95, 32) ) )
|
||||
self.failIf(B.Inside(C) )
|
||||
|
||||
class testFromPoints(unittest.TestCase):
|
||||
|
||||
def testCreate(self):
|
||||
Pts = N.array( ((5,2),
|
||||
(3,4),
|
||||
(1,6),
|
||||
), N.float_ )
|
||||
B = fromPoints(Pts)
|
||||
#B = BBox( ( (1.0, 2.0), (5.0, 10.0) ) )
|
||||
self.failUnless(B[0,0] == 1.0 and
|
||||
B[0,1] == 2.0 and
|
||||
B[1,0] == 5.0 and
|
||||
B[1,1] == 6.0
|
||||
)
|
||||
def testCreateInts(self):
|
||||
Pts = N.array( ((5,2),
|
||||
(3,4),
|
||||
(1,6),
|
||||
) )
|
||||
B = fromPoints(Pts)
|
||||
self.failUnless(B[0,0] == 1.0 and
|
||||
B[0,1] == 2.0 and
|
||||
B[1,0] == 5.0 and
|
||||
B[1,1] == 6.0
|
||||
)
|
||||
|
||||
def testSinglePoint(self):
|
||||
Pts = N.array( (5,2), N.float_ )
|
||||
B = fromPoints(Pts)
|
||||
self.failUnless(B[0,0] == 5.0 and
|
||||
B[0,1] == 2.0 and
|
||||
B[1,0] == 5.0 and
|
||||
B[1,1] == 2.0
|
||||
)
|
||||
|
||||
def testListTuples(self):
|
||||
Pts = [ (3, 6.5),
|
||||
(13, 43.2),
|
||||
(-4.32, -4),
|
||||
(65, -23),
|
||||
(-0.0001, 23.432),
|
||||
]
|
||||
B = fromPoints(Pts)
|
||||
self.failUnless(B[0,0] == -4.32 and
|
||||
B[0,1] == -23.0 and
|
||||
B[1,0] == 65.0 and
|
||||
B[1,1] == 43.2
|
||||
)
|
||||
class testMerge(unittest.TestCase):
|
||||
A = BBox( ((-23.5, 456), (56, 532.0)) )
|
||||
B = BBox( ((-20.3, 460), (54, 465 )) )# B should be completely inside A
|
||||
C = BBox( ((-23.5, 456), (58, 540.0)) )# up and to the right or A
|
||||
D = BBox( ((-26.5, 12), (56, 532.0)) )
|
||||
|
||||
def testInside(self):
|
||||
C = self.A.copy()
|
||||
C.Merge(self.B)
|
||||
self.failUnless(C == self.A)
|
||||
|
||||
def testFullOutside(self):
|
||||
C = self.B.copy()
|
||||
C.Merge(self.A)
|
||||
self.failUnless(C == self.A)
|
||||
|
||||
def testUpRight(self):
|
||||
A = self.A.copy()
|
||||
A.Merge(self.C)
|
||||
self.failUnless(A[0] == self.A[0] and A[1] == self.C[1])
|
||||
|
||||
def testDownLeft(self):
|
||||
A = self.A.copy()
|
||||
A.Merge(self.D)
|
||||
self.failUnless(A[0] == self.D[0] and A[1] == self.A[1])
|
||||
|
||||
class testBBarray(unittest.TestCase):
|
||||
BBarray = N.array( ( ((-23.5, 456), (56, 532.0)),
|
||||
((-20.3, 460), (54, 465 )),
|
||||
((-23.5, 456), (58, 540.0)),
|
||||
((-26.5, 12), (56, 532.0)),
|
||||
),
|
||||
dtype=N.float)
|
||||
print BBarray
|
||||
BB = asBBox( ((-26.5, 12.), ( 58. , 540.)) )
|
||||
|
||||
def testJoin(self):
|
||||
BB = fromBBArray(self.BBarray)
|
||||
self.failUnless(BB == self.BB, "Wrong BB was created. It was:\n%s \nit should have been:\n%s"%(BB, self.BB))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
115
wxPython/wx/lib/floatcanvas/Utilities/GUI.py
Normal file
115
wxPython/wx/lib/floatcanvas/Utilities/GUI.py
Normal file
@@ -0,0 +1,115 @@
|
||||
"""
|
||||
|
||||
Part of the floatcanvas.Utilities package.
|
||||
|
||||
This module contains assorted GUI-related utilities that can be used
|
||||
with FloatCanvas
|
||||
|
||||
So far, they are:
|
||||
|
||||
RubberBandBox: used to draw a RubberBand Box on the screen
|
||||
|
||||
"""
|
||||
import wx
|
||||
from floatcanvas import FloatCanvas
|
||||
|
||||
class RubberBandBox:
|
||||
"""
|
||||
Class to provide a rubber band box that can be drawn on a Window
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, Canvas, CallBack, Tol=5):
|
||||
|
||||
"""
|
||||
To initialize:
|
||||
|
||||
RubberBandBox(Canvas, CallBack)
|
||||
|
||||
Canvas: the FloatCanvas you want the Rubber band box to be used on
|
||||
|
||||
CallBack: is the method you want called when the mouse is
|
||||
released. That method will be called, passing in a rect
|
||||
parameter, where rect is: (Point, WH) of the rect in
|
||||
world coords.
|
||||
|
||||
Tol: The tolerance for the smallest rectangle allowed. defaults
|
||||
to 5. In pixels
|
||||
|
||||
Methods:
|
||||
|
||||
Enable() : Enables the Rubber Band Box (Binds the events)
|
||||
|
||||
Disable() : Enables the Rubber Band Box (Unbinds the events)
|
||||
|
||||
Attributes:
|
||||
|
||||
CallBack: The callback function, if it's replaced you need to
|
||||
call Enable() again.
|
||||
|
||||
"""
|
||||
|
||||
self.Canvas = Canvas
|
||||
self.CallBack = CallBack
|
||||
self.Tol = Tol
|
||||
|
||||
self.Drawing = False
|
||||
self.RBRect = None
|
||||
self.StartPointWorld = None
|
||||
|
||||
return None
|
||||
|
||||
def Enable(self):
|
||||
"""
|
||||
Called when you want the rubber band box to be enabled
|
||||
|
||||
"""
|
||||
|
||||
# bind events:
|
||||
self.Canvas.Bind(FloatCanvas.EVT_MOTION, self.OnMove )
|
||||
self.Canvas.Bind(FloatCanvas.EVT_LEFT_DOWN, self.OnLeftDown)
|
||||
self.Canvas.Bind(FloatCanvas.EVT_LEFT_UP, self.OnLeftUp )
|
||||
|
||||
def Disable(self):
|
||||
"""
|
||||
Called when you don't want the rubber band box to be enabled
|
||||
|
||||
"""
|
||||
|
||||
# unbind events:
|
||||
self.Canvas.Unbind(FloatCanvas.EVT_MOTION)
|
||||
self.Canvas.Unbind(FloatCanvas.EVT_LEFT_DOWN)
|
||||
self.Canvas.Unbind(FloatCanvas.EVT_LEFT_UP)
|
||||
|
||||
def OnMove(self, event):
|
||||
if self.Drawing:
|
||||
x, y = self.StartPoint
|
||||
Cornerx, Cornery = event.GetPosition()
|
||||
w, h = ( Cornerx - x, Cornery - y)
|
||||
if abs(w) > self.Tol and abs(h) > self.Tol:
|
||||
# draw the RB box
|
||||
dc = wx.ClientDC(self.Canvas)
|
||||
dc.SetPen(wx.Pen('WHITE', 2, wx.SHORT_DASH))
|
||||
dc.SetBrush(wx.TRANSPARENT_BRUSH)
|
||||
dc.SetLogicalFunction(wx.XOR)
|
||||
if self.RBRect:
|
||||
dc.DrawRectangle(*self.RBRect)
|
||||
self.RBRect = (x, y, w, h )
|
||||
dc.DrawRectangle(*self.RBRect)
|
||||
event.Skip() # skip so that other events can catch these
|
||||
|
||||
def OnLeftDown(self, event):
|
||||
# Start drawing
|
||||
self.Drawing = True
|
||||
self.StartPoint = event.GetPosition()
|
||||
self.StartPointWorld = event.Coords
|
||||
|
||||
def OnLeftUp(self, event):
|
||||
# Stop Drawing
|
||||
if self.Drawing:
|
||||
self.Drawing = False
|
||||
if self.RBRect:
|
||||
WH = event.Coords - self.StartPointWorld
|
||||
wx.CallAfter(self.CallBack, (self.StartPointWorld, WH))
|
||||
self.RBRect = None
|
||||
self.StartPointWorld = None
|
7
wxPython/wx/lib/floatcanvas/Utilities/__init__.py
Normal file
7
wxPython/wx/lib/floatcanvas/Utilities/__init__.py
Normal file
@@ -0,0 +1,7 @@
|
||||
"""
|
||||
__init__ for the floatcanvas Utilities package
|
||||
|
||||
"""
|
||||
pass
|
||||
|
||||
|
Reference in New Issue
Block a user