Some last minue wxPython changes

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/branches/WX_2_4_BRANCH@17219 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Robin Dunn
2002-09-17 00:27:21 +00:00
parent d2da899a2e
commit e3bd1146c7
10 changed files with 422 additions and 10 deletions

View File

@@ -174,6 +174,9 @@ Added wxXmlResourceHandler which allows you to create custom handlers
for nonstandard class types in XRC resources. See the demo for an for nonstandard class types in XRC resources. See the demo for an
example. example.
Added wxPython.lib.mixins.rubberband module from Robb Shecter.

View File

@@ -3,5 +3,5 @@
wx.wxStyledTextEventPtr = wxStyledTextEventPtr wx.wxStyledTextEventPtr = wxStyledTextEventPtr
wx.wxStyledTextCtrlPtr = wxStyledTextCtrlPtr wx.wxStyledTextCtrlPtr = wxStyledTextCtrlPtr
# This constant no longer exists in Scintilla, but I'll put it here for a while to avoid disrupting user code...
wxSTC_CARET_CENTER = wxSTC_CARET_STRICT wxSTC_CARET_CENTER = 0

View File

@@ -1819,5 +1819,5 @@ wxEVT_STC_ZOOM = stc_c.wxEVT_STC_ZOOM
wx.wxStyledTextEventPtr = wxStyledTextEventPtr wx.wxStyledTextEventPtr = wxStyledTextEventPtr
wx.wxStyledTextCtrlPtr = wxStyledTextCtrlPtr wx.wxStyledTextCtrlPtr = wxStyledTextCtrlPtr
# This constant no longer exists in Scintilla, but I'll put it here for a while to avoid disrupting user code...
wxSTC_CARET_CENTER = wxSTC_CARET_STRICT wxSTC_CARET_CENTER = 0

View File

@@ -45,7 +45,10 @@ class CustomDataTable(wxPyGridTableBase):
return len(self.data[0]) return len(self.data[0])
def IsEmptyCell(self, row, col): def IsEmptyCell(self, row, col):
return not self.data[row][col] try:
return not self.data[row][col]
except IndexError:
return true
# Get/Set values in the table. The Python version of these # Get/Set values in the table. The Python version of these
# methods can handle any data-type, (as long as the Editor and # methods can handle any data-type, (as long as the Editor and
@@ -138,8 +141,22 @@ class CustTableGrid(wxGrid):
class TestFrame(wxFrame): class TestFrame(wxFrame):
def __init__(self, parent, log): def __init__(self, parent, log):
wxFrame.__init__(self, parent, -1, "Custom Table, data driven Grid Demo", size=(640,480)) wxFrame.__init__(self, parent, -1, "Custom Table, data driven Grid Demo", size=(640,480))
grid = CustTableGrid(self, log) p = wxPanel(self, -1, style=0)
grid = CustTableGrid(p, log)
b = wxButton(p, -1, "Another Control...")
b.SetDefault()
EVT_BUTTON(self, b.GetId(), self.OnButton)
EVT_SET_FOCUS(b, self.OnButtonFocus)
bs = wxBoxSizer(wxVERTICAL)
bs.Add(grid, 1, wxGROW|wxALL, 5)
bs.Add(b)
p.SetSizer(bs)
def OnButton(self, evt):
print "button selected"
def OnButtonFocus(self, evt):
print "button focus"
#--------------------------------------------------------------------------- #---------------------------------------------------------------------------

View File

@@ -223,7 +223,8 @@ class TestListCtrlPanel(wxPanel, wxColumnSorterMixin):
def OnItemActivated(self, event): def OnItemActivated(self, event):
self.currentItem = event.m_itemIndex self.currentItem = event.m_itemIndex
self.log.WriteText("OnItemActivated: %s\n" % self.list.GetItemText(self.currentItem)) self.log.WriteText("OnItemActivated: %s\nTopItem: %s" %
(self.list.GetItemText(self.currentItem), self.list.GetTopItem()))
def OnItemDelete(self, event): def OnItemDelete(self, event):
self.log.WriteText("OnItemDelete\n") self.log.WriteText("OnItemDelete\n")

View File

