Copied/merged from the 2.2 branch.

Changes needed to build with new event system


git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@9374 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Robin Dunn
2001-02-16 08:19:50 +00:00
parent 7aa54cf749
commit 1b62f00d8e
87 changed files with 1968 additions and 733 deletions

View File

@@ -0,0 +1,91 @@
#----------------------------------------------------------------------
# Name: wxPython.lib.anchors
# Purpose: A class that provides an easy to use interface over layout
# constraints for anchored layout.
#
# Author: Riaan Booysen
#
# Created: 15-Dec-2000
# RCS-ID: $Id$
# Copyright: (c) 2000 by Total Control Software
# Licence: wxWindows license
#----------------------------------------------------------------------
from wxPython.wx import wxLayoutConstraints, wxTop, wxLeft, wxBottom, wxRight, \
wxHeight, wxWidth
class LayoutAnchors(wxLayoutConstraints):
""" A class that implements Delphi's Anchors with wxLayoutConstraints.
Anchored sides maintain the distance from the edge of the
control to the same edge of the parent.
When neither side is selected, the control keeps the same
relative position to both sides.
The current position and size of the control and it's parent
is used when setting up the constraints. To change the size or
position of an already anchored control, set the constraints to
None, reposition or resize and reapply the anchors.
Examples:
Let's anchor the right and bottom edge of a control and
resize it's parent.
ctrl.SetConstraints(LayoutAnchors(ctrl, left=0, top=0, right=1, bottom=1))
+=========+ +===================+
| +-----+ | | |
| | * | -> | |
| +--*--+ | | +-----+ |
+---------+ | | * |
| +--*--+ |
+-------------------+
* = anchored edge
When anchored on both sides the control will stretch horizontally.
ctrl.SetConstraints(LayoutAnchors(ctrl, 1, 0, 1, 1))
+=========+ +===================+
| +-----+ | | |
| * * | -> | |
| +--*--+ | | +---------------+ |
+---------+ | * ctrl * |
| +-------*-------+ |
+-------------------+
* = anchored edge
"""
def __init__(self, control, left = 1, top = 1, right = 0, bottom = 0):
wxLayoutConstraints.__init__(self)
parent = control.GetParent()
if not parent: return
pPos, pSize = parent.GetPosition(), parent.GetClientSize()
cPos, cSize = control.GetPosition(), control.GetSize()
self.setConstraintSides(self.left, wxLeft, left,
self.right, wxRight, right,
self.width, wxWidth, self.centreX,
cPos.x, cSize.x, pSize.x, parent)
self.setConstraintSides(self.top, wxTop, top,
self.bottom, wxBottom, bottom,
self.height, wxHeight, self.centreY,
cPos.y, cSize.y, pSize.y, parent)
def setConstraintSides(self, side1, side1Edge, side1Anchor,
side2, side2Edge, side2Anchor,
size, sizeEdge, centre,
cPos, cSize, pSize, parent):
if side2Anchor:
side2.SameAs(parent, side2Edge, pSize - (cPos + cSize))
if side1Anchor:
side1.SameAs(parent, side1Edge, cPos)
if not side2Anchor:
size.AsIs()
else:
size.AsIs()
if not side2Anchor:
centre.PercentOf(parent, sizeEdge,
int(((cPos + cSize / 2.0) / pSize)*100))

View File

@@ -67,6 +67,7 @@ class wxGenButton(wxControl):
self.bezelWidth = 2
self.hasFocus = false
self.useFocusInd = true
self.evtToSend = []
self.SetLabel(label)
self.SetPosition(pos)
@@ -86,6 +87,7 @@ class wxGenButton(wxControl):
EVT_KEY_UP(self, self.OnKeyUp)
EVT_ERASE_BACKGROUND(self, self.OnEraseBackground)
EVT_PAINT(self, self.OnPaint)
EVT_IDLE(self, self.OnIdle)
def SetBestSize(self, size=None):
@@ -174,7 +176,14 @@ class wxGenButton(wxControl):
evt = wxGenButtonEvent(wxEVT_COMMAND_BUTTON_CLICKED, self.GetId())
evt.SetIsDown(not self.up)
evt.SetButtonObj(self)
self.GetEventHandler().ProcessEvent(evt)
self.evtToSend.append(evt)
def OnIdle(self, evt):
while self.evtToSend:
evt = self.evtToSend[0]
del self.evtToSend[0]
self.GetEventHandler().ProcessEvent(evt)
def DrawBezel(self, dc, x1, y1, x2, y2):