@@ -45,7 +45,8 @@ class TestVirtualList(wxListCtrl):
def OnItemActivated(self, event): def OnItemActivated(self, event):
self.currentItem = event.m_itemIndex self.currentItem = event.m_itemIndex
self.log.WriteText("OnItemActivated: %s\n" % self.GetItemText(self.currentItem)) self.log.WriteText("OnItemActivated: %s\nTopItem: %s\n" %
(self.GetItemText(self.currentItem), self.GetTopItem()))
def getColumnText(self, index, col): def getColumnText(self, index, col):
item = self.GetItem(index, col) item = self.GetItem(index, col)

View File

@@ -149,6 +149,7 @@ class MyCanvas(wxScrolledWindow):
def OnLeftButtonEvent(self, event): def OnLeftButtonEvent(self, event):
if event.LeftDown(): if event.LeftDown():
self.SetFocus()
self.SetXY(event) self.SetXY(event)
self.curLine = [] self.curLine = []
self.CaptureMouse() self.CaptureMouse()

View File

@@ -13,7 +13,7 @@ from my_distutils import run_swig, contrib_copy_tree
# flags and values that affect this script # flags and values that affect this script
#---------------------------------------------------------------------- #----------------------------------------------------------------------
VERSION = "2.3.3pre8" VERSION = "2.3.3"
DESCRIPTION = "Cross platform GUI toolkit for Python" DESCRIPTION = "Cross platform GUI toolkit for Python"
AUTHOR = "Robin Dunn" AUTHOR = "Robin Dunn"
AUTHOR_EMAIL = "Robin Dunn <robin@alldunn.com>" AUTHOR_EMAIL = "Robin Dunn <robin@alldunn.com>"

View File

@@ -1 +1 @@
ver = '2.3.3pre8' ver = '2.3.3'

View File

@@ -0,0 +1,389 @@
"""
A mixin class for doing "RubberBand"-ing on a window.
by "Robb Shecter" <rs@onsitetech.com>
$Id$
"""
from wxPython.wx import *
import Image
#
# Some miscellaneous mathematical and geometrical functions
#
def isNegative(aNumber):
"""
x < 0: 1
else: 0
"""
return aNumber < 0
def normalizeBox(box):
"""
Convert any negative measurements in the current
box to positive, and adjust the origin.
"""
x, y, w, h = box
if w < 0:
x += (w+1)
w *= -1
if h < 0:
y += (h+1)
h *= -1
return (x, y, w, h)
def boxToExtent(box):
"""
Convert a box specification to an extent specification.
I put this into a seperate function after I realized that
I had been implementing it wrong in several places.
"""
b = normalizeBox(box)
return (b[0], b[1], b[0]+b[2]-1, b[1]+b[3]-1)
def pointInBox(x, y, box):
"""
Return true if the given point is contained in the box.
"""
e = boxToExtent(box)
return x >= e[0] and x <= e[2] and y >= e[1] and y <= e[3]
def pointOnBox(x, y, box, thickness=1):
"""
Return true if the point is on the outside edge
of the box. The thickness defines how thick the
edge should be. This is necessary for HCI reasons:
For example, it's normally very difficult for a user
to manuever the mouse onto a one pixel border.
"""
outerBox = box
innerBox = (box[0]+thickness, box[1]+thickness, box[2]-(thickness*2), box[3]-(thickness*2))
return pointInBox(x, y, outerBox) and not pointInBox(x, y, innerBox)
def getCursorPosition(x, y, box, thickness=1):
"""
Return a position number in the range 0 .. 7 to indicate
where on the box border the point is. The layout is:
0 1 2
7 3
6 5 4
"""
x0, y0, x1, y1 = boxToExtent(box)
w, h = box[2], box[3]
delta = thickness - 1
p = None
if pointInBox(x, y, (x0, y0, thickness, thickness)):
p = 0
elif pointInBox(x, y, (x1-delta, y0, thickness, thickness)):
p = 2
elif pointInBox(x, y, (x1-delta, y1-delta, thickness, thickness)):
p = 4
elif pointInBox(x, y, (x0, y1-delta, thickness, thickness)):
p = 6
elif pointInBox(x, y, (x0+thickness, y0, w-(thickness*2), thickness)):
p = 1
elif pointInBox(x, y, (x1-delta, y0+thickness, thickness, h-(thickness*2))):
p = 3
elif pointInBox(x, y, (x0+thickness, y1-delta, w-(thickness*2), thickness)):
p = 5
elif pointInBox(x, y, (x0, y0+thickness, thickness, h-(thickness*2))):
p = 7
return p
class RubberBand:
"""
A stretchable border which is drawn on top of an
image to define an area.
"""
def __init__(self, drawingSurface, aspectRatio=None):
self.__THICKNESS = 5
self.drawingSurface = drawingSurface
self.aspectRatio = aspectRatio
self.hasLetUp = 0
self.currentlyMoving = None
self.currentBox = None
self.__enabled = 1
self.__currentCursor = None
EVT_MOUSE_EVENTS(drawingSurface, self.__handleMouseEvents)
EVT_PAINT(drawingSurface, self.__handleOnPaint)
def __setEnabled(self, enabled):
self.__enabled = enabled
def __isEnabled(self):
return self.__enabled
def __handleOnPaint(self, event):
#print 'paint'
event.Skip()
def __isMovingCursor(self):
"""
Return true if the current cursor is one used to
mean moving the rubberband.
"""
return self.__currentCursor == wxCURSOR_HAND
def __isSizingCursor(self):
"""
Return true if the current cursor is one of the ones
I may use to signify sizing.
"""
sizingCursors = [wxCURSOR_SIZENESW,
wxCURSOR_SIZENS,
wxCURSOR_SIZENWSE,
wxCURSOR_SIZEWE,
wxCURSOR_SIZING,
wxCURSOR_CROSS]
try:
sizingCursors.index(self.__currentCursor)
return 1
except ValueError:
return 0
def __handleMouseEvents(self, event):
"""
React according to the new event. This is the main
entry point into the class. This method contains the
logic for the class's behavior.
"""
if not self.enabled:
return
x, y = event.GetPosition()
# First make sure we have started a box.
if self.currentBox == None and not event.LeftDown():
# No box started yet. Set cursor to the initial kind.
self.__setCursor(wxCURSOR_CROSS)
return
if event.LeftDown():
if self.currentBox == None:
# No RB Box, so start a new one.
self.currentBox = (x, y, 0, 0)
self.hasLetUp = 0
elif self.__isSizingCursor():
# Starting a sizing operation. Change the origin.
position = getCursorPosition(x, y, self.currentBox, thickness=self.__THICKNESS)
self.currentBox = self.__denormalizeBox(position, self.currentBox)
elif event.Dragging() and event.LeftIsDown():
# Use the cursor type to determine operation
if self.__isMovingCursor():
if self.currentlyMoving or pointInBox(x, y, self.currentBox):
if not self.currentlyMoving:
self.currentlyMoving = (x - self.currentBox[0], y - self.currentBox[1])
self.__moveTo(x - self.currentlyMoving[0], y - self.currentlyMoving[1])
elif self.__isSizingCursor():
self.__resizeBox(x, y)
elif event.LeftUp():
self.hasLetUp = 1
self.currentlyMoving = None
self.__normalizeBox()
elif event.Moving() and not event.Dragging():
# Simple mouse movement event
self.__mouseMoved(x,y)
def __denormalizeBox(self, position, box):
x, y, w, h = box
b = box
if position == 2 or position == 3:
b = (x, y + (h-1), w, h * -1)
elif position == 0 or position == 1 or position == 7:
b = (x + (w-1), y + (h-1), w * -1, h * -1)
elif position == 6:
b = (x + (w-1), y, w * -1, h)
return b
def __resizeBox(self, x, y):
"""
Resize and repaint the box based on the given mouse
coordinates.
"""
# Implement the correct behavior for dragging a side
# of the box: Only change one dimension.
if not self.aspectRatio:
if self.__currentCursor == wxCURSOR_SIZENS:
x = None
elif self.__currentCursor == wxCURSOR_SIZEWE:
y = None
x0,y0,w0,h0 = self.currentBox
currentExtent = boxToExtent(self.currentBox)
if x == None:
if w0 < 1:
w0 += 1
else:
w0 -= 1
x = x0 + w0
if y == None:
if h0 < 1:
h0 += 1
else:
h0 -= 1
y = y0 + h0
x1,y1 = x, y
w, h = abs(x1-x0)+1, abs(y1-y0)+1
if self.aspectRatio:
w = max(w, int(h * self.aspectRatio))
h = int(w / self.aspectRatio)
w *= [1,-1][isNegative(x1-x0)]
h *= [1,-1][isNegative(y1-y0)]
newbox = (x0, y0, w, h)
self.__drawAndErase(boxToDraw=normalizeBox(newbox), boxToErase=normalizeBox(self.currentBox))
self.currentBox = (x0, y0, w, h)
def __normalizeBox(self):
"""
Convert any negative measurements in the current
box to positive, and adjust the origin.
"""
self.currentBox = normalizeBox(self.currentBox)
def __mouseMoved(self, x, y):
"""
Called when the mouse moved without any buttons pressed
or dragging being done.
"""
# Are we on the bounding box?
if pointOnBox(x, y, self.currentBox, thickness=self.__THICKNESS):
position = getCursorPosition(x, y, self.currentBox, thickness=self.__THICKNESS)
cursor = [
wxCURSOR_SIZENWSE,
wxCURSOR_SIZENS,
wxCURSOR_SIZENESW,
wxCURSOR_SIZEWE,
wxCURSOR_SIZENWSE,
wxCURSOR_SIZENS,
wxCURSOR_SIZENESW,
wxCURSOR_SIZEWE
] [position]
self.__setCursor(cursor)
elif pointInBox(x, y, self.currentBox):
self.__setCursor(wxCURSOR_HAND)
else:
self.__setCursor()
def __setCursor(self, id=None):
"""
Set the mouse cursor to the given id.
"""
if self.__currentCursor != id: # Avoid redundant calls
if id:
self.drawingSurface.SetCursor(wxStockCursor(id))
else:
self.drawingSurface.SetCursor(wxNullCursor)
self.__currentCursor = id
def __moveCenterTo(self, x, y):
"""
Move the rubber band so that its center is at (x,y).
"""
x0, y0, w, h = self.currentBox
x2, y2 = x - (w/2), y - (h/2)
self.__moveTo(x2, y2)
def __moveTo(self, x, y):
"""
Move the rubber band so that its origin is at (x,y).
"""
newbox = (x, y, self.currentBox[2], self.currentBox[3])
self.__drawAndErase(boxToDraw=newbox, boxToErase=self.currentBox)
self.currentBox = newbox
def __drawAndErase(self, boxToDraw, boxToErase=None):
"""
Draw one box shape and possibly erase another.
"""
dc = wxClientDC(self.drawingSurface)
dc.BeginDrawing()
dc.SetPen(wxPen(wxWHITE, 1, wxDOT))
dc.SetBrush(wxTRANSPARENT_BRUSH)
dc.SetLogicalFunction(wxXOR)
if boxToErase:
dc.DrawRectangle(*boxToErase)
dc.DrawRectangle(*boxToDraw)
dc.EndDrawing()
def __dumpMouseEvent(self, event):
print 'Moving: ',event.Moving()
print 'Dragging: ',event.Dragging()
print 'LeftDown: ',event.LeftDown()
print 'LeftisDown: ',event.LeftIsDown()
print 'LeftUp: ',event.LeftUp()
print 'Position: ',event.GetPosition()
print 'x,y: ',event.GetX(),event.GetY()
print
#
# The public API:
#
def reset(self, aspectRatio=None):
"""
Clear the existing rubberband
"""
self.currentBox = None
self.aspectRatio = aspectRatio
self.drawingSurface.Refresh()
def getCurrentExtent(self):
"""
Return (x0, y0, x1, y1) or None if
no drawing has yet been done.
"""
if not self.currentBox:
extent = None
else:
extent = boxToExtent(self.currentBox)
return extent
enabled = property(__isEnabled, __setEnabled, None, 'True if I am responding to mouse events')
if __name__ == '__main__':
app = wxPySimpleApp()
frame = wxFrame(None, -1, title='RubberBand Test', size=(300,300))
# Add a panel that the rubberband will work on.
panel = wxPanel(frame, -1)
panel.SetBackgroundColour(wxBLUE)
# Create the rubberband
frame.rubberBand = RubberBand(drawingSurface=panel)
frame.rubberBand.reset(aspectRatio=0.5)
# Add a button that creates a new rubberband
def __newRubberBand(event):
frame.rubberBand.reset()
button = wxButton(frame, 100, 'Reset Rubberband')
EVT_BUTTON(frame, 100, __newRubberBand)
# Layout the frame
sizer = wxBoxSizer(wxVERTICAL)
sizer.Add(panel, 1, wxEXPAND | wxALL, 5)
sizer.Add(button, 0, wxALIGN_CENTER | wxALL, 5)
frame.SetAutoLayout(1)
frame.SetSizer(sizer)
frame.Show(1)
app.MainLoop()