View File

@@ -0,0 +1,249 @@
"""wxFancyText -- methods for rendering XML specified text
This module has four main methods:
def getExtent(str, dc=None, enclose=1):
def renderToBitmap(str, background=None, enclose=1)
def renderToDC(str, dc, x, y, enclose=1)
In all cases, 'str' is an XML string. The tags in the string can
currently specify the font, subscripts, superscripts, and the angle
sign. The allowable properties of font are size, family, style, weght,
encoding, and color. See the example on the bottom for a better idea
of how this works.
Note that start and end tags for the string are provided if enclose is
true, so for instance, renderToBitmap("X<sub>1</sub>") will work.
"""
# Copyright 2001 Timothy Hochberg
# Use as you see fit. No warantees, I cannot be held responsible, etc.
# TODO: Make a wxFancyTextCtrl class that derives from wxControl.
# Add support for line breaks
# etc.
# - Robin
from wxPython.wx import *
import xml.parsers.expat, copy
_families = {"default" : wxDEFAULT, "decorative" : wxDECORATIVE, "roman" : wxROMAN,
"swiss" : wxSWISS, "modern" : wxMODERN}
_styles = {"normal" : wxNORMAL, "slant" : wxSLANT, "italic" : wxITALIC}
_weights = {"normal" : wxNORMAL, "light" : wxLIGHT, "bold" : wxBOLD}
# The next three classes: Renderer, SizeRenderer and DCRenderer are
# what you will need to override to extend the XML language. All of
# the font stuff as well as the subscript and superscript stuff are in
# Renderer.
class Renderer:
defaultSize = wxNORMAL_FONT.GetPointSize()
defaultFamily = wxDEFAULT
defaultStyle = wxNORMAL
defaultWeight = wxNORMAL
defaultEncoding = wxFont_GetDefaultEncoding()
defaultColor = "black"
def __init__(self, dc=None):
if dc == None:
dc = wxMemoryDC()
self.dc = dc
self.offsets = [0]
self.fonts = [{}]
def startElement(self, name, attrs):
method = "start_" + name
if not hasattr(self, method):
raise ValueError("XML tag '%s' not supported" % name)
getattr(self, method)(attrs)
def endElement(self, name):
method = "end_" + name
if not hasattr(self, method):
raise ValueError("XML tag '%s' not supported" % name)
getattr(self, method)()
def start_wxFancyString(self, attrs):
pass
def end_wxFancyString(self):
pass
def start_font(self, attrs):
for key, value in attrs.items():
if key == "size":
value = int(value)
elif key == "family":
value = _families[value]
elif key == "style":
value = _styles[value]
elif key == "weight":
value = _weights[value]
elif key == "encoding":
pass
elif key == "color":
pass
else:
raise ValueError("unknown font attribute '%s'" % key)
attrs[key] = value
font = copy.copy(self.fonts[-1])
font.update(attrs)
self.fonts.append(font)
def end_font(self):
self.fonts.pop()
def start_sub(self, attrs):
if attrs.keys():
raise ValueError("<sub> does not take attributes")
font = self.getCurrentFont()
self.offsets.append(self.offsets[-1] + self.dc.GetFullTextExtent("M", font)[1]*0.5)
self.start_font({"size" : font.GetPointSize() * 0.8})
def end_sub(self):
self.fonts.pop()
self.offsets.pop()
def start_sup(self, attrs):
if attrs.keys():
raise ValueError("<sup> does not take attributes")
font = self.getCurrentFont()
self.offsets.append(self.offsets[-1] - self.dc.GetFullTextExtent("M", font)[1]*0.3)
self.start_font({"size" : font.GetPointSize() * 0.8})
def end_sup(self):
self.fonts.pop()
self.offsets.pop()
def getCurrentFont(self):
font = self.fonts[-1]
return wxFont(font.get("size", self.defaultSize),
font.get("family", self.defaultFamily),
font.get("style", self.defaultStyle),
font.get("weight", self.defaultWeight),
encoding = font.get("encoding", self.defaultEncoding))
def getCurrentColor(self):
font = self.fonts[-1]
return wxNamedColour(font.get("color", self.defaultColor))
class SizeRenderer(Renderer):
def __init__(self, dc=None):
Renderer.__init__(self, dc)
self.width = self.height = 0
self.minY = self.maxY = 0
def characterData(self, data):
self.dc.SetFont(self.getCurrentFont())
width, height = self.dc.GetTextExtent(data)
self.width = self.width + width
self.minY = min(self.minY, self.offsets[-1])
self.maxY = max(self.maxY, self.offsets[-1] + height)
self.height = self.maxY - self.minY
def start_angle(self, attrs):
self.characterData("M")
def end_angle(self):
pass
class DCRenderer(Renderer):
def __init__(self, dc=None, x=0, y=0):
Renderer.__init__(self, dc)
self.x = x
self.y = y
def characterData(self, data):
self.dc.SetFont(self.getCurrentFont())
self.dc.SetTextForeground(self.getCurrentColor())
width, height = self.dc.GetTextExtent(data)
self.dc.DrawText(data, self.x, self.y + self.offsets[-1])
self.x = self.x + width
def start_angle(self, attrs):
self.dc.SetFont(self.getCurrentFont())
self.dc.SetPen(wxPen(self.getCurrentColor(), 1))
width, height, descent, leading = self.dc.GetFullTextExtent("M")
y = self.y + self.offsets[-1] + height - descent
self.dc.DrawLine(self.x, y, self.x+width, y)
self.dc.DrawLine(self.x, y, self.x+width, y-width)
self.x = self.x + width
def end_angle(self):
pass
# This is a rendering function that is primarily used internally,
# although it could be used externally if one had overridden the
# Renderer classes.
def renderToRenderer(str, renderer, enclose=1):
if enclose:
str = '<?xml version="1.0"?><wxFancyString>%s</wxFancyString>' % str
p = xml.parsers.expat.ParserCreate()
p.returns_unicode = 0
p.StartElementHandler = renderer.startElement
p.EndElementHandler = renderer.endElement
p.CharacterDataHandler = renderer.characterData
p.Parse(str, 1)
def getExtent(str, dc=None, enclose=1):
"Return the extent of str"
renderer = SizeRenderer(dc)
renderToRenderer(str, renderer, enclose)
return wxSize(renderer.width, renderer.height)
# This should probably only be used internally....
def getFullExtent(str, dc=None, enclose=1):
renderer = SizeRenderer(dc)
renderToRenderer(str, renderer, enclose)
return renderer.width, renderer.height, -renderer.minY
def renderToBitmap(str, background=None, enclose=1):
"Return str rendered on a minumum size bitmap"
dc = wxMemoryDC()
width, height, dy = getFullExtent(str, dc)
bmp = wxEmptyBitmap(width, height)
dc.SelectObject(bmp)
if background is not None:
dc.SetBackground(background)
dc.Clear()
renderer = DCRenderer(dc, y=dy)
dc.BeginDrawing()
renderToRenderer(str, renderer, enclose)
dc.EndDrawing()
dc.SelectObject(wxNullBitmap)
return bmp
def renderToDC(str, dc, x, y, enclose=1):
"Render str onto a wxDC at (x,y)"
width, height, dy = getFullExtent(str, dc)
renderer = DCRenderer(dc, x, y+dy)
renderToRenderer(str, renderer, enclose)
if __name__ == "__main__":
str = ('<font style="italic" family="swiss" color="red" weight="bold" >some |<sup>23</sup> <angle/>text<sub>with <angle/> subscript</sub> </font> some other text'
'<font family="swiss" color="green" size="40">big green text</font>')
ID_EXIT = 102
class myApp(wxApp):
def OnInit(self):
return 1
app = myApp()
frame = wxFrame(NULL, -1, "wxFancyText demo", wxDefaultPosition)
frame.SetClientSize(getExtent(str))
bmp = renderToBitmap(str, wxCYAN_BRUSH)
sb = wxStaticBitmap(frame, -1, bmp)
EVT_MENU(frame, ID_EXIT, frame.Destroy)
frame.Show(1)
app.MainLoop()

View File

@@ -31,7 +31,7 @@ class FileBrowseButton(wxPanel):
startDirectory -- Default directory for file dialog startup
fileMask -- File mask (glob pattern, such as *.*) to use in file dialog
fileMode -- wxOPEN or wxSAVE, indicates type of file dialog to use
changeCallback -- callback receives all changes in value of control
changeCallback -- callback receives all > > changes in value of control
)
GetValue() -- retrieve current value of text control
SetValue(string) -- set current value of text control

View File

@@ -0,0 +1,236 @@
#----------------------------------------------------------------------
# Name: rpcMixin
# Version: 0.1
# Purpose: provides xmlrpc server functionality for wxPython
# applications via a mixin class
#
# Requires: (1) Python with threading enabled.
# (2) xmlrpclib from PythonWare
# (http://www.pythonware.com/products/xmlrpc/)
# the code was developed and tested using version 0.9.8
#
# Author: greg Landrum (Landrum@RationalDiscovery.com)
#
# Copyright: (c) 2000 by Greg Landrum and Rational Discovery LLC
# Licence: wxWindows license
#----------------------------------------------------------------------
"""
Some Notes:
1) The xmlrpc server runs in a separate thread from the main GUI
application, communication between the two threads using a custom
event (see the Threads demo in the wxPython docs for more info).
2) Neither the server nor the client are particularly smart about
checking method names. So it's easy to shoot yourself in the foot
by calling improper methods. It would be pretty easy to add
either a list of allowed methods or a list of forbidden methods.
3) Authentication of xmlrpc clients is *not* performed. I think it
would be pretty easy to do this in a hacky way, but I haven't done
it yet.
4) The default port number is 800, it's a windows thing... at least
it seems like a windows thing to me. Since I'm not being smart
about port numbers, you can probably hork yourself arbitrarily by
firing up more than one xmlrpc-active frame at the same time, but
I haven't tried that.
5) See the bottom of this file for an example of using the class.
Obligatory disclaimer:
This is my first crack at both using xmlrpc and multi-threaded
programming, so there could be huge horrible bugs or design
flaws. If you see one, I'd love to hear about them.
"""
from wxPython.wx import *
import xmlrpcserver
import Threading
import SocketServer
rpcPENDING = 0
rpcDONE = 1
rpcEXCEPT = 2
class RPCRequest:
"""A wrapper to use for handling requests and their responses"""
status = rpcPENDING
result = None
# here's the ID for external events
wxEVT_EXTERNAL_EVENT = 25015
class ExternalEvent(wxPyEvent):
"""The custom event class used to pass xmlrpc calls from
the server thread into the GUI thread
"""
def __init__(self,method,args):
wxPyEvent.__init__(self)
self.SetEventType(wxEVT_EXTERNAL_EVENT)
self.method = method
self.args = args
self.rpcStatus = RPCRequest()
self.rpcStatusLock = Threading.Lock()
self.rpcCondVar = Threading.Condition()
def EVT_EXTERNAL_EVENT(win,func):
win.Connect(-1,-1,wxEVT_EXTERNAL_EVENT,func)
class Handler(xmlrpcserver.RequestHandler):
"""The handler class that the xmlrpcserver actually calls
when a request comes in.
"""
def call(self,method,params):
"""When an xmlrpc request comes in, this is the method that
gets called.
"""
# construct the event
evt = ExternalEvent(method,params)
# update the status variable
evt.rpcStatusLock.acquire()
evt.rpcStatus.status = rpcPENDING
evt.rpcStatusLock.release()
# acquire the condition lock
evt.rpcCondVar.acquire()
# dispatch the event to the GUI
wxPostEvent(self._app,evt)
# wait for the GUI to finish
while evt.rpcStatus.status == rpcPENDING:
evt.rpcCondVar.wait()
evt.rpcCondVar.release()
evt.rpcStatusLock.acquire()
if evt.rpcStatus.status == rpcEXCEPT:
# The GUI threw an exception, release the status lock
# and re-raise the exception
evt.rpcStatusLock.release()
raise evt.rpcStatus.result[0],evt.rpcStatus.result[1]
else:
# everything went through without problems
s = evt.rpcStatus.result
evt.rpcStatusLock.release()
return s
class rpcMixin:
"""A mixin class to provide xmlrpc server functionality to wxPython
frames/windows
If you want to customize this, probably the best idea is to
override the OnExternal method, which is what's invoked when an
RPC is handled.
"""
def __init__(self,host='',port=800):
"""
Arguments:
host: (optional) the hostname for the server
port: (optional) the port the server will use
"""
EVT_EXTERNAL_EVENT(self,self.OnExternal)
if hasattr(self,'OnClose'):
self._origOnClose = self.OnClose
else:
self._origOnClose = None
EVT_CLOSE(self,self.OnClose)
exec('class Handler%d(Handler): pass'%(port))
exec('tClass= Handler%d'%(port))
tClass._app = self
self._xmlServ = SocketServer.TCPServer((host,port),tClass)
self.servThread = Threading.Thread(target=self._xmlServ.serve_forever)
self.servThread.setDaemon(1)
self.servThread.start()
def OnClose(self,event):
""" be sure to shutdown the server and the server thread before
leaving
"""
self._xmlServ = None
self.servThread = None
if self._origOnClose is not None:
self._origOnClose(event)
def OnExternal(self,event):
""" this is the callback used to handle RPCs
Exceptions are caught and returned in the global _rpcStatus
structure. This allows the xmlrpc server to report the
exception to the client without mucking up any of the delicate
thread stuff.
"""
event.rpcStatusLock.acquire()
try:
res = eval('apply(self.%s,event.args)'%event.method)
except:
import sys,traceback
traceback.print_exc()
event.rpcStatus.result = sys.exc_info()[:2]
event.rpcStatus.status = rpcEXCEPT
else:
if res is None:
event.rpcStatus.result = []
else:
event.rpcStatus.result = res
event.rpcStatus.status = rpcDONE
event.rpcStatusLock.release()
event.rpcCondVar.acquire()
event.rpcCondVar.notify()
event.rpcCondVar.release()
if __name__ == '__main__':
import sys
port = 800
if len(sys.argv)>1:
port = int(sys.argv[1])
class rpcFrame(wxFrame,rpcMixin):
"""A simple wxFrame with the rpcMixin functionality added
"""
def __init__(self,*args,**kwargs):
""" rpcHost or rpcPort keyword arguments will be passed along to
the xmlrpc server.
"""
mixinArgs = {}
if kwargs.has_key('rpcHost'):
mixinArgs['host'] = kwargs['rpcHost']
del kwargs['rpcHost']
if kwargs.has_key('rpcPort'):
mixinArgs['port'] = kwargs['rpcPort']
del kwargs['rpcPort']
apply(wxFrame.__init__,(self,)+args,kwargs)
apply(rpcMixin.__init__,(self,),mixinArgs)
EVT_CHAR(self,self.OnChar)
def TestFunc(self,args):
"""a demo method"""
return args
def OnChar(self,event):
key = event.GetKeyCode()
if key == ord('q'):
self.OnQuit(event)
def OnQuit(self,event):
self.OnClose(event)
def OnClose(self,event):
self.Destroy()
class MyApp(wxApp):
def OnInit(self):
frame = rpcFrame(NULL, -1, "wxPython RPCDemo", wxDefaultPosition, wxSize(300,300),rpcHost='localhost',rpcPort=port)
frame.Show(TRUE)
import time
#self.SetTopWindow(frame)
frame2 = rpcFrame(NULL, -1, "wxPython RPCDemo2", wxDefaultPosition, wxSize(300,300),rpcHost='localhost',rpcPort=port+1)
frame2.Show(TRUE)
return TRUE
app = MyApp(0)
app.MainLoop()