Merged the wxPy_newswig branch into the HEAD branch (main trunk)

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@24541 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Robin Dunn
2003-11-12 21:34:20 +00:00
parent eb6a4098a0
commit d14a1e2856
987 changed files with 671143 additions and 783083 deletions

View File

@@ -1,125 +1,19 @@
# Name: CDate.py
# Purpose: Date and Calendar classes
#
# Author: Lorne White (email: lwhite1@planet.eon.net)
#
# Created:
# Version 0.2 1999/11/08
# Licence: wxWindows license
#----------------------------------------------------------------------------
## This file imports items from the wx package into the wxPython package for
## backwards compatibility. Some names will also have a 'wx' added on if
## that is how they used to be named in the old wxPython package.
import time
import wx.lib.CDate
Month = {2: 'February', 3: 'March', None: 0, 'July': 7, 11:
'November', 'December': 12, 'June': 6, 'January': 1, 'September': 9,
'August': 8, 'March': 3, 'November': 11, 'April': 4, 12: 'December',
'May': 5, 10: 'October', 9: 'September', 8: 'August', 7: 'July', 6:
'June', 5: 'May', 4: 'April', 'October': 10, 'February': 2, 1:
'January', 0: None}
# Number of days per month (except for February in leap years)
mdays = [0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
# Full and abbreviated names of weekdays
day_name = [ 'Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday']
day_abbr = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', ]
# Return number of leap years in range [y1, y2)
# Assume y1 <= y2 and no funny (non-leap century) years
def leapdays(y1, y2):
return (y2+3)/4 - (y1+3)/4
# Return 1 for leap years, 0 for non-leap years
def isleap(year):
return year % 4 == 0 and (year % 100 <> 0 or year % 400 == 0)
def FillDate(val):
s = str(val)
if len(s) < 2:
s = '0' + s
return s
def julianDay(year, month, day):
b = 0L
year, month, day = long(year), long(month), long(day)
if month > 12L:
year = year + month/12L
month = month%12
elif month < 1L:
month = -month
year = year - month/12L - 1L
month = 12L - month%12L
if year > 0L:
yearCorr = 0L
else:
yearCorr = 3L
if month < 3L:
year = year - 1L
month = month + 12L
if year*10000L + month*100L + day > 15821014L:
b = 2L - year/100L + year/400L
return (1461L*year - yearCorr)/4L + 306001L*(month + 1L)/10000L + day + 1720994L + b
def TodayDay():
date = time.localtime(time.time())
year = date[0]
month = date[1]
day = date[2]
julian = julianDay(year, month, day)
daywk = dayOfWeek(julian)
daywk = day_name[daywk]
return(daywk)
def FormatDay(value):
date = FromFormat(value)
daywk = DateCalc.dayOfWeek(date)
daywk = day_name[daywk]
return(daywk)
def FromJulian(julian):
julian = long(julian)
if (julian < 2299160L):
b = julian + 1525L
else:
alpha = (4L*julian - 7468861L)/146097L
b = julian + 1526L + alpha - alpha/4L
c = (20L*b - 2442L)/7305L
d = 1461L*c/4L
e = 10000L*(b - d)/306001L
day = int(b - d - 306001L*e/10000L)
if e < 14L:
month = int(e - 1L)
else:
month = int(e - 13L)
if month > 2:
year = c - 4716L
else:
year = c - 4715L
year = int(year)
return year, month, day
def dayOfWeek(julian):
return int((julian + 1L)%7L)
def daysPerMonth(month, year):
ndays = mdays[month] + (month == 2 and isleap(year))
return ndays
class now:
def __init__(self):
self.date = time.localtime(time.time())
self.year = self.date[0]
self.month = self.date[1]
self.day = self.date[2]
class Date:
def __init__(self, year, month, day):
self.julian = julianDay(year, month, day)
self.month = month
self.year = year
self.day_of_week = dayOfWeek(self.julian)
self.days_in_month = daysPerMonth(self.month, self.year)
__doc__ = wx.lib.CDate.__doc__
Date = wx.lib.CDate.Date
FillDate = wx.lib.CDate.FillDate
FormatDay = wx.lib.CDate.FormatDay
FromJulian = wx.lib.CDate.FromJulian
TodayDay = wx.lib.CDate.TodayDay
dayOfWeek = wx.lib.CDate.dayOfWeek
daysPerMonth = wx.lib.CDate.daysPerMonth
isleap = wx.lib.CDate.isleap
julianDay = wx.lib.CDate.julianDay
leapdays = wx.lib.CDate.leapdays
now = wx.lib.CDate.now

View File

@@ -1,49 +1,9 @@
## This file imports items from the wx package into the wxPython package for
## backwards compatibility. Some names will also have a 'wx' added on if
## that is how they used to be named in the old wxPython package.
"""
sorry no documentation...
Christopher J. Fama
"""
from wxPython.wx import *
from wxPython.html import *
class wxPyClickableHtmlWindow(wxHtmlWindow):
"""
Class for a wxHtmlWindow which responds to clicks on links by opening a
browser pointed at that link, and to shift-clicks by copying the link
to the clipboard.
"""
def __init__(self,parent,ID,**kw):
apply(wxHtmlWindow.__init__,(self,parent,ID),kw)
def OnLinkClicked(self,link):
self.link = wxTextDataObject(link.GetHref())
if link.GetEvent().ShiftDown():
if wxTheClipboard.Open():
wxTheClipboard.SetData(self.link)
wxTheClipboard.Close()
else:
dlg = wxMessageDialog(self,"Couldn't open clipboard!\n",wxOK)
wxBell()
dlg.ShowModal()
dlg.Destroy()
else:
if 0: # Chris's original code...
if sys.platform not in ["windows",'nt'] :
#TODO: A MORE APPROPRIATE COMMAND LINE FOR Linux
#[or rather, non-Windows platforms... as of writing,
#this MEANS Linux, until wxPython for wxMac comes along...]
command = "/usr/bin/netscape"
else:
command = "start"
command = "%s \"%s\"" % (command,
self.link.GetText ())
os.system (command)
else: # My alternative
import webbrowser
webbrowser.open(link.GetHref())
import wx.lib.ClickableHtmlWindow
__doc__ = wx.lib.ClickableHtmlWindow.__doc__
wxPyClickableHtmlWindow = wx.lib.ClickableHtmlWindow.wxPyClickableHtmlWindow

View File

@@ -1,879 +1,25 @@
#----------------------------------------------------------------------------
# Name: ErrorDialogs.py
# Version: 1.0
# Created: September--October 2001
# Author: Chris Fama of Wholly Snakes Software,
# Chris.Fama@whollysnakes.com
#----------------------------------------------------------------------------
"""
ErrorDialogs.py: by Christopher J. Fama (trading under the name
Wholly Snakes Software {Australian Business Number: 28379514278}).
This code is released under the auspices of the modified version of
the GNU Library Public License (LGPL) that constitutes the license
under which the GUI package wxPython is released [see the file
LICENSE.TXT accompanying that distribution). I must also thank Graham
Boyd, of Boyd Mining, and CEO of the Minserve group of companies
(www.minserve.com.au), for kindly allowing the release of this
module under a "free" license, despite a certain part of it's
development having taken place while working for him...
Please note that this code, written for Python 2.1, is derives from
code written when Python 1.5.2 was current. Although since Python 2.0
the sys.excepthook variable has been available, for ease and potential
backwards compatibility (or to be more realistic
backwards-PARTIAL-compatibility!), the code catches errors by
assigning a custom object to sys.stderr and monitoring calls to it's
writ) method. Such calls which take place with a new value of
sys.last_traceback stand as evidence that at interpreter error has
just occurred; please note that this means that NO OTHER OUTPUT TO
sys.stderr WILL BE DISPLAYED. THIS INCLUDES "warnings" generated by
the interpreter. As far as I am aware, unless your code itself writes
to sys.stderr itself, these will be the only things you miss out
on--and many, if not most or all, of these will occur before your code
even gets the opportunity to set one of these file-like objects in
place. If this is a problem for you and you can't work around it,
please contact means or the wxPython-users mailing list.
DOCUMENTATION:
This is a module to display errors--either explicitly requested by a
script or arbitrary interpreter errors--these needs arose in the
course of a commercial (contract) project, but were not developed in
the course of work on such [well, very little, albeit concurrently]...
[NBNB.Does not currently support display of other than interpreter errors.]
Usage, after 'from wxPython.lib.ErrorDialogs import *' (all
identifiers defined in this module begin with "wxPy", and many of them
with "wxPyError_", so there should be no namespace conflicts...):
wxPyNewErrorDialog (<win> (['frame='] <frame (can be None)>,
<OPTIONS>))
...
wxPyDestroyErrorDialogIfPresent () # e.g. when top frame destroyed)
for unhandled errors, or
returnval = wxpyNonFatalError (<frame (can be None)>,
<HTML message>
[,<OPTIONS>])
or
returnval = wxPyFatalError (<HTML message>,
[,<OPTIONS, an extra one of which may be
'frame=' <frame (defaults to None)>>])
or
wxPybNonWindowingError (message)
for explicit errors.
<win> is one of
wxPyNonFatalErrorDialog
wxPyFatalErrorDialog
wxPyFatalErrorDialogWithTraceback
wxPyNonFatalErrorDialogWithTraceback
wxPyNonWindowingErrorHandler
and the OPTIONS (with defaults) are: (please note that the options for
wxPyNonWindowingErrorHandler / wxPyNonWindowingError are 'almost' a (small))
subset of these):
'modal' [default 1]: block until dismissed.
'programname' [default "Python program"]: appears inThe
caption of the dialog, amidst it's text and (by default) in mailings.
'whendismissed' option, if given, this should be a string, to be
executed in a restricted environment (see rexec module) after
dialog dismissal. Typically, this should be Python code to "clean
up" after what was presumably the partial execution of some
operation started by the user, after the unexpected interruption
by some error [which--at least the way I work, means an unexpected
error in the code, since exceptions that may be raised by some
foreseen (in a programmatic sense) should normally be handled by
try...except clauses].
NOTE THAT CURRENTLY THE rexec CODE IS NOT WORKING, SO THIS IS JUST DONE
BY exec...
'mailto': if None, give no "e-mail support" option, otherwise this
is meant to be an address for 'bug reports'; a command button will
be created for this, which pops up another dialog [Linux], or a window of
another program [Windows].
On Windows, this will launch your mailer (assuming your mailer
would start when a file with the '.eml'extension is double-clicked
in Windows Explorer--this will be the case for Microsoft Outlook
Express [tm and all those legal necessities] if installed, and the
association has not been taken over by some other program. On
Linux, it will open a file dialog to save the message, by default
as a '.html' file...{Please note that, on Windows and with current
(when I got the machine I'm writing this on--early 2000) versions
of Outlook Express, you may need to enter your e-mail address in
the box beside the "mail support" button.)
The template for the mail message is in the 'MessageTemplate'
attribute of the dialog-derived class in question (e.g.,
wxPyNonFatalErrorDialog). Search for this in the code below to
see the default (note that this template is in HTML format). This
attributes uses the '%{name}s' string conversion feature of Python
[see sec.2 of the Python Library Reference]; allowed Lance are:
programname version exceptionname exceptionvalue
extraexceptioninformation traceback
'version': str(this) will appear after 'Version' below "Error in
<programname>" at the top of the dialog.
EXAMPLES:
sys.stderr = wxPyNonFatalErrorWindowWithTraceback (
parentframe,
programname='sumthing',
mailto='me@sumwear',
whendismissed="from wxPython.wx import * ; wxBell()")
FOR INTERNATIONAL [NON-ENGLISH-SPEAKING] USE:
wxPyNonFatalErrorDialog and relatives have the method
SetText(Number NUMBER, STRING)
where STRING is to displayed in the wxStaticText control with ID
wxPyError_ID_TEXT<NUMBER>--see the automatically-generated code
for information about the meaning of these...
"""
_debug = 0
#_debug = 1 # uncomment to display some information (to stdout)
Version = 1.3
from wxPython.wx import *
import string, sys, traceback, time, rexec, operator, types, cStringIO, os
#from wxPython.lib.createandsendHTMLmail import *# now inline
#import MimeWriter, mimetools, tempfile, smtplib
import urllib, webbrowser
from ErrorDialogs_wdr import *
# You may see from the above line that I used the excellent RAD tool
# wxDesigner, by Robert Roebling, to accelerate development of this
# module... The above is left for the convenience of making future
# changes with wxDesigner; also so the wxDesigner-generated codedoes
# not need to precede the "hand-generated" code in this file; finally,
# as a personal endorsement: it is truly a brilliant time-saver!
# Please note that, at the time of writing, the wxDesigner-generated
# output requires manual removal of the PythonBitmaps function--an
# appropriate version of this function will be imported from a
# similarly- named module. Another manual change will have to be made
# to the automatically-generated source: "parent.sizerAroundText = "
# should be added [immediately] before the text similar to "item13 =
# wxStaticBoxSizer( item14, wxVERTICAL )", this sizer being the one
# containing the wxTextCtrl... [IMPORTANT NOTE: THIS LINE SHOULD BE
# THE ONE INSTANTIATING A wxStat2icBoxSizer, *NOT* THE wxStaticBox
# ITSELF...] As of version 1.2 [November 2001], this also needs to be
# done for the {sizers around the} wxPyClickableHtmlWindow's generated in
# populate_wxPyNonFatalError and populate_wxPyFatalError--note that
# for ease this sizer is still called "sizerAroundText"...
def wxPyDestroyErrorDialogIfPresent():
if isinstance(sys.stderr,wxPyNonFatalErrorDialog):
sys.stderr.Destroy()
sys.stderr = None
def wxPyNewErrorDialog(dlg):
wxPyDestroyErrorDialogIfPresent()
sys.stderr = dlg
class wxPyNonWindowingErrorHandler:
this_exception = 0
softspace = 0
def __init__(self,fatal=0,file=sys.__stderr__):
self.fatal = fatal
self.file = file
def write(self,s):
import sys
if s.find("Warning") <> 0\
and self.this_exception is not sys.last_traceback:
wxPyNonWindowingError("The Python interpreter encountered an error "
"not handled by any\nexception handler--this "
"may represent some programming error.",
fatal=self.fatal,
stderr=self.file,
last=1)
self.this_exception = sys.last_traceback
def wxPyNonWindowingError(msg,#output=None,errors=None,
stderr=sys.__stderr__,
fatal=1,
last=None):
if os.path.exists("wxPyNonWindowingErrors.txt"):
mode = 'a+'
else:
mode = 'w'
fl = open("wxPyNonWindowingErrors.txt",mode)
if stderr is not None:
l = [fl,stderr] # so that the error will be written to the file
# before any potential error in stderr.write()... (this is largely
# for my own sake in developing...)
else:
l = [fl]
for f in l:
f.write(time.ctime (time.time ()) + ": ")
f.write(msg)
#f.flush()
if sys.exc_info () [0] is not None:
if last:
f.write('Currently handled exception:\n')
f.flush()
traceback.print_exc(file=f)
if last:
f.write('\nPrevious (?) error:\n')
elif last or sys.last_traceback:
f.write("\n\n(For wizards only) ")
if last:
if type(last) <> types.ListType or len(last) < 3:
if (hasattr(sys,"last_traceback") and sys.last_traceback):
last = [sys.last_type ,sys.last_value,sys.last_traceback]
if type(last) == types.ListType:
traceback.print_exception(last[0],last[1],last[2],
None,f)
#f.flush()
if f is sys.__stderr__:
s = ' (see the file "wxPyNonWindowingErrors.txt")'
else:
s = ""
f.write("Please contact the author with a copy of this\n"
"message%s.\n" % s)
#f.flush()
fl.close()
if fatal and stderr is sys.__stderr__:
if sys.__stderr__ and sys.platform in ["windows",'nt',"win32"]:
sys.__stderr__.write(
"\nYou may have to manually close this window to exit.")
sys.exit()
class wxPythonRExec (rexec.RExec):
def __init__(self,securityhole=0,*args,**kwargs):
apply(rexec.RExec.__init__, (self,) + args, kwargs)
if securityhole:
self.ok_builtin_modules = self.ok_builtin_modules + \
('wxPython', 'wxPython.wxc','wxPython.wx','wxPython.misc',
'wxPython.misc2', 'wxPython.windows', 'wxPython.gdi',
'wxPython.clip_dnd', 'wxPython.events', 'wxPython.mdi',
'wxPython.frames', 'wxPython.stattool', 'wxPython.controls',
'wxPython.controls2', 'wxPython.windows2', 'wxPython.cmndlgs',
'wxPython.windows3', 'wxPython.image', 'wxPython.printfw',
'wxc','misc', 'misc2', 'windows', 'gdi', 'clip_dnd', 'events',
'mdi', 'frames', 'stattool', 'controls', 'controls2', 'windows2',
'cmndlgs', 'windows3', 'image', 'printfw', 'wx')
# possible security hole!
##def wxPyFatalError(msg,frame=None,**kwargs):
## kwargs.update({'fatal' : 1})
## apply(wxPyNonFatalError,
## (frame,msg),
## kwargs)
class wxPyNonFatalErrorDialogWithTraceback(wxDialog):
this_exception = 0
populate_function = populate_wxPyNonFatalErrorDialogWithTraceback
no_continue_button = False
fatal = False
modal = True
exitjustreturns = False # really only for testing!
def __init__(self, parent, id,
pos=wxPyDefaultPosition,
size=wxPyDefaultSize,
style=wxDEFAULT_DIALOG_STYLE,
programname="Python program",
version="?",
mailto=None,
whendismissed="",
extraversioninformation="",
caption="Python error!",
versionname=None,
errorname=None,
disable_exit_button=False):
if self.fatal:
whetherNF = ""
else:
whetherNF = "non-"
title = "A (%sfatal) error has occurred in %s!"\
% (whetherNF,programname)
self.programname = programname # save for later use
self.mailto = mailto # save for later use
self.parent = parent # save for later use
self.whendismissed = whendismissed # save for later use
self.dialogtitle = title # save for later use
wxDialog.__init__(self, parent, id, title, pos, size, style)
self.topsizer = self.populate_function( False,True )
self.SetProgramName(programname)
self.SetVersion(version)
if errorname:
self.FindWindowById(wxPyError_ID_TEXT1).SetLabel(str(errorname))
if versionname:
self.FindWindowById(wxPyError_ID_TEXT2).SetLabel(str(versionname))
self.FindWindowById(wxPyError_ID_VERSIONNUMBER).SetLabel(str(version))
self.FindWindowById(wxPyError_ID_EXTRA_VERSION_INFORMATION).SetLabel(str(
extraversioninformation))
if caption:
self.SetTitle(caption)
if not self.no_continue_button:
EVT_BUTTON(self, wxPyError_ID_CONTINUE, self.OnContinue)
if mailto:
disable_mail_button = 0
else:
disable_mail_button = 1
if not disable_mail_button:
EVT_BUTTON(self, wxPyError_ID_MAIL, self.OnMail)
else:
self.GetMailButton().Enable(False)
# disable the entry box for an e-mail address by default (NOT PROPERLY DOCUMENTED)
if not hasattr(self,"enable_mail_address_box"):
self.FindWindowById(wxPyError_ID_ADDRESS).Enable(False)
if not disable_exit_button:
EVT_BUTTON(self, wxPyError_ID_EXIT, self.OnExit)
def GetExtraInformation(self):
return self.extraexceptioninformation
def SetExtraInformation(self,value):
self.extraexceptioninformation = value
c = self.GetExtraInformationCtrl()
if c is not None:
c.SetLabel(str(value))
self.topsizer.Layout()
def GetExtraInformationCtrl(self):
return self.FindWindowById(wxPyError_ID_EXTRAINFORMATION)
def GetExceptionName(self):
return str(self.exceptiontype)
def SetExceptionName(self,value):
self.exceptiontype = str(value)
c = self.GetExceptionNameCtrl()
if c is not None:
c.SetLabel(str(value))
self.topsizer.Layout()
def GetExceptionNameCtrl(self):
return self.FindWindowById(wxPyError_ID_EXCEPTIONNAME)
def GetTraceback(self):
try:
return self.traceback
except AttributeError:
return None
def SetTraceback(self,value):
self.traceback = value
c = self.GetTracebackCtrl()
if c is not None:
s,cs = c.GetSize(), c.GetClientSize()
if value[-1] == '\n':
value = value[:-1]
if _debug:
print "%s.SetTraceback(): ...SetValue('%s' (^M=\\r; ^J=\\n))"\
% (self,value.replace('\n',"^J"))
c.SetValue(value)
# Despite using the wxADJUST_MINSIZE flag in the
# appropriate AddWindow method of the sizer, this doesn't
# size the control appropriately... evidently the control's
# GetBestSize method is not returning the "correct"
# value... So we perform a rather ugly "fix"... note that
# this also requires that we remove the wxADJUST_MINSIZE
# flag from the AddWindow method of the sizer containing
# the wxTextCtrl, which adds the wxTextCtrl... (this
# amounts, as of wxDesigner 2.6, to only a few mouse
# clicks...)
if _debug:
size = c.GetBestSize()
print "%s.SetTraceback(): %s.GetBestSize() = (%s,%s)"\
% (self,c,size.width,size.height)
w,h = 0,0
for v in value.split("\n"):
pw,ph,d,e = t = c.GetFullTextExtent(v)
if _debug:
print v, t
h = h + ph + e# + d
pw = pw + wxSystemSettings_GetSystemMetric(wxSYS_VSCROLL_X)
if pw > w:
w = pw
w = w + s.width - cs.width
h = h + s.height - cs.height
if _debug:
print "%s.SetTraceback(): calculated w,h =" % c,\
w,h,"and sys.platform = '%s'" % sys.platform
self.sizerAroundText.SetItemMinSize (c,w,h)
c.SetSize ((w,h))
c.SetSizeHints (w,h,w,h)
c.Refresh()#.SetAutoLayout(False)
#^ the reason we need the above seems to be to replace the
#faulty GetBestSize of wxTextCtrl...
#self.sizerAroundText.Layout()
self.topsizer.Layout()
def GetTracebackCtrl(self):
return self.FindWindowById(wxPyError_ID_TEXTCTRL)
def GetVersion(self):
return self.version
def SetVersion(self,value):
self.version = value
c = self.GetVersionNumberCtrl()
if c is not None:
c.SetLabel(value)
self.topsizer.Layout()
def GetVersionNumberCtrl(self):
return self.FindWindowById(wxPyError_ID_VERSIONNUMBER)
def GetProgramName(self):
return self.programname
def SetProgramName(self,value):
self.programname = value
c = self.GetProgramNameCtrl()
if c is not None:
c.SetLabel(value)
self.topsizer.Layout()
def GetProgramNameCtrl(self):
return self.FindWindowById(wxPyError_ID_PROGRAMNAME)
def GetContinueButton(self):
return self.FindWindowById(wxPyError_ID_CONTINUE)
def GetMailButton(self):
return self.FindWindowById(wxPyError_ID_MAIL)
def GetExitButton(self):
return self.FindWindowById(wxPyError_ID_EXIT)
# write handler (which is really the guts of the thing...
# [Note that this doesn't use sys.excepthook because I already had a
# working body of code...
def write(self,s):
if self.this_exception is not sys.last_traceback:
if not wxThread_IsMain():
# Aquire the GUI mutex before making GUI calls. Mutex is released
# when locker is deleted at the end of this function.
locker = wxMutexGuiLocker()
self.this_exception = sys.last_traceback
# this is meant to be done once per traceback's sys.stderr.write's
# - on the first in fact.....
try:
#from wxPython.wx import wxBell
wxBell()
if _debug:
if sys.stdout: sys.stdout.write(
'in %s.write(): ' % self)
self.exceptiontype = sys.last_type
self.extraexceptioninformation = sys.last_value
c = cStringIO.StringIO()
traceback.print_last(None,c)
self.traceback = c.getvalue()
if _debug:
#import traceback
traceback.print_last(None,sys.stdout)
self.SetExceptionName(str(self.exceptiontype))
self.SetExtraInformation(str(self.extraexceptioninformation))
self.SetTraceback(str(self.traceback))
self.topsizer.Fit(self)
self.topsizer.SetSizeHints(self)
self.CentreOnScreen()
if self.modal:
self.ShowModal()
else:
self.Show(True)
except:
if not locals().has_key("c"):
c = cStringIO.StringIO()
c.write("[Exception occurred before data from "
"sys.last_traceback available]")
wxPyNonWindowingError("Warning: "
"a %s error was encountered trying to "
"handle the exception\n%s\nThis was:"#%s\n"
% (sys.exc_type, c.getvalue()),#, c2.getvalue()),
stderr=sys.stdout,
last=0)
# button handlers:
def OnContinue(self, event):
try:
if self.whendismissed:
parent = self.parent # so whendismissed can refer to "parent"
if 1:
if _debug:
if sys.stdout: sys.stdout.write("exec '''%s''': "
% (self.whendismissed))
exec self.whendismissed
if _debug: print "\n",
else:
if _debug:
if sys.stdout: sys.stdout.write("wxPythonRExec(%s).r_exec('''%s'''): "
% (self.securityhole,
self.whendismissed))
wxPythonRExec(self.securityhole).r_exec(self.whendismissed)
if _debug: print "\n",
if self.modal:
self.EndModal(wxID_OK)
else:
self.Close ()
if _debug: print "reimporting ",
for m in sys.modules.values():
if m and m.__dict__["__name__"][0] in string.uppercase:#hack!
if _debug:
print m.__dict__["__name__"],
reload (m)
if _debug:
print ' ',
if _debug:
print '\nENDING %s.OnContinue()..\n\n' % (self,),
except:
wxPyNonWindowingError("Warning: the following exception information"
" may not be the full story.. (because "
"a %s(%s) error was encountered trying to "
"handle the exception)\n\n"
% tuple(sys.exc_info()[:2]),
stderr=sys.stdout,
last=0)
PlainMessageTemplate = \
"Hello,\n\n"\
'%(programname)s'\
" error.\n\n"\
"I encountered the following error when running your "\
'program %(programname)s,'\
"at %(date)s.\n\n"\
"(The following has been automatically generated...)\n"\
'%(traceback)s\n\n'\
"More information follows:\n\n"\
'[Insert more '\
"information about the error here, such as what you were "\
"trying to do at the time of the error. Please "\
"understand that failure to fill in this field will be "\
"interpreted as an invitation to consign this e-mail "\
"straight to the trash can!]\n\n"\
'Yours sincerely,\n'\
"[insert your name here]\n"
HTMLMessageTemplate = \
'<html>\n'\
'<body>'\
"<p>\n"\
"<i><b>Hello,</b></i>\n<p>\n"\
'<p><h2><font color="#CC6C00">%(programname)s</font>'\
" error.</h2>\n"\
"I encountered the following error when running your "\
'program <font color="#CC6C00">%(programname)s</font>,'\
"at %(date)s.\n<p>\n"\
"<p>"\
"<h2>Traceback (automatically generated):</h2>\n"\
'<p><font size="-1">\n<pre>%(traceback)s</pre>\n<p></font><p>'\
"\n<p>\n<h2>More information follows:</h2>\n<p>\n"\
'<font color="#CC6C00">'\
'<i>[Insert more '\
"information about the error here, such as what you were "\
"trying to do at the time of the error. Please "\
"understand that failure to fill in this field will be "\
"interpreted as an invitation to consign this e-mail "\
"straight to the trash can!]\n</i><p>\n"\
"</font><p>\n"\
'<i><b>Yours sincerely,</b></i>\n<p>'\
'<font color="#CC6C00">'\
"[insert your name here]\n"\
"</font>\n"\
"</body>\n"\
"</html>\n"
# text="#000000" bgcolor="#FFFFFF">\n'\
def OnMail(self,event):
try:
if _debug:
print 'Attempting to write mail message.\n',
gmtdate = time.asctime(time.gmtime(time.time())) + ' GMT'
tm = time.localtime(time.time())
date = time.asctime(tm) + ' ' +\
time.strftime("%Z",tm)
programname = self.programname
traceback = self.traceback
mailto = self.mailto
subject = "Un-caught exception when running %s." % programname
mailfrom = None#self.FindWindowById (wxPyError_ID_ADDRESS)
if mailfrom:
mailfrom = mailfrom.GetValue()
if _startmailerwithhtml(mailto,subject,
self.HTMLMessageTemplate % vars(),
text=self.PlainMessageTemplate % vars(),
mailfrom=mailfrom):
if not (hasattr(self,"fatal") and self.fatal):
self.OnContinue(event) # if ok, then act as if "Continue" selected
except:
wxPyNonWindowingError("Warning: the following exception information"
" may not be the full story... (because "
"a %s error was encountered trying to "
"handle the original exception)\n\n"#%s"
% (sys.exc_type,),#self.msg),
stderr=sys.stdout,
last=0)
def OnExit(self, event):
if self.IsModal():
self.EndModal(wxID_CANCEL)
if self.exitjustreturns:
return
wxGetApp().ExitMainLoop()
def SetText(self,number,string):
self.FindWindowById(eval("wxPyError_ID_TEXT%d"
% number)).SetLabel(string)
self.topsizer.Layout()
class wxPyFatalErrorDialogWithTraceback(wxPyNonFatalErrorDialogWithTraceback):
populate_function = populate_wxPyFatalErrorDialogWithTraceback
no_continue_button = True
fatal = True
class wxPyNonFatalErrorDialog(wxPyNonFatalErrorDialogWithTraceback):
populate_function = populate_wxPyNonFatalErrorDialog
class wxPyFatalErrorDialog(wxPyFatalErrorDialogWithTraceback):
populate_function = populate_wxPyFatalErrorDialog
def _startmailerwithhtml(mailto,subject,html,text=None,mailfrom=None):
if sys.hexversion >= 0x02000000:#\
# and sys.platform in ["windows",'nt',"w is in32"]:
s = 'mailto:%s?subject=%s&body=%s' % (mailto,
urllib.quote(subject),
urllib.quote(
text.replace('\n','\r\n'),
""))
# Note that RFC 2368 requires that line breaks in the body of
# a message contained in a mailto URL MUST be encoded with
# "%0D%0A"--even on Unix/Linux. Also note that there appears
# to be no way to specify that the body of a mailto tag be
# interpreted as HTML (mailto tags shouldn't stuff around with
# the MIME-Version/Content-Type headers, the RFC says, so I
# can't even be bothered trying, as the Python
# webbrowser/urllib modules quite likely won't allow
# this... anyway, a plain text message is [at least!] fine...).
if _debug:
t = urllib.quote(text)
if len(t) > 20 * 80:
t = t[0:20 * 80] + "..."
print "\nSummarizing (only shortened version of argument "\
"printed here), ",
print 'webbrowser.open("' \
'mailto:%s?subject=%s&body=%s"' % (mailto,
urllib.quote(subject),
t)
webbrowser.open(s)
return 1
else:
return _writehtmlmessage(mailto,subject,html,text,mailfrom=mailfrom)
def _writehtmlmessage(mailto,subject,html,text=None,parent=None,mailfrom=None):
dlg = wxFileDialog (parent,
"Please choose a a file to save the message to...",
".",
"bug-report",
"HTML files (*.htm,*.html)|*.htm,*.html|"
"All files (*)|*",
wxSAVE | wxHIDE_READONLY)
if dlg.ShowModal() <> wxID_CANCEL:
f = open(dlg.GetPath(),"w")
dlg.Destroy()
f.write(_createhtmlmail(html,text,subject,to=mailto,mailfrom=mailfrom))
f.close()
return 1
else:
return 0
# PLEASE NOTE THAT THE CODE BELOW FOR WRITING A GIVEN
#(HTML) MESSAGE IS BY ART GILLESPIE [with slight modifications by yours truly].
def _createhtmlmail (html, text, subject, to=None, mailfrom=None):
"""Create a mime-message that will render HTML in popular
MUAs, text in better ones (if indeed text is not unTrue (e.g. None)
"""
import MimeWriter, mimetools, cStringIO
out = cStringIO.StringIO() # output buffer for our message
htmlin = cStringIO.StringIO(html)
if text:
txtin = cStringIO.StringIO(text)
writer = MimeWriter.MimeWriter(out)
#
# set up some basic headers... we put subject here
# because smtplib.sendmail expects it to be in the
# message body
#
if mailfrom:
writer.addheader("From", mailfrom)
#writer.addheader("Reply-to", mailfrom)
writer.addheader("Subject", subject)
if to:
writer.addheader("To", to)
writer.addheader("MIME-Version", "1.0")
#
# start the multipart section of the message
# multipart/alternative seems to work better
# on some MUAs than multipart/mixed
#
writer.startmultipartbody("alternative")
writer.flushheaders()
#
# the plain text section
#
if text:
subpart = writer.nextpart()
subpart.addheader("Content-Transfer-Encoding", "quoted-printable")
pout = subpart.startbody("text/plain", [("charset", 'us-ascii')])
mimetools.encode(txtin, pout, 'quoted-printable')
txtin.close()
#
# start the html subpart of the message
#
subpart = writer.nextpart()
subpart.addheader("Content-Transfer-Encoding", "quoted-printable")
pout = subpart.startbody("text/html", [("charset", 'us-ascii')])
mimetools.encode(htmlin, pout, 'quoted-printable')
htmlin.close()
#
# Now that we're done, close our writer and
# return the message body
#
writer.lastpart()
msg = out.getvalue()
out.close()
return msg
def _sendmail(mailto,subject,html,text):# currently unused
"""For illustration only--this function is not actually used."""
import smtplib
message = _createhtmlmail(html, text, subject)
server = smtplib.SMTP("localhost")
server.sendmail(mailto, subject, message)
server.quit()
def wxPyFatalError(parent,msg,**kw):
return wxPyFatalOrNonFatalError(parent,msg,fatal=1,**kw)
def wxPyNonFatalError(parent,msg,**kw):
return wxPyFatalOrNonFatalError(parent,msg,fatal=0,**kw)
def wxPyResizeHTMLWindowToDispelScrollbar(window,
fraction,
sizer=None,
defaultfraction=0.7):
# Try to `grow' parent window (typically a dialog), only so far as
# no scrollbar is necessary, mantaining aspect ratio of display.
# Will go no further than specified fraction of display size.
w = 200
if type(fraction) == type(''):
fraction = int(fraction[:-1]) / 100.
ds = wxDisplaySize ()
c = window.GetInternalRepresentation ()
while w < ds[0] * fraction:
c.Layout(w)
if _debug:
print '(c.GetHeight() + 20, w * ds[1]/ds[0]):',\
(c.GetHeight() + 20, w * ds[1]/ds[0])
if c.GetHeight() + 20 < w * ds[1]/ds[0]:
size = (w,min(int ((w) * ds[1]/ds[0]),
c.GetHeight()))
break
w = w + 20
else:
if type(defaultfraction) == type(''):
defaultfraction = int(defaultfraction[:-1]) / 100.
defaultsize = (defaultfraction * ds[0], defaultfraction * ds[1])
if _debug:
print 'defaultsize =',defaultsize
size = defaultsize
window.SetSize(size)
if sizer is not None:
sizer.SetMinSize(size)
sizer.Fit(window)
#sizer.SetSizeHints(window)
def wxPyFatalOrNonFatalError(parent,
msg,
fatal=0,
extraversioninformation="",
caption=None,
versionname=None,
errorname=None,
version="?",
programname="Python program",
tback=None,# backwards compatibility, and for
#possible future inclusion of ability to display
#a traceback along with the given message
#"msg"... currently ignored though...
modal=0):
if not wxThread_IsMain():
# Aquire the GUI mutex before making GUI calls. Mutex is released
# when locker is deleted at the end of this function.
locker = wxMutexGuiLocker()
dlg = wxDialog(parent,-1,"Error!")
if fatal:
populate_function = populate_wxPyFatalError
else:
populate_function = populate_wxPyNonFatalError
sizer = populate_function(dlg,False,True)
window = dlg.FindWindowById(wxPyError_ID_HTML)
window.SetPage(msg)
wxPyResizeHTMLWindowToDispelScrollbar(window,
"85%",
sizer=dlg.sizerAroundText)
dlg.FindWindowById(wxPyError_ID_PROGRAMNAME).SetLabel(str(programname))
if errorname:
dlg.FindWindowById(wxPyError_ID_TEXT1).SetLabel(str(errorname))
if versionname:
dlg.FindWindowById(wxPyError_ID_TEXT2).SetLabel(str(versionname))
dlg.FindWindowById(wxPyError_ID_VERSIONNUMBER).SetLabel(str(version))
dlg.FindWindowById(wxPyError_ID_EXTRA_VERSION_INFORMATION).SetLabel(str(
extraversioninformation))
if caption:
dlg.SetTitle(caption)
sizer.Fit(dlg)
sizer.SetSizeHints(dlg)
dlg.CentreOnScreen()
if modal:
v = dlg.ShowModal()
dlg.Destroy()
return v
else:
dlg.Show(True)
## This file imports items from the wx package into the wxPython package for
## backwards compatibility. Some names will also have a 'wx' added on if
## that is how they used to be named in the old wxPython package.
import wx.lib.ErrorDialogs
__doc__ = wx.lib.ErrorDialogs.__doc__
_createhtmlmail = wx.lib.ErrorDialogs._createhtmlmail
_sendmail = wx.lib.ErrorDialogs._sendmail
_startmailerwithhtml = wx.lib.ErrorDialogs._startmailerwithhtml
_writehtmlmessage = wx.lib.ErrorDialogs._writehtmlmessage
wxPyDestroyErrorDialogIfPresent = wx.lib.ErrorDialogs.wxPyDestroyErrorDialogIfPresent
wxPyFatalError = wx.lib.ErrorDialogs.wxPyFatalError
wxPyFatalErrorDialog = wx.lib.ErrorDialogs.wxPyFatalErrorDialog
wxPyFatalErrorDialogWithTraceback = wx.lib.ErrorDialogs.wxPyFatalErrorDialogWithTraceback
wxPyFatalOrNonFatalError = wx.lib.ErrorDialogs.wxPyFatalOrNonFatalError
wxPyNewErrorDialog = wx.lib.ErrorDialogs.wxPyNewErrorDialog
wxPyNonFatalError = wx.lib.ErrorDialogs.wxPyNonFatalError
wxPyNonFatalErrorDialog = wx.lib.ErrorDialogs.wxPyNonFatalErrorDialog
wxPyNonFatalErrorDialogWithTraceback = wx.lib.ErrorDialogs.wxPyNonFatalErrorDialogWithTraceback
wxPyNonWindowingError = wx.lib.ErrorDialogs.wxPyNonWindowingError
wxPyNonWindowingErrorHandler = wx.lib.ErrorDialogs.wxPyNonWindowingErrorHandler
wxPyResizeHTMLWindowToDispelScrollbar = wx.lib.ErrorDialogs.wxPyResizeHTMLWindowToDispelScrollbar
wxPythonRExec = wx.lib.ErrorDialogs.wxPythonRExec

View File

@@ -1,776 +1,14 @@
#-----------------------------------------------------------------------------
# Python source generated by wxDesigner from file: ErrorDialogs.wdr
# Do not modify this file, all changes will be lost!
#-----------------------------------------------------------------------------
## This file imports items from the wx package into the wxPython package for
## backwards compatibility. Some names will also have a 'wx' added on if
## that is how they used to be named in the old wxPython package.
# Include wxWindows' modules
from wxPython.wx import *
import wx.lib.ErrorDialogs_wdr
# Custom source
from wxPython.lib.PythonBitmaps import *
from wxPython.html import *
from wxPython.lib.ClickableHtmlWindow import *
__doc__ = wx.lib.ErrorDialogs_wdr.__doc__
# Window functions
wxPyError_ID_TEXT1 = 10000
wxPyError_ID_PROGRAMNAME = 10001
wxPyError_ID_TEXT2 = 10002
wxPyError_ID_VERSIONNUMBER = 10003
wxPyError_ID_EXTRA_VERSION_INFORMATION = 10004
wxPyError_ID_STATICBITMAP1 = 10005
wxPyError_ID_STATICBITMAP2 = 10006
wxPyError_ID_TEXT3 = 10007
wxPyError_ID_TEXT4 = 10008
wxPyError_ID_TEXTCTRL = 10009
wxPyError_ID_TEXT5 = 10010
wxPyError_ID_CONTINUE = 10011
wxPyError_ID_MAIL = 10012
wxPyError_ID_TEXT6 = 10013
wxPyError_ID_ADDRESS = 10014
wxPyError_ID_EXIT = 10015
wxPyError_ID_TEXT7 = 10016
wxPyError_ID_TEXT8 = 10017
wxPyError_ID_TEXT9 = 10018
wxPyError_ID_TEXT10 = 10019
wxPyError_ID_TEXT11 = 10020
wxPyError_ID_TEXT12 = 10021
def populate_wxPyNonFatalErrorDialogWithTraceback( parent, call_fit = true, set_sizer = true ):
item0 = wxBoxSizer( wxVERTICAL )
item1 = wxBoxSizer( wxHORIZONTAL )
item3 = wxStaticBox( parent, -1, "Non-fatal" )
item3.SetFont( wxFont( 9, wxSWISS, wxNORMAL, wxBOLD ) )
item2 = wxStaticBoxSizer( item3, wxVERTICAL )
item4 = wxBoxSizer( wxHORIZONTAL )
item5 = wxStaticText( parent, wxPyError_ID_TEXT1, "Error in ", wxDefaultPosition, wxDefaultSize, wxALIGN_CENTRE )
item5.SetForegroundColour( wxWHITE )
item5.SetBackgroundColour( wxRED )
item5.SetFont( wxFont( 21, wxSCRIPT, wxNORMAL, wxBOLD ) )
item4.AddWindow( item5, 0, wxADJUST_MINSIZE|wxALIGN_CENTRE|wxALL, 5 )
item6 = wxStaticText( parent, wxPyError_ID_PROGRAMNAME, "wxPyError_ID_PROGRAMNAME", wxDefaultPosition, wxDefaultSize, 0 )
item6.SetFont( wxFont( 21, wxROMAN, wxITALIC, wxNORMAL ) )
item4.AddWindow( item6, 1, wxADJUST_MINSIZE|wxALIGN_CENTRE|wxALL, 5 )
item2.AddSizer( item4, 0, wxADJUST_MINSIZE|wxALIGN_CENTRE|wxALL, 5 )
item7 = wxBoxSizer( wxHORIZONTAL )
item8 = wxStaticText( parent, wxPyError_ID_TEXT2, "Version ", wxDefaultPosition, wxDefaultSize, 0 )
item8.SetFont( wxFont( 9, wxROMAN, wxNORMAL, wxNORMAL ) )
item7.AddWindow( item8, 0, wxADJUST_MINSIZE|wxALIGN_CENTRE|wxALL, 5 )
item9 = wxStaticText( parent, wxPyError_ID_VERSIONNUMBER, "wxPyError_ID_VERSIONNUMBER", wxDefaultPosition, wxDefaultSize, 0 )
item9.SetFont( wxFont( 12, wxROMAN, wxNORMAL, wxBOLD ) )
item7.AddWindow( item9, 0, wxADJUST_MINSIZE|wxALIGN_CENTRE|wxALL, 5 )
item2.AddSizer( item7, 0, wxADJUST_MINSIZE|wxALIGN_CENTRE|wxALL, 5 )
item10 = wxStaticText( parent, wxPyError_ID_EXTRA_VERSION_INFORMATION, "wxPyError_ID_EXTRA_VERSION_INFORMATION", wxDefaultPosition, wxDefaultSize, wxALIGN_CENTRE )
item10.SetFont( wxFont( 7, wxROMAN, wxITALIC, wxNORMAL ) )
item2.AddWindow( item10, 0, wxADJUST_MINSIZE|wxALIGN_CENTRE|wxALL, 5 )
item1.AddSizer( item2, 1, wxADJUST_MINSIZE|wxALIGN_CENTRE|wxALL, 5 )
item11 = wxStaticBitmap( parent, wxPyError_ID_STATICBITMAP1, PythonBitmaps( 0 ), wxDefaultPosition, wxDefaultSize )
item1.AddWindow( item11, 0, wxADJUST_MINSIZE|wxALIGN_CENTRE|wxALL, 5 )
item12 = wxStaticBitmap( parent, wxPyError_ID_STATICBITMAP2, PythonBitmaps( 1 ), wxDefaultPosition, wxDefaultSize )
item1.AddWindow( item12, 0, wxADJUST_MINSIZE|wxALIGN_CENTRE|wxALL, 5 )
item0.AddSizer( item1, 0, wxADJUST_MINSIZE|wxGROW|wxALIGN_CENTER_VERTICAL|wxALL, 5 )
item13 = wxStaticText( parent, wxPyError_ID_TEXT3, "The Python interpreter has encountered a so-called \"un-caught exception\".", wxDefaultPosition, wxDefaultSize, 0 )
item0.AddWindow( item13, 0, wxADJUST_MINSIZE|wxALIGN_CENTRE|wxALL, 5 )
item15 = wxStaticBox( parent, -1, "Traceback" )
item15.SetFont( wxFont( 6, wxSWISS, wxITALIC, wxNORMAL ) )
parent.sizerAroundText = item14 = wxStaticBoxSizer( item15, wxVERTICAL )
item16 = wxStaticText( parent, wxPyError_ID_TEXT4,
"Please don't worry if this doesn't mean anything to you.\n"
"It will be included in the \"bug report\" mentioned below.",
wxDefaultPosition, wxDefaultSize, 0 )
item16.SetFont( wxFont( 8, wxROMAN, wxNORMAL, wxNORMAL ) )
item14.AddWindow( item16, 0, wxADJUST_MINSIZE|wxALIGN_CENTRE|wxALL, 5 )
item17 = wxTextCtrl( parent, wxPyError_ID_TEXTCTRL, "wxPyError_ID_TEXTCTRL", wxDefaultPosition, wxDefaultSize, wxTE_MULTILINE|wxTE_READONLY )
item17.SetFont( wxFont( 9, wxSWISS, wxNORMAL, wxNORMAL ) )
item17.SetToolTip( wxToolTip("A \"traceback\" reports the nature and location of a Python error.") )
item14.AddWindow( item17, 0, wxGROW|wxALIGN_CENTER_VERTICAL|wxALL, 5 )
item0.AddSizer( item14, 1, wxALIGN_CENTRE|wxALL, 5 )
item18 = wxStaticText( parent, wxPyError_ID_TEXT5, "Please select one of the options below.", wxDefaultPosition, wxDefaultSize, wxALIGN_CENTRE )
item18.SetFont( wxFont( 8, wxROMAN, wxITALIC, wxNORMAL ) )
item0.AddWindow( item18, 0, wxADJUST_MINSIZE|wxALIGN_CENTRE|wxALL, 5 )
item19 = wxFlexGridSizer( 3, 0, 0, 6 )
item19.AddGrowableCol( 0 )
item19.AddGrowableCol( 1 )
item19.AddGrowableCol( 2 )
item20 = wxButton( parent, wxPyError_ID_CONTINUE, "Continue", wxDefaultPosition, wxDefaultSize, 0 )
item20.SetDefault()
item19.AddWindow( item20, 0, wxADJUST_MINSIZE|wxALIGN_CENTRE|wxALL, 5 )
item21 = wxBoxSizer( wxHORIZONTAL )
item22 = wxButton( parent, wxPyError_ID_MAIL, "E-mail support", wxDefaultPosition, wxDefaultSize, 0 )
item21.AddWindow( item22, 0, wxADJUST_MINSIZE|wxALIGN_CENTRE|wxALL, 5 )
item23 = wxBoxSizer( wxVERTICAL )
item24 = wxStaticText( parent, wxPyError_ID_TEXT6, "Your e-mail address:", wxDefaultPosition, wxDefaultSize, 0 )
item24.SetFont( wxFont( 8, wxROMAN, wxITALIC, wxNORMAL ) )
item23.AddWindow( item24, 0, wxADJUST_MINSIZE|wxALIGN_CENTRE|wxALL, 5 )
item25 = wxTextCtrl( parent, wxPyError_ID_ADDRESS, "", wxDefaultPosition, wxSize(80,-1), 0 )
item23.AddWindow( item25, 2, wxADJUST_MINSIZE|wxGROW|wxALIGN_CENTER_VERTICAL|wxALL, 5 )
item21.AddSizer( item23, 0, wxADJUST_MINSIZE|wxALIGN_CENTRE|wxALL, 5 )
item19.AddSizer( item21, 0, wxADJUST_MINSIZE|wxALIGN_CENTRE|wxALL, 5 )
item26 = wxButton( parent, wxPyError_ID_EXIT, "Exit immediately", wxDefaultPosition, wxDefaultSize, 0 )
item19.AddWindow( item26, 0, wxADJUST_MINSIZE|wxALIGN_CENTRE|wxALL, 5 )
item27 = wxStaticText( parent, wxPyError_ID_TEXT7, "Attempt to continue.", wxDefaultPosition, wxDefaultSize, 0 )
item19.AddWindow( item27, 0, wxADJUST_MINSIZE|wxALIGN_CENTRE|wxALL, 5 )
item28 = wxStaticText( parent, wxPyError_ID_TEXT8, "E-mail a \"bug report\" (if this is indeed a bug!).", wxDefaultPosition, wxDefaultSize, 0 )
item19.AddWindow( item28, 0, wxADJUST_MINSIZE|wxALIGN_CENTRE|wxALL, 5 )
item29 = wxStaticText( parent, wxPyError_ID_TEXT9, "Attempt to exit immediately.", wxDefaultPosition, wxDefaultSize, wxALIGN_RIGHT )
item19.AddWindow( item29, 0, wxADJUST_MINSIZE|wxALIGN_CENTRE, 5 )
item30 = wxStaticText( parent, wxPyError_ID_TEXT10, "", wxDefaultPosition, wxDefaultSize, wxALIGN_RIGHT )
item30.SetFont( wxFont( 7, wxROMAN, wxNORMAL, wxBOLD ) )
item19.AddWindow( item30, 0, wxADJUST_MINSIZE|wxALIGN_CENTRE|wxALL, 5 )
item31 = wxStaticText( parent, wxPyError_ID_TEXT11, "(Please read any accompanying documentation first!)", wxDefaultPosition, wxDefaultSize, wxALIGN_CENTRE )
item31.SetFont( wxFont( 7, wxROMAN, wxNORMAL, wxBOLD ) )
item19.AddWindow( item31, 0, wxADJUST_MINSIZE|wxALIGN_CENTRE|wxALL, 5 )
item32 = wxStaticText( parent, wxPyError_ID_TEXT12, "(Please note that no attempt to save unsaved data will be made.)", wxDefaultPosition, wxDefaultSize, wxALIGN_RIGHT )
item32.SetFont( wxFont( 7, wxROMAN, wxNORMAL, wxBOLD ) )
item19.AddWindow( item32, 0, wxADJUST_MINSIZE|wxALIGN_CENTRE|wxALL, 5 )
item0.AddSizer( item19, 0, wxADJUST_MINSIZE|wxALIGN_CENTRE|wxALL, 5 )
if set_sizer == true:
parent.SetAutoLayout( true )
parent.SetSizer( item0 )
if call_fit == true:
item0.Fit( parent )
item0.SetSizeHints( parent )
return item0
wxPyError_wxPyError_ID_TEXT3 = 10022
wxPyError_ID_EXCEPTIONNAME = 10023
wxPyError_ID_EXTRAINFORMATION = 10024
wxPyError_ID_TEXT13 = 10025
wxPyError_ID_TEXT14 = 10026
def populate_wxPyNonFatalErrorDialog( parent, call_fit = true, set_sizer = true ):
item0 = wxBoxSizer( wxVERTICAL )
item1 = wxBoxSizer( wxHORIZONTAL )
item2 = wxBoxSizer( wxHORIZONTAL )
item4 = wxStaticBox( parent, -1, "Non-fatal" )
item4.SetFont( wxFont( 9, wxSWISS, wxNORMAL, wxBOLD ) )
item3 = wxStaticBoxSizer( item4, wxVERTICAL )
item5 = wxBoxSizer( wxHORIZONTAL )
item6 = wxStaticText( parent, wxPyError_ID_TEXT1, "Error in ", wxDefaultPosition, wxDefaultSize, wxALIGN_CENTRE )
item6.SetForegroundColour( wxWHITE )
item6.SetBackgroundColour( wxRED )
item6.SetFont( wxFont( 21, wxSCRIPT, wxNORMAL, wxBOLD ) )
item5.AddWindow( item6, 0, wxADJUST_MINSIZE|wxALIGN_CENTRE|wxALL, 5 )
item7 = wxStaticText( parent, wxPyError_ID_PROGRAMNAME, "wxPyError_ID_PROGRAMNAME", wxDefaultPosition, wxDefaultSize, 0 )
item7.SetFont( wxFont( 21, wxROMAN, wxITALIC, wxNORMAL ) )
item5.AddWindow( item7, 1, wxADJUST_MINSIZE|wxALIGN_CENTRE|wxALL, 5 )
item3.AddSizer( item5, 0, wxADJUST_MINSIZE|wxALIGN_CENTRE|wxALL, 5 )
item8 = wxBoxSizer( wxHORIZONTAL )
item9 = wxStaticText( parent, wxPyError_ID_TEXT2, "Version ", wxDefaultPosition, wxDefaultSize, 0 )
item9.SetFont( wxFont( 9, wxROMAN, wxNORMAL, wxNORMAL ) )
item8.AddWindow( item9, 0, wxADJUST_MINSIZE|wxALIGN_CENTRE|wxALL, 5 )
item10 = wxStaticText( parent, wxPyError_ID_VERSIONNUMBER, "wxPyError_ID_VERSIONNUMBER", wxDefaultPosition, wxDefaultSize, 0 )
item10.SetFont( wxFont( 12, wxROMAN, wxNORMAL, wxBOLD ) )
item8.AddWindow( item10, 0, wxADJUST_MINSIZE|wxALIGN_CENTRE|wxALL, 5 )
item3.AddSizer( item8, 0, wxADJUST_MINSIZE|wxALIGN_CENTRE|wxALL, 5 )
item11 = wxStaticText( parent, wxPyError_ID_EXTRA_VERSION_INFORMATION, "wxPyError_ID_EXTRA_VERSION_INFORMATION", wxDefaultPosition, wxDefaultSize, wxALIGN_CENTRE )
item11.SetFont( wxFont( 7, wxROMAN, wxITALIC, wxNORMAL ) )
item3.AddWindow( item11, 0, wxADJUST_MINSIZE|wxALIGN_CENTRE|wxALL, 5 )
item2.AddSizer( item3, 1, wxADJUST_MINSIZE|wxALIGN_CENTRE|wxALL, 5 )
item12 = wxStaticBitmap( parent, wxPyError_ID_STATICBITMAP1, PythonBitmaps( 0 ), wxDefaultPosition, wxDefaultSize )
item2.AddWindow( item12, 0, wxADJUST_MINSIZE|wxALIGN_CENTRE|wxALL, 5 )
item13 = wxStaticBitmap( parent, wxPyError_ID_STATICBITMAP2, PythonBitmaps( 1 ), wxDefaultPosition, wxDefaultSize )
item2.AddWindow( item13, 0, wxADJUST_MINSIZE|wxALIGN_CENTRE|wxALL, 5 )
item1.AddSizer( item2, 1, wxADJUST_MINSIZE|wxALIGN_CENTRE|wxALL, 5 )
item0.AddSizer( item1, 1, wxADJUST_MINSIZE|wxGROW|wxALIGN_CENTER_VERTICAL|wxALL, 5 )
item14 = wxStaticText( parent, wxPyError_wxPyError_ID_TEXT3, "The Python interpreter has encountered a so-called \"un-caught exception\".", wxDefaultPosition, wxDefaultSize, 0 )
item0.AddWindow( item14, 0, wxADJUST_MINSIZE|wxALIGN_CENTRE|wxALL, 5 )
item16 = wxStaticBox( parent, -1, "Exception information" )
item16.SetFont( wxFont( 6, wxSWISS, wxITALIC, wxNORMAL ) )
item15 = wxStaticBoxSizer( item16, wxVERTICAL )
item17 = wxStaticText( parent, wxPyError_ID_TEXT4,
"Please don't worry if this doesn't mean anything to you.\n"
"It will be included in the \"bug report\" mentioned below, along with a \"stack traceback\".",
wxDefaultPosition, wxDefaultSize, wxALIGN_CENTRE )
item17.SetFont( wxFont( 8, wxROMAN, wxNORMAL, wxNORMAL ) )
item15.AddWindow( item17, 0, wxADJUST_MINSIZE|wxALIGN_CENTRE|wxALL, 5 )
item18 = wxFlexGridSizer( 2, 0, 1, 1 )
item18.AddGrowableCol( 1 )
item19 = wxStaticText( parent, wxPyError_ID_TEXT5, "Name:", wxDefaultPosition, wxDefaultSize, wxALIGN_RIGHT )
item19.SetFont( wxFont( 10, wxROMAN, wxITALIC, wxNORMAL ) )
item19.SetToolTip( wxToolTip("This gives the type of the error.") )
item18.AddWindow( item19, 0, wxADJUST_MINSIZE|wxALIGN_CENTRE|wxALL, 5 )
item20 = wxStaticText( parent, wxPyError_ID_EXCEPTIONNAME, "wxPyError_ID_EXCEPTIONNAME", wxDefaultPosition, wxDefaultSize, 0 )
item18.AddWindow( item20, 0, wxADJUST_MINSIZE|wxGROW|wxALIGN_CENTER_VERTICAL|wxALL, 5 )
item21 = wxStaticText( parent, wxPyError_ID_TEXT6,
"Extra\n"
"information:",
wxDefaultPosition, wxDefaultSize, wxALIGN_CENTRE )
item21.SetFont( wxFont( 10, wxROMAN, wxITALIC, wxNORMAL ) )
item18.AddWindow( item21, 0, wxADJUST_MINSIZE|wxALIGN_CENTRE|wxALL, 5 )
item22 = wxStaticText( parent, wxPyError_ID_EXTRAINFORMATION, "wxPyError_ID_EXTRAINFORMATION", wxDefaultPosition, wxDefaultSize, 0 )
item18.AddWindow( item22, 0, wxADJUST_MINSIZE|wxGROW|wxALIGN_CENTER_VERTICAL|wxALL, 5 )
item15.AddSizer( item18, 1, wxADJUST_MINSIZE|wxGROW|wxALIGN_CENTER_VERTICAL|wxALL, 5 )
item0.AddSizer( item15, 0, wxADJUST_MINSIZE|wxGROW|wxALIGN_CENTER_VERTICAL|wxALL, 10 )
item23 = wxStaticText( parent, wxPyError_ID_TEXT7, "Please select one of the options below.", wxDefaultPosition, wxDefaultSize, wxALIGN_CENTRE )
item23.SetFont( wxFont( 8, wxROMAN, wxITALIC, wxNORMAL ) )
item0.AddWindow( item23, 0, wxADJUST_MINSIZE|wxALIGN_CENTRE|wxALL, 5 )
item24 = wxFlexGridSizer( 3, 0, 0, 6 )
item24.AddGrowableCol( 0 )
item24.AddGrowableCol( 1 )
item24.AddGrowableCol( 2 )
item25 = wxButton( parent, wxPyError_ID_CONTINUE, "Continue", wxDefaultPosition, wxDefaultSize, 0 )
item25.SetDefault()
item24.AddWindow( item25, 0, wxADJUST_MINSIZE|wxALIGN_CENTRE|wxALL, 5 )
item26 = wxBoxSizer( wxHORIZONTAL )
item27 = wxButton( parent, wxPyError_ID_MAIL, "E-mail support", wxDefaultPosition, wxDefaultSize, 0 )
item26.AddWindow( item27, 0, wxADJUST_MINSIZE|wxALIGN_CENTRE|wxALL, 5 )
item28 = wxBoxSizer( wxVERTICAL )
item29 = wxStaticText( parent, wxPyError_ID_TEXT8, "Your e-mail address:", wxDefaultPosition, wxDefaultSize, 0 )
item29.SetFont( wxFont( 8, wxROMAN, wxITALIC, wxNORMAL ) )
item28.AddWindow( item29, 0, wxADJUST_MINSIZE|wxALIGN_CENTRE|wxALL, 5 )
item30 = wxTextCtrl( parent, wxPyError_ID_ADDRESS, "", wxDefaultPosition, wxSize(80,-1), 0 )
item28.AddWindow( item30, 2, wxADJUST_MINSIZE|wxGROW|wxALIGN_CENTER_VERTICAL|wxALL, 5 )
item26.AddSizer( item28, 0, wxADJUST_MINSIZE|wxALIGN_CENTRE|wxALL, 5 )
item24.AddSizer( item26, 0, wxADJUST_MINSIZE|wxALIGN_CENTRE|wxALL, 5 )
item31 = wxButton( parent, wxPyError_ID_EXIT, "Exit immediately", wxDefaultPosition, wxDefaultSize, 0 )
item24.AddWindow( item31, 0, wxADJUST_MINSIZE|wxALIGN_CENTRE|wxALL, 5 )
item32 = wxStaticText( parent, wxPyError_ID_TEXT9, "Attempt to continue.", wxDefaultPosition, wxDefaultSize, 0 )
item24.AddWindow( item32, 0, wxADJUST_MINSIZE|wxALIGN_CENTRE|wxALL, 5 )
item33 = wxStaticText( parent, wxPyError_ID_TEXT10, "E-mail a \"bug report\" (if this is indeed a bug!).", wxDefaultPosition, wxDefaultSize, 0 )
item24.AddWindow( item33, 0, wxADJUST_MINSIZE|wxALIGN_CENTRE|wxALL, 5 )
item34 = wxStaticText( parent, wxPyError_ID_TEXT11, "Attempt to exit immediately.", wxDefaultPosition, wxDefaultSize, wxALIGN_RIGHT )
item24.AddWindow( item34, 0, wxADJUST_MINSIZE|wxALIGN_CENTRE, 5 )
item35 = wxStaticText( parent, wxPyError_ID_TEXT12, "", wxDefaultPosition, wxDefaultSize, wxALIGN_CENTRE )
item35.SetFont( wxFont( 7, wxROMAN, wxNORMAL, wxBOLD ) )
item24.AddWindow( item35, 0, wxADJUST_MINSIZE|wxALIGN_CENTRE|wxALL, 5 )
item36 = wxStaticText( parent, wxPyError_ID_TEXT13, "(Please read any accompanying documentation first!)", wxDefaultPosition, wxDefaultSize, wxALIGN_CENTRE )
item36.SetFont( wxFont( 7, wxROMAN, wxNORMAL, wxBOLD ) )
item24.AddWindow( item36, 0, wxADJUST_MINSIZE|wxALIGN_CENTRE|wxALL, 5 )
item37 = wxStaticText( parent, wxPyError_ID_TEXT14, "(Please note that no attempt to save unsaved data will be made.)", wxDefaultPosition, wxDefaultSize, wxALIGN_RIGHT )
item37.SetFont( wxFont( 7, wxROMAN, wxNORMAL, wxBOLD ) )
item24.AddWindow( item37, 0, wxADJUST_MINSIZE|wxALIGN_CENTRE|wxALL, 5 )
item0.AddSizer( item24, 0, wxADJUST_MINSIZE|wxALIGN_CENTRE|wxALL, 5 )
if set_sizer == true:
parent.SetAutoLayout( true )
parent.SetSizer( item0 )
if call_fit == true:
item0.Fit( parent )
item0.SetSizeHints( parent )
return item0
def populate_wxPyFatalErrorDialogWithTraceback( parent, call_fit = true, set_sizer = true ):
item0 = wxBoxSizer( wxVERTICAL )
item1 = wxBoxSizer( wxHORIZONTAL )
item3 = wxStaticBox( parent, -1, "Fatal" )
item3.SetFont( wxFont( 9, wxSWISS, wxNORMAL, wxBOLD ) )
item2 = wxStaticBoxSizer( item3, wxVERTICAL )
item4 = wxBoxSizer( wxHORIZONTAL )
item5 = wxStaticText( parent, wxPyError_ID_TEXT1, "Error in ", wxDefaultPosition, wxDefaultSize, wxALIGN_CENTRE )
item5.SetForegroundColour( wxWHITE )
item5.SetBackgroundColour( wxRED )
item5.SetFont( wxFont( 21, wxSCRIPT, wxNORMAL, wxBOLD ) )
item4.AddWindow( item5, 0, wxADJUST_MINSIZE|wxALIGN_CENTRE|wxALL, 5 )
item6 = wxStaticText( parent, wxPyError_ID_PROGRAMNAME, "wxPyError_ID_PROGRAMNAME", wxDefaultPosition, wxDefaultSize, 0 )
item6.SetFont( wxFont( 21, wxROMAN, wxITALIC, wxNORMAL ) )
item4.AddWindow( item6, 1, wxADJUST_MINSIZE|wxALIGN_CENTRE|wxALL, 5 )
item2.AddSizer( item4, 0, wxADJUST_MINSIZE|wxALIGN_CENTRE|wxALL, 5 )
item7 = wxBoxSizer( wxHORIZONTAL )
item8 = wxStaticText( parent, wxPyError_ID_TEXT2, "Version ", wxDefaultPosition, wxDefaultSize, 0 )
item8.SetFont( wxFont( 9, wxROMAN, wxNORMAL, wxNORMAL ) )
item7.AddWindow( item8, 0, wxADJUST_MINSIZE|wxALIGN_CENTRE|wxALL, 5 )
item9 = wxStaticText( parent, wxPyError_ID_VERSIONNUMBER, "wxPyError_ID_VERSIONNUMBER", wxDefaultPosition, wxDefaultSize, 0 )
item9.SetFont( wxFont( 12, wxROMAN, wxNORMAL, wxBOLD ) )
item7.AddWindow( item9, 0, wxADJUST_MINSIZE|wxALIGN_CENTRE|wxALL, 5 )
item2.AddSizer( item7, 0, wxADJUST_MINSIZE|wxALIGN_CENTRE|wxALL, 5 )
item10 = wxStaticText( parent, wxPyError_ID_EXTRA_VERSION_INFORMATION, "wxPyError_ID_EXTRA_VERSION_INFORMATION", wxDefaultPosition, wxDefaultSize, wxALIGN_CENTRE )
item10.SetFont( wxFont( 7, wxROMAN, wxITALIC, wxNORMAL ) )
item2.AddWindow( item10, 0, wxADJUST_MINSIZE|wxALIGN_CENTRE|wxALL, 5 )
item1.AddSizer( item2, 1, wxADJUST_MINSIZE|wxALIGN_CENTRE|wxALL, 5 )
item11 = wxStaticBitmap( parent, wxPyError_ID_STATICBITMAP1, PythonBitmaps( 0 ), wxDefaultPosition, wxDefaultSize )
item1.AddWindow( item11, 0, wxADJUST_MINSIZE|wxALIGN_CENTRE|wxALL, 5 )
item12 = wxStaticBitmap( parent, wxPyError_ID_STATICBITMAP2, PythonBitmaps( 1 ), wxDefaultPosition, wxDefaultSize )
item1.AddWindow( item12, 0, wxADJUST_MINSIZE|wxALIGN_CENTRE|wxALL, 5 )
item0.AddSizer( item1, 1, wxADJUST_MINSIZE|wxGROW|wxALIGN_CENTER_VERTICAL|wxALL, 5 )
item13 = wxStaticText( parent, wxPyError_ID_TEXT3, "The Python interpreter has encountered a so-called \"un-caught exception\".", wxDefaultPosition, wxDefaultSize, 0 )
item0.AddWindow( item13, 0, wxADJUST_MINSIZE|wxALIGN_CENTRE|wxALL, 5 )
item15 = wxStaticBox( parent, -1, "Traceback" )
item15.SetFont( wxFont( 6, wxSWISS, wxITALIC, wxNORMAL ) )
parent.sizerAroundText = item14 = wxStaticBoxSizer( item15, wxVERTICAL )
item16 = wxStaticText( parent, wxPyError_ID_TEXT4,
"Please don't worry if this doesn't mean anything to you.\n"
"It will be included in the \"bug report\" mentioned below.",
wxDefaultPosition, wxDefaultSize, 0 )
item16.SetFont( wxFont( 8, wxROMAN, wxNORMAL, wxNORMAL ) )
item14.AddWindow( item16, 0, wxADJUST_MINSIZE|wxALIGN_CENTRE|wxALL, 5 )
item17 = wxTextCtrl( parent, wxPyError_ID_TEXTCTRL, "wxPyError_ID_TEXTCTRL", wxDefaultPosition, wxDefaultSize, wxTE_MULTILINE|wxTE_READONLY )
item17.SetFont( wxFont( 9, wxSWISS, wxNORMAL, wxNORMAL ) )
item17.SetToolTip( wxToolTip("A \"traceback\" reports the nature and location of a Python error.") )
item14.AddWindow( item17, 0, wxALIGN_CENTRE|wxALL, 5 )
item0.AddSizer( item14, 0, wxALIGN_CENTRE|wxALL, 5 )
item18 = wxStaticText( parent, wxPyError_ID_TEXT5, "Please select one of the options below.", wxDefaultPosition, wxDefaultSize, wxALIGN_CENTRE )
item18.SetFont( wxFont( 8, wxROMAN, wxITALIC, wxNORMAL ) )
item0.AddWindow( item18, 0, wxADJUST_MINSIZE|wxALIGN_CENTRE|wxALL, 5 )
item19 = wxFlexGridSizer( 3, 0, 0, 6 )
item19.AddGrowableCol( 0 )
item19.AddGrowableCol( 1 )
item19.AddGrowableCol( 2 )
item20 = wxBoxSizer( wxHORIZONTAL )
item21 = wxButton( parent, wxPyError_ID_MAIL, "E-mail support", wxDefaultPosition, wxDefaultSize, 0 )
item20.AddWindow( item21, 0, wxADJUST_MINSIZE|wxALIGN_CENTRE|wxALL, 5 )
item22 = wxBoxSizer( wxVERTICAL )
item23 = wxStaticText( parent, wxPyError_ID_TEXT6, "Your e-mail address:", wxDefaultPosition, wxDefaultSize, 0 )
item23.SetFont( wxFont( 8, wxROMAN, wxITALIC, wxNORMAL ) )
item22.AddWindow( item23, 0, wxADJUST_MINSIZE|wxALIGN_CENTRE|wxALL, 5 )
item24 = wxTextCtrl( parent, wxPyError_ID_ADDRESS, "", wxDefaultPosition, wxSize(80,-1), 0 )
item22.AddWindow( item24, 2, wxADJUST_MINSIZE|wxGROW|wxALIGN_CENTER_VERTICAL|wxALL, 5 )
item20.AddSizer( item22, 0, wxADJUST_MINSIZE|wxALIGN_CENTRE|wxALL, 5 )
item19.AddSizer( item20, 0, wxADJUST_MINSIZE|wxALIGN_CENTRE|wxALL, 5 )
item25 = wxButton( parent, wxPyError_ID_EXIT, "Exit immediately", wxDefaultPosition, wxDefaultSize, 0 )
item25.SetDefault()
item19.AddWindow( item25, 0, wxADJUST_MINSIZE|wxALIGN_CENTRE|wxALL, 5 )
item26 = wxStaticText( parent, wxPyError_ID_TEXT7, "E-mail a \"bug report\" (if this is indeed a bug!).", wxDefaultPosition, wxDefaultSize, 0 )
item19.AddWindow( item26, 0, wxADJUST_MINSIZE|wxALIGN_CENTRE|wxALL, 5 )
item27 = wxStaticText( parent, wxPyError_ID_TEXT8, "Attempt to exit immediately.", wxDefaultPosition, wxDefaultSize, wxALIGN_RIGHT )
item19.AddWindow( item27, 0, wxADJUST_MINSIZE|wxALIGN_CENTRE, 5 )
item28 = wxStaticText( parent, wxPyError_ID_TEXT9, "(Please read any accompanying documentation first!)", wxDefaultPosition, wxDefaultSize, wxALIGN_CENTRE )
item28.SetFont( wxFont( 7, wxROMAN, wxNORMAL, wxBOLD ) )
item19.AddWindow( item28, 0, wxADJUST_MINSIZE|wxALIGN_CENTRE|wxALL, 5 )
item29 = wxStaticText( parent, wxPyError_ID_TEXT10, "(Please note that no attempt to save unsaved data will be made.)", wxDefaultPosition, wxDefaultSize, wxALIGN_RIGHT )
item29.SetFont( wxFont( 7, wxROMAN, wxNORMAL, wxBOLD ) )
item19.AddWindow( item29, 0, wxADJUST_MINSIZE|wxALIGN_CENTRE|wxALL, 5 )
item0.AddSizer( item19, 0, wxADJUST_MINSIZE|wxALIGN_CENTRE|wxALL, 5 )
if set_sizer == true:
parent.SetAutoLayout( true )
parent.SetSizer( item0 )
if call_fit == true:
item0.Fit( parent )
item0.SetSizeHints( parent )
return item0
def populate_wxPyFatalErrorDialog( parent, call_fit = true, set_sizer = true ):
item0 = wxBoxSizer( wxVERTICAL )
item1 = wxBoxSizer( wxHORIZONTAL )
item3 = wxStaticBox( parent, -1, "Fatal" )
item3.SetFont( wxFont( 9, wxSWISS, wxNORMAL, wxBOLD ) )
item2 = wxStaticBoxSizer( item3, wxVERTICAL )
item4 = wxBoxSizer( wxHORIZONTAL )
item5 = wxStaticText( parent, wxPyError_ID_TEXT1, "Error in ", wxDefaultPosition, wxDefaultSize, wxALIGN_CENTRE )
item5.SetForegroundColour( wxWHITE )
item5.SetBackgroundColour( wxRED )
item5.SetFont( wxFont( 21, wxSCRIPT, wxNORMAL, wxBOLD ) )
item4.AddWindow( item5, 0, wxADJUST_MINSIZE|wxALIGN_CENTRE|wxALL, 5 )
item6 = wxStaticText( parent, wxPyError_ID_PROGRAMNAME, "wxPyError_ID_PROGRAMNAME", wxDefaultPosition, wxDefaultSize, 0 )
item6.SetFont( wxFont( 21, wxROMAN, wxITALIC, wxNORMAL ) )
item4.AddWindow( item6, 1, wxADJUST_MINSIZE|wxALIGN_CENTRE|wxALL, 5 )
item2.AddSizer( item4, 0, wxADJUST_MINSIZE|wxALIGN_CENTRE|wxALL, 5 )
item7 = wxBoxSizer( wxHORIZONTAL )
item8 = wxStaticText( parent, wxPyError_ID_TEXT2, "Version ", wxDefaultPosition, wxDefaultSize, 0 )
item8.SetFont( wxFont( 9, wxROMAN, wxNORMAL, wxNORMAL ) )
item7.AddWindow( item8, 0, wxADJUST_MINSIZE|wxALIGN_CENTRE|wxALL, 5 )
item9 = wxStaticText( parent, wxPyError_ID_VERSIONNUMBER, "wxPyError_ID_VERSIONNUMBER", wxDefaultPosition, wxDefaultSize, 0 )
item9.SetFont( wxFont( 12, wxROMAN, wxNORMAL, wxBOLD ) )
item7.AddWindow( item9, 0, wxADJUST_MINSIZE|wxALIGN_CENTRE|wxALL, 5 )
item2.AddSizer( item7, 0, wxADJUST_MINSIZE|wxALIGN_CENTRE|wxALL, 5 )
item10 = wxStaticText( parent, wxPyError_ID_EXTRA_VERSION_INFORMATION, "wxPyError_ID_EXTRA_VERSION_INFORMATION", wxDefaultPosition, wxDefaultSize, wxALIGN_CENTRE )
item10.SetFont( wxFont( 7, wxROMAN, wxITALIC, wxNORMAL ) )
item2.AddWindow( item10, 0, wxADJUST_MINSIZE|wxALIGN_CENTRE|wxALL, 5 )
item1.AddSizer( item2, 1, wxADJUST_MINSIZE|wxALIGN_CENTRE|wxALL, 5 )
item11 = wxStaticBitmap( parent, wxPyError_ID_STATICBITMAP1, PythonBitmaps( 0 ), wxDefaultPosition, wxDefaultSize )
item1.AddWindow( item11, 0, wxADJUST_MINSIZE|wxALIGN_CENTRE|wxALL, 5 )
item12 = wxStaticBitmap( parent, wxPyError_ID_STATICBITMAP2, PythonBitmaps( 1 ), wxDefaultPosition, wxDefaultSize )
item1.AddWindow( item12, 0, wxADJUST_MINSIZE|wxALIGN_CENTRE|wxALL, 5 )
item0.AddSizer( item1, 1, wxADJUST_MINSIZE|wxGROW|wxALIGN_CENTER_VERTICAL|wxALL, 5 )
item13 = wxStaticText( parent, wxPyError_ID_TEXT3, "The Python interpreter has encountered a so-called \"un-caught exception\".", wxDefaultPosition, wxDefaultSize, 0 )
item0.AddWindow( item13, 0, wxADJUST_MINSIZE|wxALIGN_CENTRE|wxALL, 5 )
item15 = wxStaticBox( parent, -1, "Exception information" )
item15.SetFont( wxFont( 6, wxSWISS, wxITALIC, wxNORMAL ) )
item14 = wxStaticBoxSizer( item15, wxVERTICAL )
item16 = wxStaticText( parent, wxPyError_ID_TEXT4,
"Please don't worry if this doesn't mean anything to you.\n"
"It will be included in the \"bug report\" mentioned below, along with a \"stack traceback\".",
wxDefaultPosition, wxDefaultSize, wxALIGN_CENTRE )
item16.SetFont( wxFont( 8, wxROMAN, wxNORMAL, wxNORMAL ) )
item14.AddWindow( item16, 0, wxADJUST_MINSIZE|wxALIGN_CENTRE|wxALL, 5 )
item17 = wxFlexGridSizer( 2, 0, 1, 1 )
item17.AddGrowableCol( 1 )
item18 = wxStaticText( parent, wxPyError_ID_TEXT5, "Name:", wxDefaultPosition, wxDefaultSize, wxALIGN_RIGHT )
item18.SetFont( wxFont( 10, wxROMAN, wxITALIC, wxNORMAL ) )
item18.SetToolTip( wxToolTip("This gives the type of the error.") )
item17.AddWindow( item18, 0, wxADJUST_MINSIZE|wxALIGN_CENTRE|wxALL, 5 )
item19 = wxStaticText( parent, wxPyError_ID_EXCEPTIONNAME, "wxPyError_ID_EXCEPTIONNAME", wxDefaultPosition, wxDefaultSize, 0 )
item17.AddWindow( item19, 0, wxADJUST_MINSIZE|wxGROW|wxALIGN_CENTER_VERTICAL|wxALL, 5 )
item20 = wxStaticText( parent, wxPyError_ID_TEXT6,
"Extra\n"
"information:",
wxDefaultPosition, wxDefaultSize, wxALIGN_CENTRE )
item20.SetFont( wxFont( 10, wxROMAN, wxITALIC, wxNORMAL ) )
item17.AddWindow( item20, 0, wxADJUST_MINSIZE|wxALIGN_CENTRE|wxALL, 5 )
item21 = wxStaticText( parent, wxPyError_ID_EXTRAINFORMATION, "wxPyError_ID_EXTRAINFORMATION", wxDefaultPosition, wxDefaultSize, 0 )
item17.AddWindow( item21, 0, wxADJUST_MINSIZE|wxGROW|wxALIGN_CENTER_VERTICAL|wxALL, 5 )
item14.AddSizer( item17, 0, wxADJUST_MINSIZE|wxGROW|wxALIGN_CENTER_VERTICAL|wxALL, 5 )
item0.AddSizer( item14, 1, wxADJUST_MINSIZE|wxGROW|wxALIGN_CENTER_VERTICAL|wxALL, 10 )
item22 = wxStaticText( parent, wxPyError_ID_TEXT7, "Please select one of the options below.", wxDefaultPosition, wxDefaultSize, wxALIGN_CENTRE )
item22.SetFont( wxFont( 8, wxROMAN, wxITALIC, wxNORMAL ) )
item0.AddWindow( item22, 0, wxADJUST_MINSIZE|wxALIGN_CENTRE|wxALL, 5 )
item23 = wxFlexGridSizer( 3, 0, 0, 6 )
item23.AddGrowableCol( 0 )
item23.AddGrowableCol( 1 )
item23.AddGrowableCol( 2 )
item24 = wxBoxSizer( wxHORIZONTAL )
item25 = wxButton( parent, wxPyError_ID_MAIL, "E-mail support", wxDefaultPosition, wxDefaultSize, 0 )
item24.AddWindow( item25, 0, wxADJUST_MINSIZE|wxALIGN_CENTRE|wxALL, 5 )
item26 = wxBoxSizer( wxVERTICAL )
item27 = wxStaticText( parent, wxPyError_ID_TEXT8, "Your e-mail address:", wxDefaultPosition, wxDefaultSize, 0 )
item27.SetFont( wxFont( 8, wxROMAN, wxITALIC, wxNORMAL ) )
item26.AddWindow( item27, 0, wxADJUST_MINSIZE|wxALIGN_CENTRE|wxALL, 5 )
item28 = wxTextCtrl( parent, wxPyError_ID_ADDRESS, "", wxDefaultPosition, wxSize(80,-1), 0 )
item26.AddWindow( item28, 2, wxADJUST_MINSIZE|wxGROW|wxALIGN_CENTER_VERTICAL|wxALL, 5 )
item24.AddSizer( item26, 0, wxADJUST_MINSIZE|wxALIGN_CENTRE|wxALL, 5 )
item23.AddSizer( item24, 0, wxADJUST_MINSIZE|wxALIGN_CENTRE|wxALL, 5 )
item29 = wxButton( parent, wxPyError_ID_EXIT, "Exit immediately", wxDefaultPosition, wxDefaultSize, 0 )
item29.SetDefault()
item23.AddWindow( item29, 0, wxADJUST_MINSIZE|wxALIGN_CENTRE|wxALL, 5 )
item30 = wxStaticText( parent, wxPyError_ID_TEXT9, "E-mail a \"bug report\" (if this is indeed a bug!).", wxDefaultPosition, wxDefaultSize, 0 )
item23.AddWindow( item30, 0, wxADJUST_MINSIZE|wxALIGN_CENTRE|wxALL, 5 )
item31 = wxStaticText( parent, wxPyError_ID_TEXT10, "Attempt to exit immediately.", wxDefaultPosition, wxDefaultSize, wxALIGN_RIGHT )
item23.AddWindow( item31, 0, wxADJUST_MINSIZE|wxALIGN_CENTRE, 5 )
item32 = wxStaticText( parent, wxPyError_ID_TEXT11, "(Please read any accompanying documentation first!)", wxDefaultPosition, wxDefaultSize, wxALIGN_CENTRE )
item32.SetFont( wxFont( 7, wxROMAN, wxNORMAL, wxBOLD ) )
item23.AddWindow( item32, 0, wxADJUST_MINSIZE|wxALIGN_CENTRE|wxALL, 5 )
item33 = wxStaticText( parent, wxPyError_ID_TEXT12, "(Please note that no attempt to save unsaved data will be made.)", wxDefaultPosition, wxDefaultSize, wxALIGN_RIGHT )
item33.SetFont( wxFont( 7, wxROMAN, wxNORMAL, wxBOLD ) )
item23.AddWindow( item33, 0, wxADJUST_MINSIZE|wxALIGN_CENTRE|wxALL, 5 )
item0.AddSizer( item23, 0, wxADJUST_MINSIZE|wxALIGN_CENTRE|wxALL, 5 )
if set_sizer == true:
parent.SetAutoLayout( true )
parent.SetSizer( item0 )
if call_fit == true:
item0.Fit( parent )
item0.SetSizeHints( parent )
return item0
wxPyError_ID_HTML = 10027
def populate_wxPyNonFatalError( parent, call_fit = true, set_sizer = true ):
item0 = wxBoxSizer( wxVERTICAL )
item1 = wxBoxSizer( wxHORIZONTAL )
item3 = wxStaticBox( parent, -1, "Non-fatal" )
item3.SetFont( wxFont( 9, wxSWISS, wxNORMAL, wxBOLD ) )
item2 = wxStaticBoxSizer( item3, wxVERTICAL )
item4 = wxBoxSizer( wxHORIZONTAL )
item5 = wxStaticText( parent, wxPyError_ID_TEXT1, "Error in ", wxDefaultPosition, wxDefaultSize, wxALIGN_CENTRE )
item5.SetForegroundColour( wxWHITE )
item5.SetBackgroundColour( wxRED )
item5.SetFont( wxFont( 21, wxSCRIPT, wxNORMAL, wxBOLD ) )
item4.AddWindow( item5, 0, wxADJUST_MINSIZE|wxALIGN_CENTRE|wxALL, 5 )
item6 = wxStaticText( parent, wxPyError_ID_PROGRAMNAME, "wxPyError_ID_PROGRAMNAME", wxDefaultPosition, wxDefaultSize, 0 )
item6.SetFont( wxFont( 21, wxROMAN, wxITALIC, wxNORMAL ) )
item4.AddWindow( item6, 1, wxADJUST_MINSIZE|wxALIGN_CENTRE|wxALL, 5 )
item2.AddSizer( item4, 0, wxADJUST_MINSIZE|wxALIGN_CENTRE|wxALL, 5 )
item7 = wxBoxSizer( wxHORIZONTAL )
item8 = wxStaticText( parent, wxPyError_ID_TEXT2, "Version ", wxDefaultPosition, wxDefaultSize, 0 )
item8.SetFont( wxFont( 9, wxROMAN, wxNORMAL, wxNORMAL ) )
item7.AddWindow( item8, 0, wxADJUST_MINSIZE|wxALIGN_CENTRE|wxALL, 5 )
item9 = wxStaticText( parent, wxPyError_ID_VERSIONNUMBER, "wxPyError_ID_VERSIONNUMBER", wxDefaultPosition, wxDefaultSize, 0 )
item9.SetFont( wxFont( 12, wxROMAN, wxNORMAL, wxBOLD ) )
item7.AddWindow( item9, 0, wxADJUST_MINSIZE|wxALIGN_CENTRE|wxALL, 5 )
item2.AddSizer( item7, 0, wxADJUST_MINSIZE|wxALIGN_CENTRE|wxALL, 5 )
item10 = wxStaticText( parent, wxPyError_ID_EXTRA_VERSION_INFORMATION, "wxPyError_ID_EXTRA_VERSION_INFORMATION", wxDefaultPosition, wxDefaultSize, wxALIGN_CENTRE )
item10.SetFont( wxFont( 7, wxROMAN, wxITALIC, wxNORMAL ) )
item2.AddWindow( item10, 0, wxADJUST_MINSIZE|wxALIGN_CENTRE|wxALL, 5 )
item1.AddSizer( item2, 1, wxADJUST_MINSIZE|wxALIGN_CENTRE|wxALL, 5 )
item11 = wxStaticBitmap( parent, wxPyError_ID_STATICBITMAP1, PythonBitmaps( 0 ), wxDefaultPosition, wxDefaultSize )
item1.AddWindow( item11, 0, wxADJUST_MINSIZE|wxALIGN_CENTRE|wxALL, 5 )
item12 = wxStaticBitmap( parent, wxPyError_ID_STATICBITMAP2, PythonBitmaps( 1 ), wxDefaultPosition, wxDefaultSize )
item1.AddWindow( item12, 0, wxADJUST_MINSIZE|wxALIGN_CENTRE|wxALL, 5 )
item0.AddSizer( item1, 0, wxADJUST_MINSIZE|wxGROW|wxALIGN_CENTER_VERTICAL|wxALL, 5 )
parent.sizerAroundText = item13 = wxBoxSizer( wxVERTICAL )
item14 = parent.HTMLWindow = wxPyClickableHtmlWindow( parent, wxPyError_ID_HTML )
item13.AddWindow( item14, 0, wxADJUST_MINSIZE|wxALIGN_CENTRE|wxALL, 5 )
item0.AddSizer( item13, 0, wxADJUST_MINSIZE|wxALIGN_CENTRE|wxALL, 5 )
item15 = wxFlexGridSizer( 3, 0, 0, 6 )
item15.AddGrowableCol( 0 )
item15.AddGrowableCol( 1 )
item15.AddGrowableCol( 2 )
item16 = wxButton( parent, wxID_OK, "OK", wxDefaultPosition, wxDefaultSize, 0 )
item16.SetDefault()
item15.AddWindow( item16, 0, wxADJUST_MINSIZE|wxALIGN_CENTRE|wxALL, 5 )
item17 = wxButton( parent, wxID_CANCEL, "Cancel", wxDefaultPosition, wxDefaultSize, 0 )
item15.AddWindow( item17, 0, wxADJUST_MINSIZE|wxALIGN_CENTRE|wxALL, 5 )
item18 = wxStaticText( parent, wxPyError_ID_TEXT1, "", wxDefaultPosition, wxDefaultSize, 0 )
item15.AddWindow( item18, 0, wxADJUST_MINSIZE|wxALIGN_CENTRE|wxALL, 5 )
item19 = wxStaticText( parent, wxPyError_ID_TEXT2, "", wxDefaultPosition, wxDefaultSize, wxALIGN_RIGHT )
item15.AddWindow( item19, 0, wxADJUST_MINSIZE|wxALIGN_CENTRE, 5 )
item0.AddSizer( item15, 1, wxADJUST_MINSIZE|wxALIGN_CENTRE|wxALL, 5 )
if set_sizer == true:
parent.SetAutoLayout( true )
parent.SetSizer( item0 )
if call_fit == true:
item0.Fit( parent )
item0.SetSizeHints( parent )
return item0
def populate_wxPyFatalError( parent, call_fit = true, set_sizer = true ):
item0 = wxBoxSizer( wxVERTICAL )
item1 = wxBoxSizer( wxHORIZONTAL )
item3 = wxStaticBox( parent, -1, "Fatal" )
item3.SetFont( wxFont( 9, wxSWISS, wxNORMAL, wxBOLD ) )
item2 = wxStaticBoxSizer( item3, wxVERTICAL )
item4 = wxBoxSizer( wxHORIZONTAL )
item5 = wxStaticText( parent, wxPyError_ID_TEXT1, "Error in ", wxDefaultPosition, wxDefaultSize, wxALIGN_CENTRE )
item5.SetForegroundColour( wxWHITE )
item5.SetBackgroundColour( wxRED )
item5.SetFont( wxFont( 21, wxSCRIPT, wxNORMAL, wxBOLD ) )
item4.AddWindow( item5, 0, wxADJUST_MINSIZE|wxALIGN_CENTRE|wxALL, 5 )
item6 = wxStaticText( parent, wxPyError_ID_PROGRAMNAME, "wxPyError_ID_PROGRAMNAME", wxDefaultPosition, wxDefaultSize, 0 )
item6.SetFont( wxFont( 21, wxROMAN, wxITALIC, wxNORMAL ) )
item4.AddWindow( item6, 1, wxADJUST_MINSIZE|wxALIGN_CENTRE|wxALL, 5 )
item2.AddSizer( item4, 0, wxADJUST_MINSIZE|wxALIGN_CENTRE|wxALL, 5 )
item7 = wxBoxSizer( wxHORIZONTAL )
item8 = wxStaticText( parent, wxPyError_ID_TEXT2, "Version ", wxDefaultPosition, wxDefaultSize, 0 )
item8.SetFont( wxFont( 9, wxROMAN, wxNORMAL, wxNORMAL ) )
item7.AddWindow( item8, 0, wxADJUST_MINSIZE|wxALIGN_CENTRE|wxALL, 5 )
item9 = wxStaticText( parent, wxPyError_ID_VERSIONNUMBER, "wxPyError_ID_VERSIONNUMBER", wxDefaultPosition, wxDefaultSize, 0 )
item9.SetFont( wxFont( 12, wxROMAN, wxNORMAL, wxBOLD ) )
item7.AddWindow( item9, 0, wxADJUST_MINSIZE|wxALIGN_CENTRE|wxALL, 5 )
item2.AddSizer( item7, 0, wxADJUST_MINSIZE|wxALIGN_CENTRE|wxALL, 5 )
item10 = wxStaticText( parent, wxPyError_ID_EXTRA_VERSION_INFORMATION, "wxPyError_ID_EXTRA_VERSION_INFORMATION", wxDefaultPosition, wxDefaultSize, wxALIGN_CENTRE )
item10.SetFont( wxFont( 7, wxROMAN, wxITALIC, wxNORMAL ) )
item2.AddWindow( item10, 0, wxADJUST_MINSIZE|wxALIGN_CENTRE|wxALL, 5 )
item1.AddSizer( item2, 1, wxADJUST_MINSIZE|wxALIGN_CENTRE|wxALL, 5 )
item11 = wxStaticBitmap( parent, wxPyError_ID_STATICBITMAP1, PythonBitmaps( 0 ), wxDefaultPosition, wxDefaultSize )
item1.AddWindow( item11, 0, wxADJUST_MINSIZE|wxALIGN_CENTRE|wxALL, 5 )
item12 = wxStaticBitmap( parent, wxPyError_ID_STATICBITMAP2, PythonBitmaps( 1 ), wxDefaultPosition, wxDefaultSize )
item1.AddWindow( item12, 0, wxADJUST_MINSIZE|wxALIGN_CENTRE|wxALL, 5 )
item0.AddSizer( item1, 1, wxADJUST_MINSIZE|wxGROW|wxALIGN_CENTER_VERTICAL|wxALL, 5 )
parent.sizerAroundText = item13 = wxBoxSizer( wxVERTICAL )
item14 = parent.HTMLWindow = wxPyClickableHtmlWindow( parent, wxPyError_ID_HTML )
item13.AddWindow( item14, 0, wxADJUST_MINSIZE|wxALIGN_CENTRE|wxALL, 5 )
item0.AddSizer( item13, 0, wxADJUST_MINSIZE|wxALIGN_CENTRE|wxALL, 5 )
item15 = wxFlexGridSizer( 2, 0, 0, 6 )
item15.AddGrowableCol( 0 )
item16 = wxButton( parent, wxID_OK, "OK", wxDefaultPosition, wxDefaultSize, 0 )
item16.SetDefault()
item15.AddWindow( item16, 0, wxADJUST_MINSIZE|wxALIGN_CENTRE|wxALL, 5 )
item18 = wxStaticText( parent, wxPyError_ID_TEXT3, "", wxDefaultPosition, wxDefaultSize, 0 )
item15.AddWindow( item18, 0, wxADJUST_MINSIZE|wxALIGN_CENTRE|wxALL, 5 )
item0.AddSizer( item15, 1, wxADJUST_MINSIZE|wxALIGN_CENTRE|wxALL, 5 )
if set_sizer == true:
parent.SetAutoLayout( true )
parent.SetSizer( item0 )
if call_fit == true:
item0.Fit( parent )
item0.SetSizeHints( parent )
return item0
# End of generated file
populate_wxPyFatalError = wx.lib.ErrorDialogs_wdr.populate_wxPyFatalError
populate_wxPyFatalErrorDialog = wx.lib.ErrorDialogs_wdr.populate_wxPyFatalErrorDialog
populate_wxPyFatalErrorDialogWithTraceback = wx.lib.ErrorDialogs_wdr.populate_wxPyFatalErrorDialogWithTraceback
populate_wxPyNonFatalError = wx.lib.ErrorDialogs_wdr.populate_wxPyNonFatalError
populate_wxPyNonFatalErrorDialog = wx.lib.ErrorDialogs_wdr.populate_wxPyNonFatalErrorDialog
populate_wxPyNonFatalErrorDialogWithTraceback = wx.lib.ErrorDialogs_wdr.populate_wxPyNonFatalErrorDialogWithTraceback

View File

@@ -1,6 +0,0 @@
from wxPython.py.PyCrust import *
if __name__ == '__main__':
main()

View File

@@ -1,6 +0,0 @@
from wxPython.py.PyFilling import *
if __name__ == '__main__':
main()

View File

@@ -1,6 +0,0 @@
from wxPython.py.PyShell import *
if __name__ == '__main__':
main()

View File

@@ -1,5 +0,0 @@
# Change this to an ImportError after the next release
import warnings
warnings.warn("PyCrust has been renamed to Py. Use 'from wx import py'", stacklevel=2)

View File

@@ -1,2 +0,0 @@
from wxPython.py.crust import *

View File

@@ -1,3 +0,0 @@
from wxPython.py.filling import *

View File

@@ -1,3 +0,0 @@
from wxPython.py.shell import *

View File

@@ -1,7 +0,0 @@
from wxPython.py.PyWrap import *
if __name__ == '__main__':
sys.path.insert(0, os.curdir)
main(sys.argv)

View File

@@ -1,857 +1,15 @@
#----------------------------------------------------------------------
# This file was generated by C:\Python21\wxPython\tools\img2py.py
# [NBNBNB with an addendum at the end, and...]
## This file imports items from the wx package into the wxPython package for
## backwards compatibility. Some names will also have a 'wx' added on if
## that is how they used to be named in the old wxPython package.
#----------------------------------------------------------------------------
# Name: PythonBitmaps.py
# Version: 1.0
# Created: October 2001
# Author: Chris Fama of Wholly Snakes Software,
# Chris.Fama@whollysnakes.com
#----------------------------------------------------------------------------
"""
This file was [mainly] generated by img2py. The functions of interest are:
import wx.lib.PythonBitmaps
getPythonPoweredBitmap
getPythonPoweredImage
getwxPythonBitmap
getwxPythonImage
__doc__ = wx.lib.PythonBitmaps.__doc__
--The meaning of these is obvious. They take no arguments.
PythonBitmaps
--This takes a single argument. If it tests True,
getPythonPoweredBitmap() is returned, else getwxPythonBitmap() is
returned.
Sorry no demo; see the demo for ErrorDialogs.py.
"""
from wxPython.wx import wxBitmapFromXPMData, wxImageFromBitmap
import cPickle, zlib
def getwxPythonData():
return cPickle.loads(zlib.decompress(
'x\xdau}iw\xdb:\xb2\xed\xf7\xfb+\x94C\x8aN$\x92\x16\'Q\xa2H.N\x92\xe7\xc8Cl\
\xd3\xc9Jb;\x1e\xe2x\xa0g;\xb1\xe3\xdf\xfe@\xd6.\xe8\xf4\xed\xfb\x1a+\x89\
\x0e\x9a\x04P\x05\xa0P\xc3F\xf1\xfd\xc5\xb5\xf5?[sV\xaf\xd7r\x9d\x96m\xb9n\
\xcb\x9e\xfb\x9f\x83\xad\xb9~\xd5\xfa\xd1Rz\xbdI\xda\xeb5\x15\xfb]Q\x91]\x1c\
\xfc8o\xfe3\xee\xd4\xff\x7f:I\x079\xfd\xff\xddnS\xe1\x0c\xc7\xd9\xb0\xa9xS\
\xeb\x8a\xbc\xc8\x9d\x9c*^[ME\x9e{c\xea\xe3\x83)_I\x9b\x8aVPW\x8c\xdd\xdc\
\x1e\xd0\x13_gOdM\xc5\xc7Hv\xeb4\x15\xa3\xb8y\xc5r\\\x8f\x9exj\x06\xde\x9f\
\xf43\xdfm*\xfe4\xaf\x8c\xed|<\xa0\x8a\xa8\xa9\xc8\xadl\x98{M\xc5\xb5\xde4\
\xdaK\x07\xe3\xa2\xa90*\xd9\xed\xb8\xa9\x18\xdb\xcd+^\xee\x8e\xa9\xe2\xd6\
\xa9+\xb2,\xb3\xf3\t\x91\x9f4\xdd\x0e\xfb\xee\x80\xf8Q\x8d\xea\x8aI6\xf1\'T\
\xf1j\xc8\n\xab\xa9h\x8f\x98A\x05U$V]QL\xfa\xbeO\x15\xf9\xb4\xae\xb0\xf2I\
\xdf"\x06}W\x88\xb8\xac\x00-\x0b\xedf\x9a\xdca\xafG\x15?\xa8\xc2\xeb\x15="n\
\xbf!n\xe8\r\x07\x18\xfa\x16MC?\xb7\x0b\x1a\xfa7\xad\xe9\xa5\x98\xf4,\xaa\
\xf8\xa2\xd2\xdc{}\xcc\xfd\xef\x868\xb7\xe7Z.M\xe5C\xc3\xa0\xc2\xc9\xd3\x82&\
j\xbb\x19z\xe6\xa5\x93\x9c\xa6a\xa5a\x90?\xf0\xfd1Uh\xf4\x8a\x9d\xe7\xe3\xbc\
\xa9(C\xf9\nU\x1c;</\x05\xd1\xf2\xa1l*\xfc\xbc\x97\xd3\xbc\xac5\xbd\x8c{i\
\x965\xc4\xfd3\xd7\x0c\xcc\x9e\xd8c\xa7\xffO\xfdD\xd6L\xd4\xb0\x18f\x98\xb9\
\t\xd6\xc7\xc0\x1e\x10qW\xb6|\xc5o*z]\xac\xf41\xa8\xfd\x10H\xe2\x06M\x85\xdf\
\xf4"\xb83\xe8\xd1\xbc(\xcd\n\x1aX~> ~$\xcdn\x18{EV\xd0D}\nx\xe8`\xd0\x97f\
\xe8\xc3\xc1\xd0\xce\xa8\xc2l\xb8\xee\xa5\x9e\xe5\xd0Jvt"n0\x18R\xc5RC\xbe]\
\x8cm\x87\xf8\xa1x\rO3\xdf\x1b\xd2\xdc\xf6\x9b\n\xc7\xab\x0b\xf52\xeb\xb6\
\xdfT\x9c\x86\xd4h\xdf\xeb\x13?\xde5+\xc8\x1a\xd4\x85\xb6\x07-\x98^\x9a\x83\
\xfcu\x1a\x87\x95z\xd8\xd9{\x16\xd6z\xbf\xa0\n\xbd\x19\xd8p<\x1cf\xc4\x8f\
\xc9\x88\xc9\x1fS\x85\xd1,\xdc\xdeD,\\\xa2\xb6l\xba\xf5\xdd|\xec\x13\x83\xde\
\xd9\xb2Qzb\xa7Y\x1fC1M)-\x87\x9b\xe6\t\xd7r&.\x91\xff\xd2\x92\xc4\xd1r\xd87\
\xe58\x88|\xb5\x19X\x9a\xa6NFO\xfcj*\xb2~Z`\xab\xef5\xe3\xf0\xc4\xae\xf5\xe8\
\x89%\x8d\xa5CJO\x18\xcd*\x1c\xf4\xfd!\x0b\x03S6J,\xbc\x99\xcan\x89\xc9a\xb3\
_\x9c\x9e\x9d\xdb\xb4\xc6\x86r\x1c`a\x8a5V\xf8`\xf2{\xdeb,^\xbf4\xe3\xc8\xf2\
\xcc\xa5W\xfe\x99k\xc8/\x86\x855\xee5K{\x81\xf7m\x1f\xe2\xf3\xc9\x95\xbd\xd0\
\x82i5,\xcczi\x9a\x11\x0b\'\x06\x11W\xa4}b\xe1\xa6\x85-V`\x8b\xbd\x98\xb2["\
\xff\x9c\xf7m\x06\xf2\'\x91l\x94\xc8_\x8f\xe4+D\xfe\xbc-\x1b\xa5\x8am\xda\
\xc8\xbdl\x02\x91\xf3R\xca6\x88Aw\x95l\x836a\x97$\xae\x9b\xf62Z\x96?\x9b\x1d\
e\x8f\xc7=\x87\x18\xb4%\xc7\x01\x9e&\xb2\xd1\x9c\x16\xdd\xaf.\xb6i\x8em\xfaf\
\xca\'\x88A?H\xc0\xdaEoB\x15\x9b\xf4J\xd1\x13"\x86dr3tw\xe8\x0e!\xa5Z4Q\xde\
\xd8\x85<\xcd\x9b\xfd2\x9c\x0c\xb3!\r}\x1a\xca^\xa8b\xdf\x92\xc4\x11\xb5{\
\xcdD\r\x9dA\x91\xd2\x13\x8bM\xb7vj\x0fA\xdchD\xeb4\xb3@\\X\xa2\x17\x1f\xe2\
\xe2\xde\x95\xbd\xd0\x06j7B\xc9\x17L\x1e\x10-\x9f\x9b\x81M\xf2\xc9\x10\xc4M:\
\xb2\x82&\xfbw,+ .\x9a\xa1\x17\xe2p\xc5\xec_\xd0\xe2\xb7\x87\x1ef\xff\xb1Y\
\x96N\xdfq\x1c\x9a\xca\xfbY\x1b4\xd9_i\xe1\x16\x99\x8d\xb9\xfd\x93`i\xb3<]BE\
\x91\xa1"$9\xd6\xf7{C\x9c\x95t\xaa{\xe2\xbc\x85\x80\r$?H\xc0\x0eC\x92\x0eC\
\x07Ol\x90\x1cs\xeaB<%\x19$\x04_A\x07N\x12\xca6\x88\x96\x95J\xbeBC\xff\x94P\
\xc5\xb0\x87\x8a\xd6\xec\x15\x9c\xfb\xcd\n\xea\xbb}\xc7\'\xe2,\x9a\x97\xe1\
\xd0M\xa9\xe2\x99v\xe5X(58+#~\x05\x8a\xc0\xa3)\x89#Z"\x03ZN:\xa4\x8a\xebf\
\x03\x89]\x9c\xbaD\\4{\x85hi\xcf*hY\xf6\x15\xf9\n\xcd\xadN<\xcd}\x7fH\x15[\
\xa4K\x89c~@s{\xe8\xd2\x82\xe9\x17\x03"\xae\xd0H\xdd\xc8\x87\x1e\xd1\xf2@\
\xa7\x98S\xf4\x86T1\xc6\xd9\xe0\xb0\xd8\xf2\xd1hQ\x80\xda\xab\x86\x85\xb9#t)\
\xa2\xe5\x894\x94L\xe8A\xb4p\'6\xcd\xcb\xb07\xa4\x85;&\xe90\x10\xfa\x07U<\
\x93\xb4\xccR\x0f\xc4]B\x0f\x12\x8d\x12-\xddf\x13\x8a3\xcc\xf2\x89\x96m\x12\
\xc1\xce\xd0J\x89\x96\xf9\x86\xa7\x99/\x94\t\x9a\xca\xdbf\x9d\x16i\xe1\x14\
\xf4\x84\xebB\xdb\xca \x94F\xa6\xec\x96\xa8]#\x9eZ\xf6\x18b\xfc\x1dt`\xa1\
\x19\x11\xb5\x87\xe0G\xdfF\xc5\xb8\xc3\xe3\xc8\xa8\xe2W\xd3h>\x14\xf2dHb\x9c\
\xe4\xc7p\x92\xf5\x86\x8d\x18?\xae\xe4\x13D\xfeS(\xdbp\xe8\x15K\xd2\x925\xaf\
\x94\r\xb5\x99\x9d\xf6\xc1\xa0\xaa#\xdb\xa0\nc\x84M\xd8\x07\xc7\xceB\xe6zJ\
\x15\x95#\x1b\xa5WN\x9b\n\xaf\xefy\x90t\'\xb3\n\xda/I\xcc\x92\x0e\x0c\xcae\
\x05\xa4\xd4[\xb3\xd6\x85*\xc5\xe7\xfe&\x8d\xc3J\xf3\x9cf\xff\xb8Y\x1fb\x14~\
J\xdb4iX(\x94 Qh\xb2y\x03\r\xc74\xd2\xef\xcd\xb2\xcc\xc5q\x03j;\x8dB2\x10\
\xcb\x16\x9a\xc1\x8fY/\xb4\x1c\x1e\x02\xe6GA\x15\x13\x129\xe3\xba4\x15\x83)i\
}B\x97\x82\xd6G+\xc8J-\xc8\xe4T\x97\x8dR\x85\xd2\xe2\x15\x04\x05\xde6\xe5\
\x13tF\xfd5\xb1\xf8\x0bT\x8c\x1b\xb9\xee:Be\xa1W\xd6\xe8X\xebIM\xe9\x9a\x8c\
\x11+\xf7\xa0I\x0fb\xd9(U\xa8!O%\xac\x82\x1ftF\xd9\xe2\xdc#\x16\xa6\xa4nd\
\xbe\x03\x16\xf6H\x11\xf0R\x1b\xe7\\\xd8\xb0P\x9c\x14\x0eX\x18\x92\xc93\xc9}\
\x9c\xfb\xbb\rq\xe3|\xec\xe2(\xd8\xd6XU\x80\x1ed\x91P\xf2\x85n\t\xb5G\x91\
\xb4\x10\x83.H\x18XBg\xa3\x8a\xc7\x86\x85\x93\xa2\xb6q\xe8l\x08\xb1\x91\x0b\
\xf0\xf4\x0b\xc9 \xdfgm<L\xb8\x17p\xec\x9a$\xbf\x9f9\xe0\xe9b(\x1b\xa5\x8a\
\xbb\x16\x04}\n;j\xa3\x99\xca~\x9a\xbb>\xb1\xd0\x07\x93\x8bAA\x15\xfb\xb6l\
\x83*\xe6\x9bq\x0c\x1c?\x87\x08~oI\x06\xd1\xae\xbc\x89\xe58\x88\xc9\xeb\xb3n\
\x89\x85\xa6\xc1S\xe9Q\xc5*i(c\xa9K\xbd#-\xb8\xe8\xa7=\xa2\xf6,\x96\x03\xa3\
\x8a\xf7\x0e\xaf\xa0\x82\x18\xd4!Y\xd8\x97z\xd0Q\x97\x18$\x146b\x90\x86\xd3t\
hA\x06}o\xf1\xd0\xa1\x17\x9e\xd1\xcc\t\x03\xc6\xa5\x8a\x85f\xe62\'\x1d\xa4D\
\x8bOr\xac/\x14zZ0\xddf\xe8\xb6\xd0\x9dl\xaa(g\xc4\xd1+w$O\xbd|\\@\\\xf0a\
\xe1B\xf9\x1eir\xe8\xb4`\xbe\x91t\x18O\x86\x90\xb8\xeb8\xf8\n{H\x15!\x1d\x16\
\xfd\xbe\xd3\'~l\x85\xd8\xc8.\xf8q\xe7r\xa3\x109\x7fh\xd1\xd9\xc3\xde\x80f\
\xff\xa5aP6\x10g6|\x06\rq\xb9\x9d\xf50\xf4n)\x9f\xa0\x89\xdah6\xd0\xd0/2X\
\xd1w\xcd+\x83\x9e0\xab\xb1_h\xb2\xfbckB\xb2p\x95x:q&\x10\x8e\x1fh*\xfdb2\
\xa6\x03\xc7i\x0e`\xa1\x9d\xf7\x07T\xf1\xd8\x92\xb4\xc0\xac&c5-\n\x9c/w\x01\
\xb6\xa9\x0f\x01\xbb#_\x81<\x9do1\xd7\xc7\xb4N{\n\x1d\'u!\xf9\x11r\x1b\xd0\
\x82\x7f`W\xf6\'\xb0\xb4\xaaY\x1b\xc4\x8f#\x12[inci/\x94\xb2\r\x9a\xfdq#\xb6\
\x1c\xdb\xe9\xc16=\xedb\xef\x17PHvM\xd9(ql\xd0\xbc\xe2\t\xe9\xe0Q\x85\xd6\
\x96\xafP\xc5\xfbJvK,,\xb0\x1b\x86\xfd\x01Ux\xa1\x9c(<1%\xb7K6\xc4\x92\xbaWd\
\xa3XA\xae|\x85*VigO\x06iJ\xd3\xa0\xd2q\xd2\xcf2\x88\x9c3R\x14m7u\xa0\x9eOy\
\x15Bc+y\x8by\xd8b;\xcd\x82\xb1\x84\x94\xb6\xa8b\xa5i\xa3\xe8\xe79\\\x04\x1e\
\x8cw\xdfC\x1b\xcf\xb6d!M\xd4\xef\x12\x87\xf8\x18\xeb\xd4\xf3d\xb7T\xe1\xc4\
\xd0\xc7\x8a\x01&\x8a\x0f\x8b!\x8c\xd5\n\x8a\x91\x9fA\xa7k5\x8dN\x9cq\x81U\
\xa86\x0c*r\xa1\xf6P\xc5VS1H\x07\x1e\x96e\x9b\xa4\xd40\x9d\x80\x85\xbf\x03\
\x9e\x17\xbc\xb2\xda\x85\t\xe8\x0e\x88\xb8\xf7M/\xc2H\x1a\xe2H\xfaL\x1c\x9b\
\x14\xc3>\x11\xf75\x91\xafP\x853\xe3\x18U(#90Z\x96o\x95|\x82\xa8\x8dH\x1d\
\xed\x0b\x81B\x8bN%O^\xaf\xdf\xf3i\x05}\xc6\x82\x91zahA\x85ck\xed\xcd\x91\
\xb4PE/\x90\xdd\x12\x0b7,\xc91\xaa\xf8\xe2@\xc2\xb0\xd4>\xa6\xbd/8\n\x0bg\
\xa5$3ab\xc3LX#\x9d.\x13:\x1dU|\xee\xca\'Hl\xed\x8e \x93\xb31\xad\xb1>-\x07q\
\xe2`\xd1\xddc\x8d\x8d\xd9(R\x9aF\x05\xbb2\x98\t\xbb\x01\xc4g\x81C\xab\x08\
\xe54PE.\x97\xc3\x90\xe6\xe5\xa7\xc3\x92\x1f\xf3rI\x03\xebe6\xfc0\xab\xb36h\
\x1a\x9c\xae\xa4\x85\xa6\xe1-\x91\xe3\xa0\x8aQ(\xc7A<\xfdn\xcb6\xa8\xe2\xc2\
\x82\x8b\xd1\xc2Q\xf0\xc7\x85,L\xb1\xb3\x1f\x1a\x9eN&\x13\x7f\x02\xdb#\xc2\
\x91\x94\xd3*\xfcg\x8e<\x02\x13\xa1\xc1\xfa\x8d\xd2\xbb\xd4\xc2Y\x99\xe3\xdc\
_\x81\x0fe8\x04\xc7\n\xf2\xb0\n\xeb\x16\nZ*\x1b\x85,\xbciv\xa5\xeb\x8a\xcd\
\x00\x16\x96\x90\x0e\xe3\x94\xc8\xdf\xd2\xb0\xc5\n\x8f*65\x1ck9\x0c\xefa\xd3\
hQ\x14\x16\x1cU\xbf\xd8\xd9\xe5\x92A\xf3\xcf\x1cUX^\xcfK\x9b\xa1\xf7\xa8\xdb\
\xdc\xcd\xc6\xd4\xe8\x19\xc9B?\xb5\xd9\x8dM\x82\xde\xcd&`\xe1\x87\x16\xf3\
\x14Z\xf02\x1c\xbbu\xa1\xc3\x02\x1a\xbd?\xc4\xa1\xf5=\x91O\x10\xd7\x97U\xd9\
\x0b\xbc_t\x12\n\x16\xa3"\xa3\xb3\xc1\xc9-\x08\x94#G\x8e\x94*\xe6M\xd9\x06M\
\xd4Z\xd3Fa\xe5>\x04\xec\xf1\xec\tZ\xc9Q \xb9N\x8b\x7f\xde\xc2F\xee\xe1\xe0;\
+!\xc6YO>\xef\xd0T\xbalWv<\x96R)Ul\x87\xbc\x1c r\xda1\xce\xfd\x01\xdc\x1d\
\xd7\x95l\x14\xfeB\r^\'\x17\x07\xce\xc1\x88\xa9\x85\xf7\xabOm\xf4r?%j\xd7\
\x1b\xf2\x87\xf9 \x05\xf9\xdb\x06\xcf-N\x8f.[\xd1cT\xfc\x9ab\xdf\xb2M\xf8\
\x89\x8c\x91\xa1TX\xefJ\xc8\x8f1\x0e\xf1\x1e\xc9\xb1\\\xea\xa7\xa3)\xb9\xd3\
\x8b\xd4\xa5\xf5\xf1uJ\xa6W>\xe9\xc3\xb5G\xf2T\xa8E\xa0v,\x97%\x8e\xe8\xbf\
\x92ZTl\x07r\x1c\xb4\xc6\x86\r\xb5i\x91\x0e\xf1\xc4\x06\xd6\xe90\x85M\xf8n\
\xf6\x04U\xac\x90\xadn\xfb\x16$\xee\xb4\xc5S\xc9\xce\xd0HvK\x8bN\x89e\xa3T\
\xb1\x14\xf2\xbc\xc0\x16["\xefWo\x90\xe3\x89t\xf6\n\xf1t)\x86\xef\x82Ms\x8b\
\xb4\x9c\x9e0\xb3\x89\xc9\xbb6\x13\x07\x17t\xe4\xc9F\x89\xeb\x0f\xac\xa0A\
\xe9\xfdg\xce\x81\x1c\x9b\xe4v\xb3+\xdb\xbc=\xfa\xd8\x84\x8fm\xf2\x9e\xe7ch9\
\xbdY\x1bTqA\x15\x8e8\xc6a\x04\x90\xfb8\xf7\x86XR\xc6\xec\t\xe2\xd8\x92.\x89\
#\x8eufO@s$\x938\x1f\xf6\xe1>\xfe\xa3\xc9F\xb1\xc6H\x16\xa6\x99\x85-6\xc2a\
\x91\x0f\xc0\x8fs\x12\xb0~\xdf\xc3\x11\xbd`\xf0Z\xc7\x1a\xb3h\x1a2\xa1}\xd2\
\x1a\xb3iI\t\xc1\x87\xf0B\x9b\xb7\x98\xb0p)@Ej\xe0X\xa8\xa3D\x8bO>\xb6\xbc.4\
\xf46\xa4T\x81\xf3\xf6O%_!\xe2\x96\x15\xd6a\xb0>\xb6\xc8\xde\x17\xda\xbaEO\
\xdc*\xb2\r\x9a\xec%\x07fS\x8e\n\xcd\x95\x03\x03\x83f\x03#~\x9c$\x88$\xda\
\x109\xf7\xcd\xd9 \xb4\x11\x07~\x98uRXm\xa1(\x12\x83\x9eu\x88q\xf6\xd3\rM\
\xf9\x044\x148\xcbs\x1f\x96\xc5\xcd\xec\tb\xe1\xa9B\xbe\x0b\xb1^\xa0\xc2ud\
\xb7T\xb1k\xf0H\xa1\xe4}R\xc9\x8b\x9f\xa7,\xf9m\xf9\n\xc2>\x1d,\xfe\x1c\x82\
\xbe \rV(\x92Cbrd\x91}\xdb\x1fc\x13\xdad\xac\x8a\x9d\x8f\x8a\x82\xddr\xfd!q\
\xec\x9e\xcf[\xf1?R\xf2pz\x08\x89C\x1c[\xa1x\xe5@*\xbd\x7f\x10\x91H\xd9\xae<\
\xd3\x10\xb0\x1bB\xb0E\x1d\xec\xfd\x01*6\xdb\xb4>\xc4\x96#\x8e\xf5IeI\'}\x98\
\xe6\xdfK\xf9\n\xb1\xf0\x98\xbc\xe7\xd6x\xd0\'~\xa404\x0b64?\xc2\xc0\xf3lT,6\
mx\x96\x10\x1fP\xf2(^\x99\x8f\'\x16-\x98m\x12\xb0\xe3~\n/\xed\x84T\x85\xfe$\
\xed\x11\xb5\x1b%\x8c\x80\t\xbc,\xdb4\x0e\x7fh\xa5T\xf1\x97\x0f\x0b\xcf\xa7n\
\xaf`G\t\xbd\x99&\xaa\xa2\xfd\xe2\n\x05\x9e\x9e\xd8\xe10\xc7\x00\x1b(nX8\xc8\
\x8b\x0c\xe2\xf3\x06\xc1\xd8t\x8c\xb9\xdd$\x7f\xb2-TZ\x9a\xb9\xcd\x88\x99\\ \
\xa2\x19B:\xa4Y\xd1\x88-\xd5\x95\xdd\xd2+\xdf:\xe0\x98\xe5\x13\xf9\x06I\x87\
\xa2\xe8\xc1\xcd\xb0\xa3\xc9^\xa8B\xe7\x10\xa7\x0c?\xc960\xfb\xfa\x88_A\xc5&\
G#-\xf8\xe8\xbb\x0es\x0c\xae\xac\x81\'_\x81\x13a\x04\xf3>\x85R\xb3C\xde\x9e\
\xd4w\xe1\x93\x0eCI-\xd1\x12\xd3\xc0\xfc\xbc\x80&\x1d\x90\r4\xc8X\x16\xc6R\
\x8cC:,\x92\xd3\xde\xaf\x0b\x89\xbe\x08q\xe4\x1c\xd2\xa1oA|z\x88\xbf|4\x11\
\x14\x1e@:\xa4!/\x07\x98o\x8b\nB\xbe>\xbb\xb1\xc9n\x18\x08\x1d\x86*6ln\x94\
\x14\x92\x7f\xe6\xa6\xb2Q:_\x8eKYA\xfc\xc8(\xa2i\te\x93\x16\x8c\xab`%\x8f\
\xb1\xb4\xe7g\xbdP\xc5\x9e#{\xa16\x9eI\x06\r\x85\xb6E<\xfd\xdd\xcc\x9c7\xf6\
\x86.\\\xbf\xa1l\x03\xbe\x8bJ\x8e\x03QQU\xb6A\\\xbf\xb7\xe4+pC\x91\xc8\xe9\
\xf9\x1c\xd3Zg\xcf7\x1f\xc0\xab\x1aw\xeb\x81\x85\xb3W\x88\x85\xbbT\x91\x0b\
\x15\x8eD\xdf\x06\xcd\xad\xe3Zp2\x15\x88\x04\xa4\xcc\xa0+\x07b\x9cC6\x07&\
\x82\xc2\x0e\x14\x92\xcf!\xb6X\x0eeb\r\xbb\xd2\xf1<(h\xbc\xa3\\\xacuG\x01vc\
\x027\xe5\x14N{\xb1\xfc\xe9\x89\xf3\x11\xa4e\nY\xf8F6\xa1\'\xe4\t=\xb1\x80\
\x91\n!<\xa1\xc9\x86B\xd2\x13\xc2\xb1\x99\xec_d%\xb9\xc2\x8c\xa2\xddp\xa0A\
\xd0\x8f\xa1\xb0\xfel\x86\xee\x0e\xdc\x01\x8c\x80g\x0b\x9a\xf4dB\x0c\xd2M`YX\
A{*\xe5\xd0!\x83\xe8\xd0\x1a\x17\xfe\x181>\x86\xd0\xf4a&\xfc6\xe5+4\xfbiC\
\xed8\x15:,\xac\x02\x9aJ\xc1C\xb8\xc2\xb7I\xdb\x1aKmk@\xd6I_\x88 "\xff\x96\
\xf4SO\xcc%t\xdc\x08\xb1\x13\x17\xeaW\xe2\xca\xa1\xd3\xec\xafq(\xbe\x0f\xe90\
-\x11\x14N\xb1\xa3"\x04Br\x0f\x9e\xab\x03\x97\'\x1b\x1c3K\x00d\x06`\xd0m\xc8\
\xc4\x81A\xc70V\xb3!\xc2\xb5\x17\x06\xf6m\x06#\xe0\x17\x85\xaf\x85\x06\x0b\r\
e\xb9\x8b\x80\x7f\x0e\x93g\xb9y\xc5\x9bx\xbeK\x15;\xa4\xd1\xfb\x93\x1c2\xe8>\
\x90\xd4B\x06Qp\xc9\xcbzP7^H\xb0yB=\xc7\x81\xc3\xb1y\x07\xda\xc5\x84\xe3\xfb\
,q\xbf\x91\\\xb7\x866d\xd0<I\xed\xc1\xa4\x0f~l\xcez\x01^*\x96\xe3\xa0\x8a.\
\x9d\xb7\xb6\xc5\xd6\xfc\xdb\xacQ\xaaxf\xac\xd3\x04J\xde\xa9.\x1b\xa5%u\xd6B\
\xfc\xd6\x865\x9f\x90cfRx\xec\xd8\x9d\xbd\x02{\x9f\xe2/\xb9\xcf.\x93\xd7\xd9\
\x13T\xf1\xc4\xc8\x9d\x14\x8b\xae0\x81vq\x10\x9fk\xd3\x11\xed\xf4m\x1cZ\x7fY\
!\xc9\xa1\x05\'\xcdD\xf5\xad\xdce_p\xc9m\x80c6C\xd2\xd8\xf4\xca4n\x14\x87\
\x96\xc2\xd8\x9e\t\x9cn\x03R\xbe3g\x88\xc8\xea-\xb9\xd3\x85\xda\x0c\x8d\xfe\
\xac#9F\x15\x1dX\'\xfd\x1e4\x94}\x17\xa8\x9b>x\xfa\xd4\xc297F$`\xaa\xc0\xe3<\
\x80\xd8z\x8a\x81T\xb1\x10n\xb9\x0f\x81\xa9\xe1\x08\xde;\x92\x96\xbeP\xf2\
\x88\x85\xd7\tp\x06\x16V\xe1\x8f\xd9T\x12\xc7\xbe\x06\xb2Qz\xa2\xb2%\x0b\xe9\
\x89KR6\xfd\x9c\xa3\xd5m\xb6\n\nDh\x86]\xe0a\xc6p\xa7_\x98\xb2\x82\x18T6<\
\x1d\xb8\xbe\x0f\xdb\xf4\xa4\x92O\x00q\xe7\xcaq\x10\x83\xfe(\x88x\xf7\x80\
\xb8\x9b \xb0\x9c\x8d\xa1\x07\x1d\xb9\x10[lgO\xc9/%\x848PH\xf3S\xec\x86\x14\
\xbba\x9b15\x85C\x03\xd3C\xe0al\x98\xd5\xef\x19\x12\xd0\x83\xc8\xf9\x12\xcb\
\'h7\xfcv\xe4\xd0i\xa4E#\x82=\xcfs!\x1dF\x16\x0e-\x0b\x03\xdb\xb2(\x82\xe7\
\xb2j\xfd\xbb+\x89\x83\xa3\x8a\xe1/^N\x90\xb3_\x01D\x1f\x03d6`\xad\xf5\xd8Qe\
+\x98l\x17g\xe5G\x15H\x95\x02O\xb8dX\xa5B\xed\x81\x82\xd6\xe6n\xb1\xb4\x1f\
\xe8\x04\xf2\x85*\x89\x88\x15q\xcc\x16:\x1d\xc2>\x89l\x94*,\x03\x90\x91\x0c\
\xc6\xc8+#\x00\xd2\x01\xcd\xedE\x0b\x12f\x80\xf3eBaRo\xd2C\x1c\xe8m\xd6\x06l\
d\x12\x17\x9e\xcfN\xea\x08\xd2aP@\xcb9i\xc9i &\x17\xd0O\xebB\xa7\xd8\x08\x91\
U\x0e\xd7\xe6&\x02\xcb\x03\x88\x0b5B\xb4\x9a\x97\xf6+\\\xe1\xd9\xd8\x85\xb8\
\x98\xf5\x02d\x86)GJk}\xc7\x90\xaf\x10\xd7_t\xf9\x04U\x98.@G\x16\x16\xbf\xc7\
\xa1V\x0f,|\xa1\xa1\xd7\x81\x00\xe2\xd8\xaa\t(\x0f\xebt\xbb\x1d\xd9\x0bU|+\
\xc9\x890\x19\xc0#\xf0c\nx\xe5\x10V\xf4\xd9\x8c\x16\x84\xe2m\x80l\\\xbc\xf2\
\x13v\xb6t\xdc\xed3\xc8\x86\x81mG\x8c\xebK\x81\x88\xb8\xb2\x00\xe5\xe1\x98x\
\x8746\xd7\x9d\x80c\xfa\xac\x17h\xd2\x90\xa7\x1e\xcb\xd3-\x151`\x07N\x95\x17\
\xd9-\x18\xf4\x87qJ6\xce\xa8\x96d\xb2G\x1c\x0b\x03\xf9\x04q\xac\xd3\xc2\xf9\
\xc2\xb0\xa4\x9e\x83\x80?k}\x1fuY\x81HQ\x17Q\xd1\x14\xd4\x8eT\x84}\xfap!\r$\
\xd7=\xaa0u\x88`V\x14\x97"9t\x1c\xe2\xae|\x82*\xde\xd1Ih\x8dS\x8eV\xb7\xe48\
\xe0\xd9,\x81\xbaaUr\xd3\x86\xdaS`\xd1\x998\xe6{\xbc\x91\xbf\xc86 \xa5\xbe\
\xaa\xd8\xa6\x19\x96\xd4\x90\xc1>\x19\xa2\xb3\x1b3Z\x10\xaf\x8c\xa1\xd4L\xc0\
\xb1\x96)\x1b%\x01;&\x1bh0\xe9aI\xdd\xc9%\x05\x1b9\x9b\xb5\x01\xf7\xb1\x0e\
\xa9\xcdp\x8f}\x12(\xeex\x02\xf7q\xd8\x91\xd4\x12\xd7O`\xcf\xe5\x13D\x9b\x1e\
I\xe2\xf6\x86\x8c\x93^ q\xd1\x1f\x8fm\xe2\xa9\xab\xb25\x0fo\xf1\xb0\x99\xec\
\xc2\xcd\x0b\xc0p\xe2\xb6$\x9fx\xea\xb5\xe1\x98\xb1}\xec\xdb\x0e\xcf>6\xf23\
\xc3=\x86\xa8\xd0\x1d\xe8\x1f.\xef}W\x0e\x1d _\x96tcF\xfd*\x08\xe7s\x1c\xf9\
\x0b\xce\xfd\xc2\x87\xb9\xf2\x1e\xde\xd1\xfe\xc0\x87s\x87qJ\x1c\xb1z\x0c\xe4\
\x134/:)\x02\xde\xb8\x07]\xea0\x82\x97\xd6\xc2:5m\x9c\x84)v\xa5\xe9\x01\x1e\
\xe5\x81\xa7k-\xd9\x0b1\xa8\x8a\x11\xd3\xeaC\xf4\x1dN)f!\x0c:\xa2eU\x95OP\
\xc5i\x8b\x99<\xa6}\x9b\xcaF\x19\xa6\xa5\xd1\xf1Z\x17\x12\xb0:\xb7\xc1\x08U\
\x8dW\x10B%W#\xc91\xaa\xf8f\xcaW\x88A\x89.\x9f \x06\xad\xcc\xc6A+9\xa8\xe4+\
\xc4\xb1s\x8a\xbc\x8fe \xe4\xd2\x00\xf8\xc9\x86M\xb8JaA\xcbv-Z\xb8_\x0c\xc4\
\xc4-\xa8\xa3/6\xaf\x0f\x86\x89+8=r,\\C\x97\x8d\x02\x03\xef\xc8\x91\xc2\x08 \
\xf5k<\x18b\xa2\xeeg\xbd\x10O\x17I\xd0\xa7R\xfb<T\x80\xd7\xee\xe3\x88\x9eo\
\x03\x94\xc6\xda\xe79Y|\xb63\xee\x13\x93\x7f\xd8\x00\x94\xb1:\xfa\xce\xc0J.\
\xc0\x8f\x12\x17\x1e\n\x07>\x94;Kv\x0b~\x18\xf2\t\xa2\xd6\n \xd8|\xf0\xe3K3\
\x0e7s\xd8\x1d\xf6)f\xc5\x08\x06\xde\xd8b\xe2 \xfaZ\xe4\xfdrk\\\x16m\xb1\x0e\
\x85\xd1\xd31\x96\xd4;\x08\xa5\xdc\x86M\xb8\x1e\xca6\x80\xfe!\xdfg6\xb4\x10\
\xb2\xd9!oqj\r\x11\xf2\xfd\xc41\x0b\xf6\x08\x94\x8cSr\xb0\x82\x0cW6J\xcba\
\xbb\xa4\xb8G\xd6\x07\xb5\xd7SH\xfe\x14fB\x9b4Gw\xec!\x18\xbbDX\xda\xc1\xb8o\
\x83\xda\x11\xa4e\n\xf2\x1dF2\xf5q\xf0\xed\xb7\xb9\x8215\xba\xec\x05\xfe \
\x87\xa5\x14\xa6\xf2\xa8#i\xc1U\x95\x08\x98\t\x17\xb4\xd8\xael\x83\x9eX\xeb\
\xc0\xaf\xeda\xb2\x17\x08\x8f;\x988\xd8\x1ef\x05H@\x06\xab \x9b\xbdB\xe4_\
\xb8\x10\x17C\x00S\xbe(\x08\xd7\xba\xd0\xa5\xaeh^\xec\x9c#4#\xc6)e\x08_\xef\
\x93\xa2(6:\x9c\xa1\x03RG\x85,`\x14#\xf9\xb5{u\xa1^L\x1e\x18\x88\x8b\x19\xdb\
c\x81\xb8\xdf.6\xe1\x18\xc2\xf1\x17\xa3\x90X\x95\\\x83\xfbg\xc2\x18\xa3K\x92\
AN]\xc8\x01\xc0\xf0\x86>\x0e\xbe\x83@vKO<\x98\xb2[\xc0^g\x15 \x7f\x8ahB\x1f;\
\xfbG\xc3\x0f\x7f2`\xf8\xfe\xfd\xec\x15\xc0\x92\xda\xd8b>\x96\xd4)[Z\xc2\xfa\
\xa2\xdd` :\x9bCw\xe8\xcc\x06F\x15\xd7\x1ab\xe2)N\xa0\x1et~\x97yzb\xf0\x13\
\x08NOu\x9e[\xf8P\x16I\x06\r\x07.6\xd0\xb8\xa4+D\xf9\x04\xd7\x7ft\xc4\x92\
\xb2>\xd4\xafO\x14J\xf3\x84\xf6I[\xec\xb4\x94#\xa5i\xd0\x08\x99\xd1\xf3\n\
\xa0\x7f.\x08`\'\xb4@\xc4,\xae"\x16(@d\xb6p\xa9f8\x84\x05\xfc\xb7\xcd\xf3\
\x82 \xd7\x1eod\x96\x96{\xba|\xa5 \xa3\x88!V6\xa2\xf7\x17\x08\x92\xe7\x0cy\
\x7f\xe3\xe0\xa3\x03l\xf1\x1f\x8bG\n\xf1\xb9\x90@\x180\x94\xf8\xa7\x9c\x17\
\x1cI\xbd\x0e\xe2\xb7y\x9f\x88\xbb\x1c\xc9n\xa1\x9eSlm\x92r\x0c8\xed\x00\xa8\
\xc3\x17\x1e\xaa\x00\x11^\x0b>\xe9mI\x0b\xa2\xa2\xeb\x8c \xcaPaN\x11\xe0\x1e\
b\xd1E\t6\xe1\x00\x9b\xf0\xbd\x0e\x17\x01\xdb\xb7\x86E\x9e\xef\x01\xef\xca=\
\x1b\x18V\x0e\xb4\xa7\x0cmb\xab\xf1x\xd6\x06\x0cM\x86\x04\x08u\xb4\xe1\xe9\
\x90\xb0\xf8cq4\x10\x0b}\x169,\xb5\xa7\x11@G\x96\x03@j$\xc9\xa7\x8ae\xf8\x0c\
\xfc>\xb8\xbedH~\x00+\x19r\xa3Xt\xaf\x1a\x8f\x14\xc2\xe0\xbe#{\xc1\xa2\xb3d\
\x05\xad\xa0s\xf2\x08\xa4\xbe\x0f\x07\xc0eG\xb6\x81P<\xcd\xed\xa0`8\xe1;L\
\x83\xe70~\xcc\x96\x8dR\xc5\x83\x83\x03\xc7\xe3\xcb_\x0c\\r\nZt]FT\xb9pw\xdc\
\x10\x0b\xb3\xa2\x8fM\x98L\x11M\xc8\xe13xVp\xe0\x8c\x11\xf4\xfb\xd8A\xa4\xb9\
\x07\xf2?\xd8\xb2\x17b\xd0\xde\xacQ\xe2GoVA;\xca(e/@2\xb5!\x1csH\xfe\xe7\n\
\x91w\xf6\x07i\x1an?y}\xaa\x08\xa6X\xc9\xec\xc5\xffD\xd8\xe2q\x9a\xc2\xe4y\
\xaf\xc8FiI}e\x9d\x8eW\xa1\xcd\x91U\x04\x97\xe6\x165\xde@\xf0\xc2}\x89\xe48\
\xe0\x0b\x06\xb0m\xe0#\x92\xf8\x8d\x01T.\xf4\xd3{\xba\x96\xe5\xba6\xec\xcaO\
\xe4\xda\x13f7\x14\xf8\x83\x19\x93\xa9\xe2/\x1f\x9e,\x0crF\x97\x8e]\xa8\x1b,\
\x1d|H\x87\xebXvK\x15\x7f[<\rPi}S\xf6\x82\x1bC\x8c\xa8\xe2\x8bl\xcf\x0co`\
\x1d\xb77{\x85\xa6\xd2\x94\xe4c\xb2S\x1b\x12\x97\xbd\xd6\x9d\x08\xb1h\x0e\
\xe8^\xd3\xd0\xc7c\xbe\xc4\xfa2\x05"s\x0c\x00\x95J.\xa4\xbe\xeba\xb2\xcf\x19\
\x1e\xc5:\xee\xc8\x83\x8f\x8d}\x8e\xa7&\x0e\x8b1\x0c\x89\x16\x8b\x9c\x02"\'\
\x98\x8d\x03\xf0l\xc6\x19\xf8\x90\xc9\x1fX~p\x94\xb8\xe5\xc8\x95L\x15\xbb\
\xa5l\x83fN\x0b\x11G\xe6\xdb\x82\xd3\x04\xb0\x02\x1b\x0e\xc4\x16C\xac<\x9cs!\
\x00\xcb9\xbb]JDW\x86|\x91\xed\xcc\x95\x8d\x02kM\x9e\xbc|\xe2@\\<\x00\xcaSd`\
aF~\xed~\x96B\xe7\xff\xce\x88*\x0b\xc2\xe0\x9b\x8a\xd8\xc9\x00\xb4h\x1d\xb6\
\x1ayi\xb3`KaX\x9d\x03D\x91\xf2\x1d\xde[M\xb6\x01\x9fR\x87\x99\x0c~\xfcV\x11\
\x9bg\xb5x\x01qS\x97q\x17\xb9J\x10^!\x84qW\x14\x17\x1d\xc5Pi\x05\rY\x8e\xf9}\
\x04B\x1c\xd9\x0b\xf1\xe3\xdc\xe0q\x00P\xf61\x94O\x10\x83\xfe\xda<Qx\xa2\xa7\
!\xc0\xed\xc3\'\xed\xcbm\x8a+\x11\x87\x16\x84\xe3\x90\xd1\xb6l\x8a\x0e1\xb7\
\t\xc3\x1b\x06\x88\xac.\x13\xac\xd1\x9dX\x08\xa4\x1eUX0|)o\x19\xe2\xa2\xe08\
\xf27R\x15\x06c{\x0cx6\t\xe9\xa1P\xad\xe9\x89\xed\x11\x04\xfd\x18Z\x8eI\xbbr\
\x92\x15`\xd0g\xdebc\xf0\xe3\xa5B\x8c\xcf\xc3\x16[\xd5\xe5\x13\xc4\x8f\x8c\
\xac\xf9\xa1\xef\xc0\x03\xaf(ptOp\xaa\x7fb\x9c\x12\xfbq\xcfX\xa3\xe7\xdd\xd0\
\x9f=\x81\x00D\x85\xb8:\xdf\x14\xbe#\x89\x9b\xa6\x1c\xb38!\x0ck\xbf.\xd4\xa8\
!yJO<\xccz\xc1\x1d\tG\x92\x8f%\xc5@\x8c\x1c\xc1\xc7\xccD|\xdf\xc7\x05\xb2\
\x9e\x81\xc9f\xbf\xa5\x12\xcai\xa0\'R\x86#\xf3\x85\xbam\\\x9a\xe8\xf3\x9d\
\x80\xaf\x11\xd3\x02IwH\'\xd0@(\xbd\xc4\xe4\x98\xe4\xa9\x9f\r\xa0K\xb9%\x00T\
\x05\x0c\x1au\xca\x03C,\xe9\x91\xfc\x96\xe9d\x80\xcb\xe7\xf3\xb4\xa4\x86\xf5\
\x1d\x08\xd2\xb5M\xd9\x0b-\xcb\xaf\xa5\x1c\x07\x02v\xb3F\x11;\xd1\xc8Xu}\xf8\
>\x17\r\xc0\xa3\x1c\x1c\xf3\x93P\xce-Ux\x04\\\x9a\xf8)n=\xefZ\xf2\t\xe8c\xb6\
l\x03\x10\x89)\xa0^>\xe6\xf6\x83+\xdb\xa0y\xd9\x9d\x92.\xe5:pC\x15]\x80Jr`Y*\
\x866\r`\xf2\x1c$\xc0\xe5XCb\x90F\xd2\xc1\xcd8\xc0\x9dw\x00+\xc8\x11o\xd8p\
\x00\xc2\xf2`\xdf\xfe-e\xa3\x18\xa9\xc2;\x1bb++\x01:\x1a\xc3:\xa9p\x015e\xb0\
\xf1\x18\x08Da\x02\x02\xae\x0e\x18\xf0\xc0\x05T\xe3\xd5\x82\xe68\x06\x0c\'6\
\xb9[l1\xb3\x91\xb8\x9e\x9f\x8f\x018\xb4\xc98\xcbz)\x1c\xdd\x03Zt\xf6x\x00\
\xe2^\xbb\xf2\thl\xb8[-t\x1a@\xbd\x88\x85\xc3\xc2\x07\xd4k\xd3\x05\x00"\xc3\
\x19\xf5\x9b\xfc\x85\x03\xdb\x87\xad\x9e3\xdeA\xa6Qp\xe5H\xa1*0\xaa\xc2\x83\
\x1f&\xc0\x81c38\xdfC\xc0.OaG-\xa8\xe0i\x06,\xdc-\xbd"\x94\x07\xc4N\x9e\x811\
\x12Z01h?\x06p\xc9\x87\n\xb7\xac\xf34`%\x7f\xa2q\xd8\x19_\xa8\xebP\xa4\xd9\
\xf2{p\xa8\xbe7\xb0\xf8\xf9\n\xa2EW2\xdd\xfe\x18\x17.7K\xa4s\xe0D\x0bk\x91|\
\x85\xa8\x9d\xe8\xf0\xb0Z\x90\x0eq \x9f -G\x8f\x01\xc4\xe8#6\xdfn\xe1$d\xcc\
\xd5o\xba\xbc\x91:\x03x\x9d\x8e\x02r\xa9\xd5\xff#[]\x87\xc4e<\xffn\x04\x9c\
\x01\x83\x05\x8ft\xd9-\x90\x08tD\x17V\x06\x8f\xb3\xee\xca6\x10\xf43\x81\x0f\
\xb2\x01|\xac\\H\x07\x8fU\x16\xda\xfb\x960\xc5pG\x93\x93yHW\'\xa3\x19XstJ\
\xd9(\xa0\t\x01\x10D)_\x98\xb2\x80\xd9,\xfap\x0e\x93\xd8\xf2&\x0eB\x8b\x87\t\
!\x00\xdc\x1c\x1c\xd3\x01\xe6\xf0\x19zo\x07\x88\xde\xf7ph\x1d\xc7\xb2\x17j\
\xe3\xc0f\x9eB\xe2\x06\x14GN\xc7|\xbdc\xcc!=\x1b\x97\xcf\xdb\x1d\xd8\xd9\x19\
\xf4 eF\x1cp\xe3\x0c\x8f\x12\x9aac\xbf\xfc@n\x86\xb1\x85+\x11\xdfb90b\xf2\
\x11\xed\xfd\xf1\xa4\x8f\x8b(\xc7\n\xd2\x8e\xb0\x13\xb2\xe0t\x0e\x9c\xbbc\
\x91\xf7\x0bG#\xb7;\xc0K\x15|c\xa8\x04>\xc8a\x9cc%\x9f \xe9\xf0\xcd\x91\xe3\
\xa0\'\xa6\x1e\x04\x1b_\xbcx\xd2\xb1\x1b\\\x9c\xb7\x8b\x1d\xe0Pl\x9c\x95\xef\
\x81\xec*,T\x1c\xcc*\x80r\xadx\x1c8\xc5t\xbeI\xce\x92NG\xb8\xa5`\x8c\xa2>{\
\x05\x19SF\x88{\x0c\xb0\xb4+\x13\x99[8k\xc2\xa6J>\xd8\xbc\xc0}\xe4S\n\x94\r\
\x84\xe5\t\xd7^\x07\xc0\x14v\xed}%\x7f\x90/\x15\x92S\x0b\x82m\x82\xb3r\x81\
\x01\x98\x19\x9c*\xbfB\x8a\xbey\xec\xeb\xbbq\xe5Hq\xcbw\xd6hN\xf8dK\xbeB<uG\
\x10}\xecw\xf8\x04[\xbd\xc6\x11\x90\xd8*\xe5H\x01\xacg\xa0\x9fL\xe6A"G\xc8\
\x068eo\x13\xf9\x04\x80K\x88$\n\xc5\x001>\xc6\x18\xf1}\xc2\x1bDE\'=\x84\xb0\
\xdeu\x01)\xcaa\xf2|\xd4\xb0M\xfb8\xe6]\x03;\x9b3/X1\xc2\x93\x1c6v\xc8\xb3\
\xe9x\x8cp?!\xd0\x91Sx\xd0\x0c6;\xb2\x17\xaax\r$\xb5T\xd1m\xf1\n\x82\xfa\x15\
\x9a\xb2[b\xd0\xb3*\xdb\xa0\'\xba\xbal\x03J^\x89\x108\x83\x05\xd78w\x87\x05\
\x19\x14\x11<\xcaI{\xf0\xb2\x9cU\xfc\n\xc4\xc5\x0exjs\x14\xf0\xae\xcb\xaf`Y\
\x1a\x1e\xcc\xfb\x02\x8e\xbbuSV\xd0\x92\xca\x01\x9c.8\x1fJ\x01\xf0\xb5P\xbf\
\xa0\x07q\x86\x10\x86\x02~\xe7\x10V\x0f\xce\xe1\x9f6\xd2\xc1\xb0.u\xd0\xe2M\
\x88[\xbe*\x83\x9f\x06\x00?\x05\x16L\x1e\xde\xb7\xae\x07\x81\xd2\x87B\xf2\
\xc9\x04\xc6\x88\xd5\xe2l\x04\xb0O\x06\x16~nF:\xe9Oz\xb0\nl\x88\x1c\x8f\xcd&\
\xad\x85\xf3\x85\x91]G%\xb6i\x0ej\x7f\x92L\xae\xcfF\x80\xe3\x02\xc4\xf8,\xec\
\xb9\x03C\xf6B+\xe8W\xcc\xe3\x80p\xbct\xe4\xbc\x10\xf9\xd7\xa4|\xf7\xc6\x9c\
\xab\xe2\xd9\x81v\x91\xc3z\xddg\x00\x04\xa3\xc2\xfb\xa4\x18\x89#\x1b\x06\xde\
\x02Y\xf3=g\x82H\xc0\x16\xa3n\x18Y\xee\x90\xb2i\xa7)t\xedW\x001\xfc\x02[\xec\
F\x85\x1d\xe5\xc2\xe4\x99\xd7pX\xa4x\xe2\x94\x8f\xb51\x18\xb4\x1cs\x88\x02\
\xe8\xc1\x96\x0b)\xe5Cc\xcb\xe1\xc8\xccml\xa0\x9dX\xb6\x81+"t\xf0\xa5\xc2\
\xe2#\x06-\xaa\x00-\xf2\xcd\xfa\xaf\xb6\x9c\x06$X\xd2e\x05\x92E\x91\x9br\x98\
q\xe6\x16\x8b\x8f\x02\x8e\xbd~\xaf\x10Wg\xb7\xed\xa3\x83H\xb3\x8d\x83\xef\t\
\x11\x9a"\xb3\x91\xfb\x87}\xb0\x05$\x8c\x0f\xa3\xb9\xef#\xf6\x1a3\xc4j2A\x9c\
p\x8a\xd0b\n\x85$K\x90\x88\xc3\x86\xc4]\xea\x00\xec3\x81\x8b\xf1\x13e\x90q\
\xebB\x1a\n]v\x9a\xb8|gu\x0f\x9bPh[\xc0\xd1\xcf\x9e\x80c\xb7\xc5\xfc\xc0\xfd\
\xca\x15\x15\xd2\xc1\x83\xcaR\xd1Z\xf7\xebB\xe7\xbe.\x9f\xc0-_E>A\x0bf\x89\
\xb1\x81,\xa4\xb7\xe4+8\xf8\\SV\x00\x955\x1b\x07\xb10\xae\xe4\x13\xc4\xb1\
\x1f\x1a\x1c\xcc\x03\x04\xdb\x16\x19\x92\xc8\x01\x99{\x8d\xcf(`\x8bW;\xccST|\
\xb5$\x0b\x89\xc9-\xd2\xe8\'\xe3\x14,|\x88\x80u\xe2\x88\x95\xc6\x08\xb31\xdc\
\xe9\xa9#\xdb\xa0\'\x16\x1c`\xae\x18x\xd0J\x80\xec\x1a#i\x95\xa7\xca\x81Q\
\xc5\xc7J\xce-dr\x82d@6nN\xff,!\x0b\xfb8\xf8\x1em\xd9(n\x0bN\xb1\xc5\xc6\xd8\
b\x19\xe7\x0f\xe2\xcb\x81\x7f\xba\xb8V1@\xa8\xe472\xc8\xb8\x03 3,>\x92\n`{>\
\xf2I\xc8F\xd1\xc7\x91\x1c\x07=\x11\xd2&,\xf2\t0\x02\xb6\x07$B\x86\x83o\x95\
\xec\x86\xf1\x801h\xaf\x15\xb0N\xec\xeb\xdbV\x801\x9a0\xda\x85\x0c\x9at<\xec\
SE\xcfB|\x9f\x01T\x8b\x14L\x11\x87\x07\x16\xeeu\x89 (_\xdb[f\xa8F\x06\xa8FK\
\x97mP\x85\x1fJ\x06a\xad\x07\xb2\x82\x96\xf6i,_\xa1\x8a3h\xd2\x0e\xdbb\xef\
\xc8e"4#\xa8\x1b6i\xe3=\x99\x08\xec\xd5\x01\xe6\xca\xc6\xc2\x8d\\\xd9(M\xc3\
\x072\x13\xc6\xee\x10\\_1%?\x80Pe$\x93\x07{?\x9cU\x00v\xc2\xf8\x8f\t\xc3M\
\x15\xf9\x04\xad\xa0\xd76.*\xf9\xb0\x1b\n\x1d(\x02No\xf1.\x84;\x9d\xd5\xd1^)\
+h\x05\x9d(\xf2\x15$\x9e\x88\x01~\xe2\x94\x87\xbb\x94\xf4.\xcb\'8\xc5\xb6\
\x12`\x04&\x80W*\x14\x14\xf6\'6v\xb6A\xb0\x824\x1b\xe3"\x8a\xeap \x04\x07\
\xdfO\x97\x17.\xebRmd;\xc9\x01\xe5\xf1\x19R4A\xac\xe0\'\x87\xe3\xfa\xf0\xa1\
\x18\x8c\xcaJq4\x06\x0c\xb2\x91i\xbeb\x827\xf8}(W6\xdcr\x83\x1c\xe6\xec\x1bA\
\xab\x1d\xaf\x0f/\xbe\xd1\x014\x81\x1d\x88k6\xc9\x8f\xba\x90\x0cb,>\xbb\xb2~\
\xe8L>Gh\x12\x92tE\x0f\xe6\xec\x11g\x08q\x00\x04\xfdc \xee\xe1\x81\xc9\xc7\
\x96l\x83\x9e8/\x99\x16\xac1\x97T\xc9&\xc2M\xc7I\x0ci\x99C\xfd\xda\x03\xd4K(\
y\xb8\x06=c!Ux\x86l\x94v\xf6{S\xbeB\xcbr7A\xc4\xbb\x8f\xdb>O\xb3\'h\x9d\xbe\
\xb5!\xd8\xfap\x99h\x81l\x14^|\x8a\xf2\x0c\xc6\x8cs\xccu\xc9Sd\x91\x00\\\xbd\
\x18\xe38\xf9\xc6\xb1\x13\xce\x88\xd1I\x90^\xab\x0f\x98\xe7\x01+\x8a|6\xdc\
\xabd\xad\xf5\x0b\xac1\xa5\r\x9cA\x1f\xcaD\xd0\x01b\xc6\x02\xb5\x1f8\xa7J\
\x1f\x87\xc5wx\xbf\x86|\xb7\xa9\xad\x00\xf8X@\xfb\xcc\x19R4\x81\xfe\xb15B\
\x1a\x16NH\xd6W\xe5+\xc4\xa0?\x0c\x80\xe0\xeb\xc7\xa7|\xa7\xa8\x87E\xd7bD\
\x15\xbbK\xd78\xa5\x0c\'\x13\xebq>%\xbe\x94\x97"\xc0-3b< -\xcdp\x00\xdda~\
\xf6\nUh|\xc3\xdf\x82\xed\xf13\x06\xde\x81\x95\xcd?!\x8cw\xc6\x19t*\x9c\xa6\
\xec\x0b\x9e\xf2\xed|\x0f\xdes\x83n\xa6\xf8\xc3\x1c\x8e\xaa[(\x02\x16\xa7\
\x93J\x1c\x08\x94\x02"gJ!_Kf\x91x\xc2\x19%\x14C8w\x14\xa0\x198k\xc2g\xbe\xd1\
\xee`\xe1\xda0\xbddZ\x89\xb6-\x1b\x85\xdb\xb6\x02\x8a\x80\xef\x01\x7f4\x00mb\
\xd0\x91n\xb1\xd4\xa6C\xeb\x9f9]V\xd05\xb5_\xae|\x05\x0b\x97\xe6\xa5\xf0}\
\xdc)\xfaY\x01c4\x01q%4i\xd1-b\'\x9cq\xc9\x83\x16<\x84&\x9d\xb9\x8c\xc7\x8d\
\x801J\xe1\x93\xbe\t\x10{e\x90\xde\'\x0b\xfb\x85\xa3+\xa3\x12>\xfa\x0c\x0c\
\xfaQ\x01\xb9\xe3a\xab\x97\x80h\xd6\xce\x1cZ\x1f\x1a\xd4\xc0\x0c\'\xd0#\x07S\
\xfaX0y({\x81\xbd\xaf\xe2\xbc\xcdp\xaa/pr\xb5\x0c7\xfd\xbes(>E\x08\xeb\xb7\r\
\xa8\xb9\xe5\xd2\xde\x7f\x9b\xca\x91\x12\x0b\x15\xdab\xde\x90o\xa6\x1c\xb4\
\xe5\xd0\x11\xae5\xe5+\xc4\xe4\x1f\xb1|\x027\x97fO\x0ch\xa2pf\x8f\xf9\xcc\
\x8eG\xfc\n\xe6e#\x94\x15\xb8\xe9\xa7!\xbb\x87\x8d\r\x14xH\x9f4\x86\x0f\xe5R\
\xe7i\x00B\xf5\xde\x91\x93\x8d3\x1b\xb4\xb8)\xce\xa8y\x9db\x8d\xbe\x8d\r\xf4\
@\x1a\x8a%\x94M\xa4\x91\xe4|J}($;#\xc4\x80{\x8c.\xb5\xb0+\'\xd0a.m\xec\xca\
\x14\x1c\xdb\xafd\x1b\xc4\xa0\xcft\x00\x8f\xf3\xb1\x87e\xa9!(<D\xd0\xef3\xef\
\xdb!\xf6\xad\xeb\xc8^\xe0\r\x9c5J\x9bp\x89\x8e5k\xc0\x16\xdf\xc0\x00`\x88\
\xf3\xa0\xbd\xb3\x80\xfdr\xb1\xb4;\n\x0e\x0b^t\xfb\x86l\x94\x16\xdd\x83+\xbb\
\xc5mAN\xc3\xe2s\x10\x94s\xbb8l\xab\xb7\x91m\xad\x80\xe6\xf8\x82\\72\xe1\xc3\
N@\xb7l\xc4\x11EO|\'Y\xe8\x16\xec"\x189\x00P1\x8a\xa0\x9cuK\\Oh\xe8\xc2\xae\
\xc6}\xd3%\x00\xc93>\xd53\x086\x97\xfdt\xddP\xf2\x838vAk=+x\x05]\xcb\x91\xb2\
}\x8b\xec/\x1e\xebA\x07\x0e$\xdd\x00\xfbv\xaa\x02\r5\x81\xf9vE\xf1\x97L\xecA\
\xa2e3\xe0\xa1\xf3\xf5\xc1X6\x8a\xab\xa1p\xdd\xf4\xd9\x16{a\xacB\n\x0c\xfcH\
\xe7W\xe0a=1\xb1\x91\xf9\xa6\x9f\xd5\xe1\x15\x045\xf0\xa3\xcb\xfb\x05\x91"\
\xdf\x83\ng\x03\x84\xf5\xd8A\xd0\x8f\xb37\\\xc4@2q\xf6\x06\x17Y\x9b\n\x0e/|\
\xabd\xb7\xb4\xc5n\x18\rU\x002\x92\xb2Ym\xc3\x16{\x9b5\nS\x83\xb3\x02r\x06\
\x88\xd8\xe2\x03\x07\xbdx\xb3n\x89\xa7\xe7\x9c\xe4\xcd\xc5\x92\xda\xd1qXp~\
\x87\xf5Y\x1bp\xfc{\xe4\x81\xaf\x0b\xed(\x13\xc1\xe9>\\Ho\x01+$p\xfdf\xa1\
\x1c)\xe6\xc5\x91\xbd\xd0\xae\xbc*\x11\xd2\xe3\xc4h\xaf|x2\xf0`\xdb\x04n+\
\x87\x8f\xeds\xc9\xdd\x02\xec\xf3\xd1\x92\xe4#m\x91\x03\xe18\x81\xa4\xf3\xc9\
U1\xcc\xc6pU\xb4g\xdd"WV%\x1b\x05\xa49\x92s\x8b\x99\xd3\x90u%\x87^xc\xc9\x99\
C\x88\xd3\x92\xaf \xc3\xa1){!\x16\xfe\xe4\xd8+gM\xf8\xa3\xcb6ps\xda\xc3-\xce\
!4\xfa\xc1l\xa4\xc4\xe4k\x85L\r\xbf\xef\xa2B\x05~,\x87n\xf9\xd9\x95mP\xc5:y\
\xbf\xea\xdb\xd8\xf0}r8\x9f\xb5\xadKz\xc5\xeeO\xa0mM\xa7\x80\xd0\xf8X\xfc\
\x01\x9c\xd49\xa7;\xfd\xa9\xc26eL\xef\xd4D^\'\x1bG\xe3\x0e\xe3\xa5\n\xa8\xc5\
{\x0cJ\xb3\xb1\xe8\xfe\x98\xb2\x17\\#\x98"\xe3\x92\x8b\xd8|\x1f\x9e\xef1\xfb\
`+\x05AaN <dH3cz\xbf2\xc6\x88\x9d\x7f\xbf\x18\xa8\xc3\x98\xef3\x07\xa6F\x01\
\xeb\xe4\x9d\x1c\x07\x16L\x90 \xaf\x13_0\\\x0ee\xa3T\xe1V\x08\xa4Z\xd0a\xfa\
\x1d\xd9\x0bU\xfc\x01\xd4\xab\x18\x00\x0e\xf4\x05\xb2\xd0c\x05m7\x94\xddBa\
\x85\xf2\xed\r\xa0|G\x94\xb3K\xact\xdc\x07\xb2T\xc4\xa29xp`\x01V\xc0\xc9\xd5\
Vq\xf7m\xd8\xe7\xadnB(\rp\xde\xbe\xb4ax\x0f\xb0`R\x06/p\xf6\xdb\xcf\x90\xb89\
\xc7oo]9R@\xf0*\xdc\xf0w`\xae<B\xff\xb0\xf8\xb0\xb8\xa2\xd8\xeb\xa4\xc7\xd0\
\xd9M\xdc\x8cu\xf9\xd2\xd5\x8a\xce\xeb\x03\xa7\xe9>\xe3\x838G\xc4\xdeH\x0e\
\x1d\x80\xc3@>\x81$\x1a\xb1\xac\xc0\x8e\x8a\x81\xba\xe1\xc3b7\x06`\xc8\xe7d@\
6;\x11P\xf1\xd7EV\x9e\x02i\xadL\x13X\'\x8ei\xdd\x92f`\x89S\r1`N\x91a#\x00\
\xb1@\xd7\xe5\xc4\xf6\x81,|\x1c\xc9q\x10\xc7\xc2.\xddM\x18\xf2\x813\x01\xc7\
\\\x8e\xe0\x9dP@\xb7W\x17\x1aX\xc0\xe4#"\x113\x8a \x83\xe8\xbbd\xd4\xef\x00\
\xbb\xb2\xd2\xe5+\xc8\xdd\x11\xcaq\xc0I]\x01\xa74\xe4\x14\xf6\x14\xf3\x9c\
\xf4=\xf8\xc7\xd6\x03\xf9\nM\xd4\xeb\x14\xf7\n\xf8.\xe0_]>\x01\xf1i"\xde`\
\xc1\x97\xf3\xdb\x90\xbd`\xab3\xcc\x93\xf5\xc2+S\xd2B<\xb5K\xd9\x06\xb10P\
\x10\xb1\xeaa\xe1v\x19\xeb\xc4Y$\x0c\xbeE\x91c^\xfa\x0c\xa0\xe2\x1b\x87\xab#\
9\x0e\xe0.p\xd1@\xe6ts\x19\xeb\xc4)\xdc\x8e\xe0\xcc\x98\xb0\x96S1^\x8a\xb3j|\
e\xe0\x12#3\xde\x14I\x0b1yY\xaa\x1bp\x96\x7f\x02xR"\xed\x8f5I\x1cU\xfc4\xe4+\
TQ2\x92)\xc7\x19\x15R:\xcb\xacN\x00K\xdd"\xa5\x8c\xd0\xd7a\xf1!|\xed\xe58\
\x81\xdeE\xb2Q\xaa\xf8\x1bK~P\x859\x02D\x82#E\xe3\x98\x0fOT\x0c\x1c\xf9\nU8\
\x8c\xb9\xb2a\x12o\xce^\xa1\n\x7f\xf6\x04\xae\x99\xa8dz\x15.\xd4\xf3\x88SA\
\xb1\x8d\xec\xa1b\xc8\xb7\x16\x07\x01\x0f\x1db<\xa1};\xf6\xf8\x1eN\xce0\x0bv\
\xfd.\x8c\xe4+T\xb1\x1aS\xc6\x03\x99(n\x9e\x81\\\x13\xcc\xcb\x1d9U\xec\x9c\
\x81\xf5=J\xf6"\x8e_\xa4o<\xd7d/\xd8/\x15D0\xdf\xf6\xf9I\\\x1f\x16\x13\xe4\
\x97z+\xc9(\x12F\x00-~\x87!V\x16X\xb8\x87k\xe1\x03\xbe\x16nvd\xa3Tq\x1c2\x0b\
\xe1\xc9{h\x03w\xc1\t\xda\xf6d\x05\x0c<#\x90#%\x06uH\xed)\xbc\xdc&jKG>\x01\
\xfcX$\xbb\xc5%E\x8a\x9a\x17\xde\x10\xd9oG|f\xb3n\xb9\xde\x01\xb6\x87o`\xfeh\
\xe1\xb0\xe0\xfb\x95\xb7|"O8\xbbz\x05\xecF\x0f\xd8\x8d\x0e\x94\xbc\t\x1b\xab\
\x17\x1a"xC\xd0\xd2\xf2\x00\xf6\x19 \x13\xd6\x95\xec\x05sk\xc6\xf2\x15\xaap\
\x0cY\x81hS\x08\x08\rG\xbc\xff\x92;\xdd\x16:?\x8c\x91Y\xa3@C\x99\xd8\x95.\
\xf8qJ\x17/\xc6\xd2m{\x1fAJyP\x14\x0fc\x00\xa88\xd3\xa2c\xcaq\xd0\xecW\xa5l\
\x14\xd1Y\x15\x18\x81\x0c\x87\xf8\x83\xc5\xd3\x00i\xb9\xc3\xa9mX\xb5\xfe\xc8\
`\x8e\x1e\xa4eQ\xc9^0\r*d\x10\'\x00\xbd\x05rx\xe0cW~\xd6\xe5\xcc\x01\xf3\r\
\xaf\x93\xb0\x82\xf0\x01\x83@6J\x15{\xa1|\x85\xa6\xf2q6\x0e\x9a\x17%\xe1n1s\
\xc7\xb3F\xe9\t\x97S\x0eqJ\xaa%\x84\x9e\xa5F\x7f;{\x05\x190)\xc4)\xa44\x14\
\x81S\x95\xf9\x01\xae[#9s@c\x93\x18w\xa5\xbe\xfe\xd6\xe2=\x07\xafd\xe9!5\x96\
\x07\x85\xb5\x0f\xac\xa4\x846Et\xcee)_0<m\xb3-\x86\x89*\xc8\xad\xef\x8d\'c\
\xe4\xc9\xd3\x90i1u\x10\x7f!u\xc3\x9d%\x15\x81`\xf3db\xe76\x96v\x0e~\xd8\x0c\
\xd3\xf2\xe0\x88\xe8\x84\xbc`Pa\x93P\x9a\xe4>\xc0\x1cA {!\x8eM9|\xcdF\xd1J\
\x04D\x04{zKF\x87qX\xf0\xd0\x91\xbdd\xe4S\xc2\xf92\x18\xa6n\xe3S\xd2\x80\xe8\
\xf6} \x11\x0eY\xfdJ\x11\xb1:d\r\x96\xef\xbf\x1ci@\xc93\x00\xd3`\xe8\nk9/\
\x0e\xc4\x16\xc7\xf8F\xfc}\x0f\x07^\x96\'rc\x0b\x11\r\xa0\xdf\xcf\x00\'P\x81\
H\x80\xcf\xb8-V\xcf\x8fU\xd9\x06\xed\xec\xcfp\xfe\x8d9k\xc2\xbe\x14J\xf0LD\
\x9c\xb4\x8a\xbf\xed\xa32\x90\x8b\x93!op21v\x1f\x1f\xc5\xf2\x15z\xe2\xb0\x03\
\xac\x02g\x08\x89*\xd9\x06\x04}W\xf2\x03\xeeA\r\xa1\xd6\x01\x0c\xbc#\xfe~\
\x14\xeb\xebc\x06\xd9\xf0\x9d\x80\x97Y\xb7\xc8m\xab\x03\xfc\xc4\xd9,\x1e]\
\xb9\xa4p\x83\x9b4\x83\xbe\xccC\xb2\xc2\x01]\x1f~\xdcA\x17`0\xbed\xf4c\xd6\
\x060\x9bSlu\x17[\xfd\x02S\x99r\xf2\x9bcC\x92OO\x9c\xc0\x03\xdf\xef\xfb\xf4\
\x84\xd5\xc2\x89<\x9e\xe0\xab\x08S\xe4v\xe9\x01\x12pk\xf3\x06B\xe4l\x93n-6f4\
\xbd\xc2\x89\xc0\x18\xb3y\xed"\x04\xce\xd7K\'%\xb0,\xbd\x14nl9\xd9\xbc\x92\
\xf9\xe2\'\x7f\xa5\xea\xba-\x89\x03\x83:\x88\x9c9\x10\xc1\xcf!\x94+v\x98e-\
\xd9-\x04l)\xdb\xa0\x8a+\x83\xaed\xd6\x85\xe6\xa5++\x90J?\x96\xaf\x10\x9379K\
Q\n;\xca\xd0\xf8\t\xc8\xd3;\r\x1f\xa5\xca .\xcc\x16/\x871\xbeE\xd1Ez\x9c\xc2\
\xb1\x1aj\xf7#\x9c/\x9c\x16\xaf\x17K\x16\xe2\xfe\xcbH>A\\w\x03@\x8a\x1c\x9c\
\x95K\x81|\x05h}\x03"\x98S\x1e\x8eg\xaf\xd0\xbc\xac\xc4@\xba\xb9\xfcm0\x0f9D\
\xf8+\x11\xeb\xb6|\x02\xa9\x9f+\xb9\x1cp\xcd\x95Az\x8c.=\x00\x88"\xe7+\x00I\
\x85\xfcAl&\x1c\xda\x92|b\xb2\xcf\t\x85\xd8g\xf0\x17\x0bW\xde\x8c\xbd\xc4U\
\xd9:\x8aAG\x01\xef\xb9\x0c\xca\xc4\x9a\xc1\x03\x83\xaa\xf0\x89O1\x1f\x97\
\x15~\x9a\xc0\x18\xf5a\x9b&\x9e|\x05\xe9\x1cB\xd9(\x8c\xf7\x08\xc9M86\xbf\
\x1c\xc8\'`\x03\x85</\xf0\x8fe\x18\xba\xcdf\xb5\xce\xb05\xfe\xa4\xd0\x05#C\
\x19\xf6\xaa&\xf2\t\x1az\x8b\xbf\r\xe6#\xba\xb2\xd3\x95\x15p\xb9\xf2\x07\xa5\
<\x867\x8cp6\x0c0Q7dG\xf9\xfd\t\xae\xfeY\x16\x8bq<\x113J\xcdE\xd0/\x98U\xd0D\
](,\xfa PJ\x13;\x8a\x9d*\x8a\xc3!,D\xcdO]\xc0\xd6|\xc4<#\x86\x9c\xf1\xb7\x8e\
68\xf1\x95\x8b\x94\xfe1E\x02\xd2\xc2G\x90\xfc/\xc3\xa3&8\xd5\xbf\xf1\x87\xad\
8\xa9\xc82\xe5\xdd\x18\xd7\x854\xb6\x04\xa1x\x0fw\xdf\xf6:\xc0L\x0c\xb1o\x87\
\x01\xc4\x85\x0f\xa5\xf7\xba\x8b]9\x81O\xe9\x90s\x88\xc8d\xc8\xae\xec\x16\
\xa8NF\xa9\xb1J{\xc1\x9f\xbeb\x95\xd6\xc0\xb1V\x17jT\xe7n\xf1\xca^%\x89C\xe4\
,\x91\xaf\xe0$\x8cd\xa3\x88Y\xb4\xb1\x81X\x83\r\r\xf9\x04Ul9\x88\xcd\xf3G\
\xfe\x169y\x96\xdd\xc7\xfd\x06\xba4!\xc4+\x0c\xefXA\x80\xdb\x87O\xe9\xc4\x92\
\xbdP\xc5\x84Sc\xf1W"\xd2\x11fn\x00#\xd1\r\x81\xbaae\xf3\x8a\xf3L\xb0\xb2\
\xd9\xa3\x1b\xfe\x13\xb1\x07\xa9b\xc2\x8b\x9f\xad\xc6G\x03P\rN\x08\xe2\x04\
\x88\xe0\xb9p\x88x\x01w\x0beb\x97|l\xc3\xcc\x81\t\x98\x92\x8bq<\xc9\xa1J^sZM\
\x96c\xc7th\x15u\x86mZ\x0e\xb3ni\xef\xabd\x13\n\xa9\r\xbd\xf0n\x84x\x83\x0f\
\xb7\xed=\xee{\x14\xec\xe8^eE\x91\xc5\xd6W\x05\x92\x7f\x82\xfcR]\xfe\x90\xe4\
\xd8\xa7\x8a\xdfm\x84J\x06\xfc\xd5\x0c\x03\xd1j\x06\x83u:\x80\xe1p\x9a\r\xd7\
\x92#\x85\x07\xcd\x813\x83\xb7z\xca\x1f\x81d\xc7\xbf\x19\xcaW\xa8\xa2\xdb\
\x01\xb2\x8bs\xee\xa8#\xd9-\x0e>\x0b[\x9d\x93w\xb6\xa7\x80H\xf0\x87\xbe\xbe#\
\x83n\xc1\x8e\xaaa\x1bP/\xce\xaaq\xc9\xb7k\xf9\x16\xf8\x11\'\xae) \x93U[\xbe\
BO\x84#\xa4\xd7b\xf0\xe4\x91%\xbb\xa5\x8ao\xf0\xb0\n\xbd\x10\xf7=X1\x9a@S\
\x1az\xb2\r8\x10\x19c\xd4\xc7T\xaek\xf2\x15\xa4\xb5\xe2\x8ftq\x9e\xde\xf3\
\x18+\xd9\xc7J>%X\xa3\x9f\x8f1\x95\x8f\x08P9\x8c\xe7\x1fp\xe2+\x17\xcb\xf2\
\x8e1W\x9cw\xc3\xe7\xef\xcf\xf9\xe0\xd8\x1ag\xb2\xb1\xe0\xcc\x08\xf8\xebr)\
\xdf\xf5\xe2\r\xe4B:\xec\x84\xb2\r\xa4\x1a\xb4e\x05\xc0\x82\x0c*\xf1`\xef/\
\x84\xc8\xa7\xc4\xaaS\xe0\xcanqI\x00\x11+a#\xc3\xa1\xca`0\x07\x07\xdfwS\x0e\
\x0c\xb9\x18K90b\xe1w\xba\xb8U\x14\x19\xe4\xc7\x99J(\xa4\x82\xb37\x0c+\xd9\
\x06t)U\xbeB\x15\xc7\xb3q c,\xe3Os\x88\xf1{\xce\x7f*qJ\x0cm\xe2 \xf9]\x87\
\xe7\x16\xb6\xe9\x16\x89-\xdb/p\x91\xbe\x17\x01:\xcbhJ\x93?\xc1\xc5\xceP\x9f\
3a\r\xa0\x9f\xde1\xd4\x8bS\xa7\x8d9O\x8d\x0f&?\x94r\x1cD\xfe!\xc3\x92\xf8\
\x1a\xe3\x0f\xe4b\xcc{\x90\x96\x9b\x0e\x00\xbac\xa8\n\xc7\x11\xbf\x02ZnB\xec\
\xec!t\xcbkS>\x81K\x02$r\x062\xfb\\\xa0\x01\xda\xc4\x17\x0c\x1f\xe0\x92w}XZ\
\xde\x149\xaal\xe8\x0e\x15_\xfa\xe6\xef\xf2l\xc8\xa1s\xfeS\xc4\xe7\x8a!\x14\
\xc5!\xbc\xb4>\x7f\x97\xe7]\x02\x9c\x92\x8f\x15tJ\xc1\x94"\xe5t\xeb[\xb3^\
\x90\x10$\x01\x021C\xb4\xfa\x8e\xbf\xda\xc5\xde/\x85q\x17\x9c\x1e\xf8\xd5f&\
\xc3\x9d\xbeM\x17\xd9\xeaT\xaepUD@2\xf17\xa8n\r\xd9(\xe2\xd9\x1cju`Ff\x90\
\xc9B\xc6\x00\xf9\xe7J\xf2\xa9\xc2s!\x83|l\xc2e\x92\xb8\xae/o\x84\x10D\xc2\
\x1f\xa76\xbefB\xf2c\x92\xf27\xdb\x9el\x80\'\xc70#\xd7\xf9K$}H\xdc\x8f1\xae\
\x00\x14\x80F\x9e\'|ha}|\xe3\x0c2Ch(#\x05_d\xe3\xef7|\xc0\xd7\xf62\x1b\x15\
\xdf\x03\xd9\x0bU\x04:\xf7\x02c\xe4\xd6\x92\x1c\x83\x91\xa8\xcbW\xe0\x99\xe0\
O-x\x88\x9aor:\xa9\t\xb4\x8bU:\tE\x0b\xf0\xa0e\xa4(\xda\xf9\x10\xba\xf6F$i\
\xa1\'~0\xaa\x82\xbf\x91\xda\xb5y\x1apD\x8fg\xbd\x10\x93\x87\xb3^\xa8\xc2\
\xeeP$\xc0\xe2\x94T\xdf\x19v\x92#\x14\xbf\x81+\xcc\x13\x0e`>C\xed\x19\x0cag;\
\x1a\xa0\t\xf8r\xf1\x9cgI\x16\xc2jtd\xa3\xc8\xab\xe0\xc8\'\x90\xde\x13\xdf\
\x06\x93\xe9\xe8N4|\xee\x85\x13\x82lq\xd2*\xbe,\xe9\x97@e\xf1W\xa9w\xa0\x07\
\t\xcd\x19\x15\x11\x90\x19\xecP\xfdR\xca\n\xdc\'T\xf0\x05\xb2\x1c;\xfbP\x03\
\xb2k\x00\'\xd3q\x80\x8fA\x15\x98\xca\xa5\xa9\x1c\x07M\xe5\n\xe3\xd88e\xc8\
\x86&i\xc1\x9d\xf7H\x8e\x94^\xd9S%\xc7 >9W\x96\xc7\x1f<\xe5\x1b\x10|\x85h\
\xe0\xca^`W\x9a\xb2\x17@\x12\xbbr`\x98JW\xd2\x82\xa9\x9c\xbd\x82KW\n3\x19\
\x88\x99\xf36"\x016|[\x9fY\xe4\xb8\x109\xd3\x11\xbe\r\xc6\xc1\xfa\xb6\'{\x81\
1\xc2\xb9\x7fl\xe4\xbb0a\xbeel\x9cm\xa3\xc2\xe1\x13\xe8\xa4\x8d\xa4\x11\x05t\
\xba\xbd\x08\x10\t\xfe"\xec3I\\\xb7\x9f\xe2\x93\xa8\xf3\n>\xc3\xc3\x1c\xfb\
\xa5\x01f\xd1\xc3nx\xe7 \xe7\x8e\x83\xfd\xf2JY\xce\x8a\xdc\x01\xa8$\xc4\xc7\
\x8ee\x1e\x92{\x1d\xdfL\xe1KW\xd7|\x8a\xf1\xa5\x9a\xc0\x04~\x8c\xf3n\\\x91Sv\
8p=h\x9f\xc8\x05-\x0cmZ0\x87#90\xaaX`Cb\x0c\xc3\xfb+\x9f/\x13\xcc\xedgG\xbe\
\x02\xae\xbb\xb2[|\xc8iV\x81K\xdf\xfc\x91.\xce\x15\xaeG\x00\x94Y\x10\xf4\x1e\
\xac\xd7\x94\xb34\xc7|\xc3\x9fCG\xdft|\xe2\x91\xf3\xe4\xad\xb4\x01\xf6\xe1\
\xcfx-G\x08\x1d\xf1e\xeb\xd56v\x14\xc7\x81\x02d\x03.2\x9cs\xcb\x16t\x07\x06\
\x93\x1eqJ\x19\xfe\xde\xbc?E\x16+\xfe\x08\xb5\xaf\x02\xfb\xe5\xc2O\xb7\xab\
\xc9^\xa8\xa2\xe4\x0f}q\x02\x0c/\xc2\xa7\xaf\xf82\xcb\x9a\x06 \xd7\x04G\xa36\
{\x85*>X\x92AH\xceh\xcb^\x90\x12\x93\xb1_lXm\x86\xf2\tZ\xa7\xfb\t\xf7\x82\
\xeb\xc7\xab\x81|\x82X\x98\xe9\xb2\x17\x04\xa7\x19T\xc2\xea\xe8\xda\xacQ\\\
\x12\xe0\xd46\xac\x9f\x9e\x93\xd4\xcesN\r>"I\xe7\xa4\xac\xc0_r\xf6\x97\x14+y\
\xd9\x04\x10\xa3\x07\xddA)e\xb7\x08\n\xf3\x97\xbf,\xa0L\xee8\xabW\x8e`\xdb\
\x11\x7f\xd7\x8bs\xcb\x1dv\x91\xb7\xa7\x0f!m\xcf\x9e \x9e&\xb3q\x10\x83\xa6\
\x0cJ\x9b@H;0\xcd\xfb>\xacy\x95?~\xe4\xe0\xf3j\xf31\x80m\xfc\x85\xcb\xef\xb1\
\x1c\x18"#\x0c\xaeeO\xde\x1ao1\x97Y\x18\xcanq\xcb\xd7e\t\x03\r\xe5\x83\x8a\
\x1c\x11|w\xe5\xa2B8\x9f\xe3Q]\\U\xc93\x08\xb6\x92\x13\xc6\xb0\xc7\xf9%\x80\
\x94\x1asbV\x0bj\x0f\x87\x8d/\x13 \x11X\xa5u\xf9B\x7f\x0ffSB\x87E:\xcc\x90\
\x1a\xbc\xcd\t\xc92\xe0P\xc6\xbc\xb3\x07\xd8\xd9\xebtug\x92\x17\x88\x14\xbd\
\xd3\xf0\xbdW\x8e\x89?\x90\xa5e\xd7_~#\xef\x17!v\xc5\x89\x03\xcf\xd5:b\xaf\
\x13\x1f^\xdaE\x1d\xe08\x8b\xbf\x0c\x87\xd8k>\x81\xa7w\xdaA\x00\xa2\x0f{N\
\xef\x00\x95\xc5\x9f\xf2Y!\xaf\xf5`\xd2\xb3\xa1k[L>d\x90\x95\xf0+\x9c\x81\
\x8a\xbft\xc5\xba\xe5"2\x82f94\xa5\x82\xf1\x0e}\x80\'\x9d\x11@\x14>\x0e\xcf>\
\xc4x\xd6\xc3\xc1\xd7\xe7\xefGqF\xe1\x1b\xec}\xa1n`{\xb4\x00\xd3r8\xf3\xf5\
\xec\x95q\xe3>\xdeb\xf0\x82\xcf9fX\x85\xe3DO\x87\x9c\xb5IB\xac8\xa7\x1b\xdfW\
/9I\xd3\x00\x87\x85m\xc8\n\x18\x12\x0c\xa0\xe2\xcb\x1bC2FR\x99\xab\xe2\xa6\
\x94\xaf\xe0f[\x8b\xe7\x05:\xddE\x08\xf7 W|\xb1\x99\xa7\x9c\xbe\xa0\x92m \
\x7fr\x1b\xdb\x94s0\xff\xd4%\x83\x10\t\xb0`\x9cqLK\rd\x1bP\xe1B\xf9\n\xa2\
\xb3$\xd8\xc6\x05\x7fu\xf8\xa0+{\xa1\xf5\xf1\xcb@r\x13\x06>~wd\x1bXA\xfc=\
\xad\x0cm(\x95\xac\xc0\xb7\xb0\xbaH\xe3\xc4Z\xdfG\x05a\xe3\x14L^b\x10\x16K\
\xed\x1b\xceB\xc3\xb78\xe7q\xde\xca\x14\x19\xef\x0390zBC\x8e\x19\xa9\xc2\xfd\
\xe14,\xac\xe4-q\xec\xd5\x01\x93\r\x06aq\x92\xb7g|\x88\xd6\x1f\x00\x00\xb1\
\x17\xc8q\x00\xe1\xce\x9f\xdf\xe3/\xc2\x9e\xcd\x9e ~\xa8- \xee8\xc9\xdb\x85\
\x8a\xaf\xffx0g\x7f[r\x1c\xc8mK\xca\x9503\xb1\x82\x1c\xfe\x16\x16c\x9d\xecY\
\xa3\xc8\xd9\x15!\xc0\xcd\xaa\xd3\x06\'z\x1a\xe2\xfb@\x8e\x05\xe1\xc8\xf6\
\xfe\xc0\x92\x8d\xd2\x13\xbb\x8e\x1c\x07\x9e\x98\xb5\x81;4\xael\x03Y\x9a\xc9\
\xb93(2\xa0\x90\xe69b\xc5Aa\x8faI\x9c\x9ab\xc9\x06\xcc\xb3\x00\xfc\xc5\xa1\r\
d\x8d\xf9\xca\xff\to\xc2\x14:L\xc2\x90\x00\xa4\xa6\x98S;H[\xc4\xe18\x9d1\x13\
\x9c\xc9w\xab\x92\xaf\xe0\xcb\x1bt\xc7\xca+\xf8s\x84\xe7\x1c|\xe4K\x8a\x97\
\x9cn\x8c\x91]\x07\xf4\xa5\xbcl\xc2_/\xfd\xad\xb3\xd9\x04\xb5\xe7\x85\xaf\
\xa7\xdb\xf0\x07=\xbb\x00\x93f\xb8\x0fdu\xe1\xe7\xe7\xed\xb1\xc8`\x9f\x02;\
\xea@\xe5oa\xf1\xc7\x8fl90\x18\xab-\xb8\xb2\xf8K\x9b\x87\x15b\x16\x0e\'\x8aS\
\xb8Q\x06\n\x1b\xb2\x02\x17\xd8\x9b\x91\xda\xcd\xffh^8\xc1\xd2\x04X\xb8\x0c)\
\x87\xc6\x054\xd8\r\x06.\xb1\x1a\xa8k\xb2[\xdc:j\xe18I\x81"(Zr\xe8\xc8se\xca\
W\xa09"]P]\xe84Md\x05\xf0A\xaa|\x05\tQg\xb4\xd0\x13\xde\xacQ\xa4\x81\x9b\x8d\
\x838v+\x9f\x80@\x19"\x88\x91\xb3\xfd\x92\xd0\x17\xa5\xc5"\x03\xfcv\x14\xc8^\
\xe0\xb6\xe5\x108;!\xdft\xdc\'t\xf8\xb3\x99\x16\x0e\x1cV\xf2:S\xe0r8\xb8\xf4\
DBZ\xec0T<s~)\x86%\xa5\x9cA\x86\x95<_Ct\xc5\x03\xc7\xb4\x11\x84#\x7f`\xeb\
\x05\xc1i\xa1o\x00\xbb\x01\xbf\x94\xc7;\xea\xbb\x01a\xc0\xba\x94\xa2c{\xf0\
\xe5\xc0v +\xa8\x8d\xc0\xc1\xd2fg\xf9\x16\xebt\x19"#!\xeeW\xa6\x9c\xdd\xe3/>\
Q?\xe0\xd3\xf4\xbd\x86\x18\x1fG\x8a\x9e8\xae\xee\xf1\x17\r8\x15T\x1f\xee\xe3\
e2h\x069\xe3\xd8vfO\x00S\xd3\x02R%\xc7V\x9frN\x15F \x96]|q\xab\x8f\xb0\xe0\
\x83!\x1b\xa5\x8a\t\xa7?\xe1\x14\xb2\xbf\x18d\xe3`\xad\xf7]$I`\xf1y\x11!\x8f\
\xd1\x80?\x82` J\xcc\xdf\xb1z\x1d\xc96\xa0\xd1\xcf\x1a\x85inC\x81gH\xe2.K~\
\xfe\x9c\xd83\x85l\xf2\xac\x00V\xa1\x9f 8\xedC=/;\x08\xa4\xf2%\xe7\xfd\x00\
\x11M\x0f\x07\xce\x07\xfe\xe2\x16\x7f\r\xe9\x0c\x1ft\x90\xa9\xc2\xfe\x1a\xf8\
~T\x0f_\xe9>\x89e\x1b\xa8p\x01)\xeaC\x81\xffH\x01\x99\xc9\x98\x9d]\xbbm\xe4\
\x99(\x00oX\x9b\xe2\x83R\x8c\xb8\xeb;\xb2Q$\xcb\xe6\xccO\x03\x00\x97l|\xddE4\
\x81/oP\xbaB[~z\xe2}\x02\xd4^\x8a\xf8\\\x9b?\xef\xca\x19\x0f\\:\x1a\xc5^\x00\
`\xf9\x03c\xad3`i\xf7b\xf8.8\xbf\xf6YW\xb6\x81;g\xb8qXp\xe6Z\x87\xbf\x94\x97\
\x81\xa7\xad\x96)J\xd9\xaaZ\xd3V\xb7\x95\x88?JKm\xb5\x9b\xa2\xb5:\xad\xa8e\
\xb4F\xad\xa0\x15\xb7tQ\xc2\x96%\xfe;\x12\xc5n9-W\xfc\xf1Z\xfd\x96\xdf\x1a\
\xb4\x86\xad^S|YnDyj\x1d\xb7n[\xf7\xa2\xfcn=\xb4\xceZ\xd7\xad\x83\xd6]\xeb\
\xa8u\xd2:m\xfdl\xfdj\x9d\xb7.Z\x7fZ\xcfbL\x8f\xad\xc3\xd6\x95\xf8})\xfe^k}l\
e\xad\x9dV\xde\xfa,\xfe\xdei\xa5\xad-Q\xb2V!J\xd6\x94\xfa\xdf\xban\xd2Zh-\
\x8a\xb2\xdcj\xc8%RVZ\xab\x82\x98D\x10\xc2\xc4h\r)\xeb\x82\x90%A\x8a\x05bt\
\xf1\xdbhm\x8b\xb2\xd7\xfa\xd4\xda\x14\x7f\xc6 \xa6\xf7\xff!f\x17\xc4\xd4e\
\xa3\xf5\xae\xf5\xd6\xfa\xd6\x103\xdfz/\xc8\xf9 \x88\xf9\xde\xdao\xcd\xb5\
\xbe\x8a\xbf\xbf\x08b\xfe\x08\xa2\xd6Z/\xad\xbf\xad\xd7\x86\xcfDL\xda\x10\
\x93\x81\xa0B\x10\xfb\xb1\xf9\xd74K\xb32\xa7f\xd7\xfc\x872M\x94\xad\xc4TL\
\xd5l\x9b\x9a\xd91#\xf1\xc70Gf Jl\xeaf(\x8ae\xda\xb28\xa6kz\xa2\xf4M\xdf\x1c\
\x98C\xb3g\xde\x98O\xe6\xb1y+\xca\xb1yo\xfeFy0\xcfD\xb96\x0f\xcc;\xf3\xc8<1O\
\xcd\x9f\xe6/\xf3\xdc\xbc0\xff\x98\xcf\xe6\x0f\xf3\xd1<4\xaf\xccKs\xcd\xfchf\
\xe6\x8e\x99\x9b\x9f\xcd\xd4\xdc2\x0bsb.\x88R\x88\xdf\x8b\xa2,\xff\xaf\xb2b\
\xae\x8a\xb2\xde\x94%s\xdb\xdc3?\x99\x9b\xe6\xd8lff\xa5\xb5\x0bR6\x04\x19\
\xff&\xe6\x9d \xe5\xed\xbf\x88\xf9f\xce\x9b\xefE\xf9`~7\xf7\x05As\x82\x98\
\xdf\r15)O\xe6W\x90B\xc4|1_\xcc\xbf\xe6\xab\x98|\xb3,\xcb\xaa\x9c\x96\xdd2)\
\x95R-\xdb\xa5Vv\xca\xa84D\x19\x95A\x19\x97\xba\xf8;,\xad\xb2\x10\x84X\xe5\
\x96 \xa6\xfe\xbd\x00"\xec\x92\x8a\x83\x7f\x89,\xb7\xf4\xca~\xb9i\xfa\xe5?L\
\x0c\x912(7\xc4\xdf51\xc3\xb2W217\xa5\x03\x82\xa8x\xe6S9\x14320\x8f\xcb\xe3r\
\x88\xe9\t\x02\x9e\x1aBj2\xbe6\xa5&\xe6\xb6\xbc/\x7f\x97\x0f\xe5Yy]\x1e\x94\
w\xe5QyR\x9e\x96?\xcb_\xe5yyQ\xfe)\x9f\xcb\x1f\xe5cyX^\x95\x97\xe5Z\xf9\xb1\
\xcc\xca\x1dQ\x82r\xcd\xcc\x05)\x9f\xcbz\x96\x16\xc4<M\xcc\x14d8\xe5V\xf3\
\xb7\xd3\x90D\xc4\x14\xe5\xa4\xacg\xe6\x7f\x11S\x97\xf6\xbf\x88\xa1e\xb6P.\
\x947(\xf5\xef\'A\xc0b\xb9\\\xae\x94\xab\xe2\xcfz\xb9Tn\x97\xf5R\xbb\x01\x19\
u\xd9+kb>\x95\x9b\xe5\xb8\xdc-7\xcaw\xe5[\xf9\xad\x9c/\xdf\x97\x1f\xca\xef\
\xe5~9W~-\xbf\x94/\xe5\xdf\xf2UH\x1e\xb3*\xab\xaa\x9aV5Y\xddj\xd4\x90S\x17"\
\xa6\x9e\xa7\xa4bR\xb6J\x9e\xa3zf\xd6M\xa5r\x051j\xd5\xae\x1ab\xb4\xaaSE\x95\
Q=5\x9c\xad\x17\xc9\xbd\xe0\xfe\xa8r\xc5\xde\xf8\xd6\x90R\x97\xa0\x8a+\xbd\
\xaa\x17R\xcf\x0c+\xab\xb2+\xa7r+\xaf\xea\x8b_~5\xa8\x86\xa2\xcc\x99L\x14\
\x11\xd3\x13\xff\xdfM\xf5T\x1dW\xb7\xe2\xd7}\xf5\xbbz\xa8\xce\xaa\xeb\xea\
\xa0\xba\xab\x8e\xaa\x93\xea\xb4\xfaY\xfd\xaa\xce\xab\x8b\xeaO\xf5\\\xfd\xa8\
\x1e\xab\xc3\xea\xaa\xba\xac\xd6\xaa\x8fb\x1f\x119VY\x97\x8f\x15\x93B\xc4\
\xd0\xcc,7\xbb&\xabv\xaa\xbc\xfa\xcc\xc4\xa4\xd5VCLM\xca\x8d$\xa6.59E5\xa9\
\x16\xca\xb8\xbam\xf6\xc3\x8d9\xac\x16\xaa\xd5\xd2\xae\x16\xab\xe5j\xa5Z\xad\
\xd6\xc5@\x97\xaa\xed*l\xc8\xa9\x89\xd9\xab03\xe2\xff\xd9\xac\xc6\xd5n\xb5!~\
\xbd\xab\xde\xaao\xd5|\xf5\xbe\xfaP}\xaf\xf6\xab\xb9\xeak\xf5\xa5z\xa9\xfeV\
\xaf\xe2T0\xa7\xe5\xb4\x9aN\xa7\xddi2U\xa6\x99\x10\t\xba\xd8I\xc7\xa5:eb\xb6\
P\xec\x86\xac\xf6\xb4=u\x049\xab\r1\xda\xb43%8_CL45\xa6\xa3\xe9\xbd $\x98\
\xc6S}\x1aNG\xd57\xd3\x9a\xdaSg\xeaN\xbdi\x7f\xbaP\xfa\xd3\xc1t8\xedMo\xa6+\
\r1O\xd3\xe3\xe9Bu;\x15\\\x9f\xfe\x9e>L\xcf\xa6\xd7\xd3\x83\xe9^u7=\x9a\x9eL\
O\xa7?\xc5\xff\xf3kz>\xbd\x98\xfe\x99\xd6\xc4<O\x7f\x88\x7f\x1f\xa7\x87\xd3\
\xab\xe9\xe5tm\xfaq\x9aMwDM>\xfd<M\xa7[\xd3b:\x99.L\x17\xa7\xcb\xd3\x95\xe9\
\xeat}\x1a\x94yI\x82\xe0c\xc5\xdb\xdfn\xc8hO\xb7@\xd0\xd2t[\x94\xceto:7[f\
\x9f\xa6\x9b\xd3\xf1twzln\x88\xe6E\xd7\xd3\xb7\xe9\xb7\xe9\xfc\xf4\xfd\xf4\
\xc3\xf4\xbb\xa8\xd9\x9f\xceM\xbf\x8a\x7f\xbfL_\xa6\x7f%17\xd3Wq\xd2\xda\x95\
\xd9\x15\x8b]\xfc;\xed\x1eL\xbb\xddD\xfcR\xbaj\xb7\xdd\xad\x89\xd1\xba\x9dn$\
~\x19\xddQ7\xe8\xc6\xe2\x97\xde\r\xbbV\xd7\xee:\xe2\xb7\xdb\xf5\xba}\xf1\xaf\
\xdf\x1dt\x87\xdd\x9e(7\xdd\xa7\xeeq\xd7\x17c\xb8\xed\x86e-\x06\xac2\xa9\xea\
\x1dB\x85e\xdaV\xb9$Xy<\xbd\xef\xdew\x7fw\x1f\xba\xcd2;\xeb^w\x0f\xbaw\xdd#\
\xd1\xe4I\xf7\xb4\xfb\xb3\xfb\xab{\xde\xbd\xe8\xfe\xe9>\x8b\x9a\x1f\xdd\xc7\
\xeea\xf7J\xfc\xba\xec\xaeu?v\xb3\xeeN7\xef~\x16\xff\x9dv\xb7\xbaEw"~\x9dw\
\x17\xba\x8b\xdde\xf1k\xa5\xbb\xda]\xef.\x89_\xdb\xdd\xbd\xee\xa7n\xbd\xcc6\
\xbb\xe3\xeen\xb7f\xd0F\xf7]\xf7\xad\xfbM\xfc\x9e\xef\xbe\xef~\x10\xff~\xef\
\xeew\xe7\xba_\xbb\xba \xe2K\xf7\xa5y\xeao\xf7U("fbW\x82\x86\x84\x89Y\x91g\
\xcb\xba\xf8U\x93\xb4U.\x88\xa5}#\x08Z\x9aN\x93n\xf2\x0fi@I\xa2$j\xd2\x16\
\xafkI\'\x89\x12#\x19%\xfdn\x90\xc4\xa2FO\xc2\xc4J\xecDo:r\x127\xf1\x92~\xf2\
\xb9\xf9/\xc1\xcfd\x90\x0c\x93^r\x93<%\xc7\xc9mr\x9f\xfcN\x1e\x92\xb3\xe4:\
\xd9\xef\x1e$wIM\xccQr\x92\x9c\x8a_?E\xdd\xaf\xe4<\xb9\x10\xbf\xff$\xcf\xc9\
\x0f\xf1\xefcr\x98\\%\x97\xc9\x9a\xf8\xfd1\xc9\x92\xba\xcd\x9d$Ov\xca\xcf\
\xe2w\x9al\tb\xd4i\x91L\x92\x05\xf1\xf6b\xb2\x9c,\x89-_\x93\xb3l\xd63S\x13s,\
\xcaJ2M\xe6\xfe=3\xab\xc9z\xb2\x94l\x8bF\xf6\x92O\xf50\x92q\xb2\x9bl$\xef\
\x92\xb7\xe4[2\xdft\xb4\xd0}\x9f|\x001\x8b\xd5\xbe\xe0\xeb\xf7d?\x99K\xbe&\
\xeb\xddn\xf7\x8bx\xe6%\xf9+\xfe~\x15z\x91\xa9\x94JML\xa5L\x95\xaeR\xef\x99D\
Q\x14Ui+\xf5\xbb\x9a\xd2\x11\xffF\x8a\xa1\x8c\x94@\x89\xc5o]\t\x95\xba\x0fK\
\xb1\x15Gq\xc5oO\xe9+\xc7\xa5\xaf\x0cD\x196\x7f\x0f\x94\x9eR/5\x92h\xedf\x99\
\xdd(7\xca\x93r\xac\xfcC_\x1b?\xeb\xde+\xf5\xdc\xfc\x16\r<\x88?g\xca\xb5\xf8\
\xfbB\x0c\xf8@\xb9S\x8e\x94\x13\xe5T\xfc\xf7O\xf1\xe7\x97r\xae\xf4\x93\x0b\
\x85\x88\xf9#\xfe\x9f\x0be\xbd[\x13RK\xb0\xe7f\x00?\x14\xbfzT\x0e\x95+\xe5\
\xb2!fM\xf9\xa8d\r1;J\xae|V\xd2\x86\x98-\xa5\x10\xffN\x94\x05eQYVV\xc4\xefUe\
\xbd!fI\xd9V\xda\xe5^\xd3\xd6\'eS\x19+\xbe\xb2\xabL\x92\r\xe5]C\xce\x86\xc2\
\xc7f-\x02\x96\xa6\x89\xf9\xa6|S\xe6\x95ff\xde+\xb7\xca\x07\xa5\x9e\x9b\xef\
\xa2\x81^w_\x99S\xbe*_\x94\x9e\x18\xf0\x8b\xf2WyK^E}K5\xd5R\xb5\xabJ\x9d\xaa\
oI\xd5\x10\xd3U\x13UQ\x1bB\xaa\x07SU\xdb\xaa\xa6v\xd4^7R\ru\xa4\x06j,\x9e\
\xd7\xd5P\xb5T[\xad\x89qTW\xf5\xd4\xbeZ\xbf\xeb\xab\x03\xf1\xefP\xed\xa97\
\xea\x93x\xe7X\xbdU\xefU"\xe6\xb7\xfa\xa0\x9e\xa951\xd7\xea\x86r\xa0\x1e\xa8\
w\xeaAS\x8e\xd4\x81r\xa2nI1]\x13s\xaa\xde\x08b~\xaa\x8d\x00\xf8\xa5\x121Jr\
\xae^\x88&\xfe\xa8\xcf\xea\x0f\xf5Q\xad%\xd1\xa1z\xa5^\xaak\xeaG5Sw\xd4\\\
\xfd,jSuK-\xc4\xbf\x13uA]TU\x9c*\xcb\xea\x8a\xba\xaa\xae\xd3p\xd4muO\xfd\xa4\
n\xaa5C\xc6\xea\xae\xba\xa1\xd6\xe2\xfb\x9d\xfa\xa6~S\xe7\xc5\xef\xf7\xea\
\x07\xf5\xbb\xba/~\xf5\xab9\xf1\xf7W\xf5\x8b\xfa\xa2\xfeU\xd7\xc4\xf3\xafBe_\
\x16*\x89\x10\x00\xedkq\xb4\x1f\xa8\xd3v\xb7\xf9{\xda6\x041I\xfb\xdf\x82yI\
\x9c6KS\xb1v\xdb\xf4\x91\xeev\xbb\xad\xb5;\xed\x1fj\xd46\xda\xa3v\xd0\x8e\
\xdbz;l[m\xbb\xed\xb4\xdd\xb6\xd7\xee\xb7\xfd\xba\x99\xf6\xb0\xddk\xdf\xb4\
\x97\x94\xa7\xf6q\xfb\xb6}\xdf\xfe\xdd~h/\xaa{\xa5(\xd5Y\xfb\xba}\xd0\xbe\
\x13C8jo$\'\xed\xd3\xf6\xcf\xf6\xaf\xf6y\xfb\xa2\xfd\xa7\xfd\xdc\xfe\xd1~l\
\x1f\xb6\xaf\xda\x97\xed\xb5\xf6\xc7v\xd6\xdei\xe7\xed\xcf\xed\xb4\xbd\xd5.\
\xda\x93\xf6B{\xb1\xbd\xdc^i\xaf\xb6\xd7\xdbK\xed\xfd\xeev{\xaf\xfd\xa9\xbd\
\xd9\x1e\xb7w\xdb\x93\xa4&c1\x99\x11\xb3\x9cl\xb4\xdf\xb5\xdf\xda\xdf\xc4\
\x9fw\xed\r\xf1\xf7[{\xbe\xfd\xbe\xdd,\xb3\x0f \xa6&Go\x7fo\xef\xb7\xe7\xda\
\x91\xf8\xfd\xb5\xfd\xa5\xfd\xd2\xfe\xdb~\x15\xa6\x8d\xa9\x95\x9a8f\xb5\xae\
\x96h\x8a\xa6jmM\xd3:Z\xa4\x19\xdaH\xabI\t\xb4X\xd3\xb5P\xb3\xb4Z<\xdb\x9a\
\xa3\xb9\x9a\xa7\xf55_\x1bhCQz\xda\x8d\xf6$~\x1fk\xb7\xda\xbd\xf6[{\xd0\xce\
\xb4\xfb\xd6\xb5v\xa0\xddiG\xda\x89v\xaa\xfd\xd4~i\xe7\xda\x85\xf6G{\xd6Tu\
\xaf=\xd2~h\x8f\xda\xa16n\x96\xd9\x95F\xcb\xecR\x1b(k\x9a\xa1\xd6\xe4\xbckH\
\xd9h\x7f\xd4>j\x99\xb6\xa35\xcb\xecV\xb9\x16\x02\xe0\xa0{\xd0\xc845\xb9\x13\
\x7f+\xc9A7\xd7>k\xa9\xb6\xa5\x15\xdaD[\xd0\x16\xb5emE[\xd5\xd6\xb5%m[\xdb\
\xd3>i\x9b\xdaX\xdb\xd5\xf6\xda\x0f\xe6\x86\x16h\xef\xb47\xed\x9b\xd6\xeb\
\xcek\xef\xb5\x0f\xdawm_\x9b\xd3\xbej_\xb4\x17\xed\xaf\xf6*JKX\x17e\xa7\xeaL\
;\x9e\xda\xed$\x1d\xa5\xa3\n\xfei\x9d\x87\xaa\xd3\x89:Fg\xd4\t:qgU=\x103\xac\
\xaaz\'\xec\xa8\xa6\xd5\xe9\xb6\xedNO\x0c\xdf\xe9\xecw\xdd\x8e\xdb!\x89\xb6\
\xdf\xbd\xd4\xae\xb4\xa1\xe2u\xea\xd2\x17e\x07\xc4\xcc\xd5\xa2\xf9^\xa1R\xef\
\x9c\xba\x1c\x88\x1a\xbf3\xe8|\xd6\x86\x9d^\xe7\xa6\xf3\xd49\xee\xdcv\xee;\
\xbf;\x0f\x9d\xb3\xceu\xe7\xa0s\xd79\xea\x9ctv5\xbd2\xcc\xeb\xf6Y\xfb\xb4\
\xf3\xb3\xf3\xabsS\x9dw\x96\xdb\x17\x9d?\x9d\xe7\xce\x8f\xcec\xe7\xb0s\xd5\
\xb9\xec\xacu>v\xb2\xceN\'\xef|\xee\xa4\x9d\xadN\xd1\x99t\x16:\x8b\x9d\xe5\
\xceJg\xb5S\x13\xb3\xdeY\xealw\xf6:5)+\xaa\xaa\x8e\xb4E\xf5D\xfd\x84\xc1\xff\
\xef\xb2\xdf\xa5\x7f7\x05\xb1c\x10\x93i\xf2\x9c\xa9\t\xf9 JM\x0e\x13\xb6+H\
\xd9\xe8lt\xdeu\xde:\xdf:\xf3\x9d\xf7\x82\x98\x0f\x9d\xef\x9d\xfd\xce\\\xe7k\
\xe7K\xe7\xa5\xf3\xb7\xf3\xdaiEf\xb4*6\x7f\x19\t\xf5.\xeaFI\xa4Db\xf3EZ\xd4\
\x89\xd6:Q\xb4[\x1a\xd1(:0\x83(\x8e\xf4(\x8c\xac\xc8\x8e\x9c\xc8\x8d\xbc\xa8\
\x1f\xf9\xd1 \x1aF\xbd(\xea\xdcDO\xd1qt\x1b11ag1\xf9\xbf\t\xa9\x8bP\xae\xba\
\xfc\xfbD\xedw\xee\xa3\xdf\xa2`\x99\x9dukB\x1e\xa2\x87\xa8\x96j\x1f\x14*g\
\xd1ut\x10\xddEG\xd1It\x1a\xfd\x8c~E\xe7\xd1E\xf4\'z\x8e~D\x8f\xd1at\x15]FkQ\
+\xfa\x18e\xd1N\x94G\x9fEI\xa3\xad\xa8\x88&\xd1B\xb4\x18-G+\xd1j\xb4\x1e\xdd\
UK\xd1v\xb4\x17}\x8a6\xa3q\xb4\x1bmD\xef\xa2\xb7\xe8\xbe\xf5-\x9a\x8f\xdeG\
\x1f\xa2\xef\xd1~4\x17\xfd\xd2\xbeF_\x1abV\x051/\xd1\xff\x8f\x8c\x81B\xba\
\xc7\x9d\xcauGjM\xcc\xdf\x86\x98\xb9\xfa\x9c\xa9\tab\xf8\xf7k\xd42La\xd3V\
\xc6\xd4\xe8\x1a\x89\xa1\x18\xe7\xe2\x00i\x1b\x9a\xd11"\xc30FF`\xc4\x86n\x84\
\x86e\xd8\x86c\xb8\xc6\xd7\xd23>G}\xc37\xce\xb5\x8114\xd6\xa3\x9eqc<\x19\xc7\
\xc6\xadqo\xfc6\x1e\x8c3\xe3\xda80\xee\x8c#\xe3\xc485~\x1a\xbf\x8cs\xe3\xc2\
\xf8c<\x1b?\x8cG\xe3\xd0Xi\x04\xfc\xb2\xba\xdc\x1e(>N\xfc\xff&\xa4.\xb3\x99\
\xbb2.\x8d5\xe3\xa31G\xe7\xcc{IL\xbd\xcc2\xa3.\x0f\xd1\x8e\x91\x1b\xaf\xd1g#\
5\xb6\x8c\xc2\x98\x18\x0b\xc6\xa2\xb1l\xac\x18\xab\xc6\xba\xb1dl\x1b{\xc6\'c\
\xd3\x18\x1b\xbb\x82\x94\x9a\x98\r\xe3\x9d\xf1&H\xfa&\xca\xbc\xf1\xde\xf8`|7\
\xf6\x8d9\xe3\xab\xf1\xc5(\xcb\x17\xe3\xaf\xf1j\xb4F\xe6\xa8\x14\x86\xd2t\
\xd4\x1d%#e\xa4\x8e\x84\xd8\x1auF\xd1\xc8\x18\x8dF\xc1\xa8&&\x1e-\xab3\xbe\
\xff\'!\x97\xda\x91J\xc4L\xfe\xb5\x0c7;\xfa(\x1c\xfdC\xb7\x19\xed\x913rG\xde\
\xa8?\xf2G\x03Q\x86\xa3\xde\xe8f\xf44:\x1e\xdd\x8e\xeeG\xbfG\x0f\xa3\xb3\xd1\
\xf5\xe8`\xb4h\xdc\x8d\x8eF\'\xa3\xd3\xd1\xcf\xd1\xaf\xd1\xf9\xe8b\xf4g\xf4<\
2#\xa7\x99\x977\xe3\xc7\xe8\xc7hWH\xb8\xc7\xd1\xe1\xe8jt9Z\x1b}\x1ce\xa3\x9d\
Q>\xfa<JG[\xa3b4\x19-\x8c\x16G\xbb\x912Z\x1e\xad\x8cVG\xeb\xa3\xa5\xd1\xf6ho\
\xf4i\xf4\x14m\x8e\xfe\x94\xb5(y4\xd7\xbbU\xbb\x1e0\x13\xc13b\x08\xcd\x82\
\xfekM\xab\xff\x95\xa4\nb\xd6hf\xc6\xa3]A\x8a;\xda\x18\xbd\x1b\xbd\x8d\xbe\
\x8d\xe6Ey/\xca\x87\xd1wQ\xf6Gs\xa3\xaf\xa3/\xa3\x97\xd1\xdf\xd1\xeb\xe8n\
\xd4\n\xcc@\xd8\xd0\xc14\x10ju\xa0\x04j\xd0\x0e\xb4\xa0\x13D\x81Xu\xc1(\x08\
\x82\xc7Q\x1c\xe8\xa2\x84\xc1\xe5\xc8\n\xec\xc0\t\xdc\xc0\x0b\xfa\x81\x1f\
\x0c\x82a\xd0\x0bn\x82\xa7\xe08\xb8\r\xd6G\xf7\xc1\xef\xe0!8\x0b\xac\xe0:8\
\x08.\xca\xbb\xe0\xba\xad7\xe7\xd6r{\xb6\xa0\xa8\x1c\x05\'\xc1\x9aFd\xf1\xff\
\xcb\xc4\xaci\xfaHof\xe6\x9f\xd3\xe0g\xf0K\x94\rA\xceyp\x11\xfc\t\x9e\x83\
\xf9\xd1\x8f\xe018\x0c\xae\x82\xcb`-\xd8\x1f}\x0cN\xa3,x\x1d\xed\x04y\xf09H\
\x83\xad\xa0\x08&\xc1B\xb0i,\x06\xcb\xa2\xac\x04\xab\xc1zS\x96\x1a\x92j\xa2\
\xc2`;\xd8\x0b>\x05\x9b\xc18\xd8\r6\x82w\xc1[\xf0-\x98\x0f\xde\x07\x1f\x82\
\xef\xc1~0\x17|\r\xbe\x04/\xc1\xdf\xe05h\xc5f,,\xf3\xd8\x10j\xd1\xb2\xd0)T\
\xd3\xed\xfc{f6\x94\xa3\xe0(\xa0\xff:R\xaf\x0c^zT^"a\x1c\xc7\xf4!\xad\xb8\
\x1b\'\xf1\xafZ\x0f\x17E\x8d\xdb\xb1\x16\xd7\xb3\xf3(\xc8\xe9\xc4Q|)\xf6\xb9\
`v\x1c\xc7\xaf#=\x0ec+\xb6c\'vc/\xee\xc7~<\x88\x87q[\x90c\x9b\xabA]\xc8\xb7\
\xb6*H\xea\xc57\xf1Y\xf0\x14\x1f\xc7\xb7\xf1}\xfc;~\x88\xcf\xe2\xeb\xf8 \xbe\
\x8b\x8f\xe2\x93\xf8T\x94\x97\xe0g\xfc+>\x8f/\xe2?\xf1s\xfc#\xbe-\x1f\xe3\
\xc7\xf8A\x15J\xab\x99\xa8\x87\xf1\x95\xb1\xdc\xbe\x8a\xaf\xe2\x93\xa0Hj\x02\
h\x86.\xe3+\xed?g\xa6j\xaf\xc5\x1f\xe3f\x99e\xf1N\x9c\x8b\xf29N\xe3-Q\x8ax\
\xd2\x10\xb3\x10\xd7\xe4,\nb\xf6\xc5r[\x8eW\x041\xab\xf1z\xbc\x14o\xc7{\xf1\
\xa7x3\x1e\xc7\xbb\xf1F\xfc\xee_\xc4\xd4\x84\xac\x80\xa0^\xfc\x16\xff\r\xbe\
\xc5\xf3\xf1\xfb\xf8C\xfc=\xde\x8f\xe7\xe2\xaf\xf1\x97\xf8%\xfe\x1b\xbf\xc6-\
\xdd\xd4K\xbd\xd2\xa7zWOtE\x17\x9a\x94(51bf*E\xd5\xf4Km\x92\xd4\xa4\x1c\xc6U\
\x9bw\xcd\x91\xda\xd1#\xbd\xde\xfc\xff\x9e\x17C\xac\xb2@\xff\x87\xbe\xeb\x9b\
\xc5\xb1\x1e\xeb\xba\x1e\xea59\x96n\xeb\x8e\xee\xea\x9e\xde\xd7}}\xa0\x0f\
\xf5}\xb1szzM\xcc\x8d\xfe\xa4\x1f\xeb\xb7\xfa\xbd\xfe[\x7f\xd0\xcf\xf4k\xfd@\
\xbf\xd3\xebEv\xa4\x9f\xe8G\xfa\xba\xf8\xc5\x84\x9d\xea?\xf5_\xfa\xb9~\xa1\
\xff\xd1\x9f\xf5\x1f\xfa\xa3~\xa8_\xe9\x97\xfa\x9a\xfeQ\xcf\xf4\x1d\xfdW\\\
\xe9\xb9\xfeY?\xd5S}\x18\x131[\x82\x9c\xbd\xb2\xdb\xd5\xf4B\'Rf\xdb\xbf\x12\
\xca\xe8D_\xd0\xeb\x05\xf8\xef\xed\x7f\x18\xd7\xc4\x8c\xf4ff\x16\xf5E}Y_\xd1\
W\xf5u}I\xdf\xd6\xf7\xc4\x9fO\xfa\xa6>\xd6w\x051\xbe\xbe\xa1\xbf\x13\xe4\xbc\
\tb\x16\x8do\xfa\xbc\xfe^\xff\xa0\x7f\xd7\xf7\x1bb\xe6\xf4\xaf\xfa\x17\xfdE\
\xff\xab\xbf\xea\xad\xd0\x0c\xcb\xb0\n\xa7a7<\x12\xd6\xb6\x12\xaaa;\xd4\xc2N\
\x18\x85F\xf8\x10\x8f\xc2 \x8cC=\x0cC+\xb4\xc3\x9f\xb1\x13\xba\xa1\'J?\xf4\
\xc3a<\x08U1;\x8fq\xed\x97\x9b3/\x84\xd1G\xa4\xf0\x8c\x1c\xa9\xc3\xb0\x17\
\x1a\xeaM\xf8\xefY\xa9\xcf\xa1\xa7\xf0)\xac\x89i\x04\xc0qx\x1c\xde\x86\xcb\
\x82\x98\xfb\xf0w\xf8\x10n\xebg\xe1ux\x10\xde\x85\xbb\x82\x9c\xa3\xf0$<\r\
\xf7G?\xc3_\xe1\xa2q\x1e^\x84\x7f\xc2\xe7\xf0G\xf8\x18\x9e\tb\x0e\xc3\xab\
\xf02|\xd1\xd7\xc2\x9a\x98WA\xd4\x9a\xf8\xaf\x8fa\x12f\xe1N\x98\x87\x9f\xc34\
\xdc\n\x8bp\x12>\xeb\x0b\xe1b\xb8\x1c\xae\x84\xab\xe1z\xb8\x14\x96\xfav\xb8\
\x17~\x12\xc4l\x86\xe3p7\xdc\x10\xe5]HN\xc69\xf3\xa4!\xa5H^\xa2\r\xb1#\xf6\
\xbbo\xe1\xb7p>\xdc\xef\xfe\xe7^\xa9\x8d\xe9\x89\xfe^\x10\xf3A\x94\x86\x98\
\xef\xe1\xf7p?\x9c\x0b\xbf\x86_\xc2\x97\xf0o\xf8*J\xcb\xaa]\x89\x955\xb5\xba\
Vb\x9d\x84\x8a\xa5ZmK\xb3:Vd\xfd\x11G\xbe\x90\xb9\x96X\x8fVhY\x96mY&I2\xc7:\
\x113r\xa2\xd7\xe8i\xcf\xea[~\x9d\x1a\xd8\xeaY\xf3\xf1\x8d\xf55~\xb2\x8e\xad\
[\xeb\xdez\x89\x7f[\x0f\xd6\x99um\x1d\x88R\xcf\xccfh\x99\x8e\xb9 N\xd3c\xf3\
\xa9!\xe6*\xbe\xb3\xae\xe2#\xeb\xc8:\xb1\x0c\xfd)<\xb5\x0c\x95$\xd8\xbfI\xf9\
i\xfd\xb2\xfa\x9ds\xeb\xc2\xfa#JC\xcc\xb3\xf5\xc3z\xb4\x0e\xad\xaf\xe1\x95ui\
\xadY\x1f\xadm\xb1\xd02k\xc7\xca\xad\xcf\x82\x9c\xd4\xf2\xf5\xc7`\xcb*\xac\
\x89\xb5`-\nb\x96\xad\x15k\xd5Z\x17\xe50\\\x12\xc4\xd8 f=\xa8\x89q\xacmQNu\
\xcf\xda\xb3>Y\x9b\xd6\xd8*\xc2]k\xc3zg\xbdY\xdf\xacy\xeb\xbd\xf5\xc1\xfanm\
\x87\xfb\x82\x949\xeb\xab\xb5\x14\xf4\x0517\xe57\xd3k\x9c\xef7\x82\x98~R\x13\
\xf3\xa5!\xe6\xc5\xaa\xd5\xff\xff=\'B\'\x0b~\tb\xee\xa3\x9a\x98\xbfL\xcc\xab\
\xf5j\xcd\x8551-\xbb\xf6\xb0U\xf6\xd4\xde\xd6\xbbvb+vm\xbc\x0b\x83\xd3\xd6\
\xec\x8e\x1d\xd5Z\x8b-\xd4\x05;\xb0c[o\xfe\xe8v(h\xd1m\xbb\xb94m\xdb\xae\xed\
\x89\xbf\xfb\xa2\xd4\xbf|{`\x0f\xed\x9e}c?\xd9\xc7\xf6\xad}o\xff\x16\xbf\x1f\
\xec3\xfbZ\xfc?\x07\xe2\x99;\xfb\xa8\xf9sb\x9f\xda?\xed_\xf6\xb9}a\xff\xb1\
\x9f\xed\x1f\xf6\xa3}h_\x89\xbf\x15\xbb6\xc8\xfe\xf3\\\x19(\x97\xf6\x9a}\xa2\
\x0e\x955[\x98f\xf6\x8b\xb5\x98\x8c\x15\xcc\xcc\xb3\x95\xd9s\xe1\x8e\x9d\xdb\
\x9f\xed\xd4\xde\xb2\x0b\xfb\xb5Yl\x13{\xc1^\xb4\x97\xed\xf9\xd1\x8a\xbdj\
\xaf\x0bR\x96\xecm\xfb\x8f\xd85{\xf6\'\xfbA\xdf\x8c7\xedM{l;\xd6zs\xc6\xac\
\x07I\xb8kg\xe2\xcf\x86\xfd\xce~\xb3\xbf\xd9\xf3\xf6{\xfb\x83\xfd\xdd\xde\
\xb7W\xc29{\xde\xfa*~\x8f\xad/\xf6\x8b\xfd\xd7~\xb5[\x8e\xe9\x94N\xe5L\x9d\
\xd0\xfc\xd6\x84\xaf\xc8y\xdf\x133sdu\x9dzf\xde\xda\'\xc1\x7f\xcf\n\x138P\
\x8a\xe4\xa3]\x8b\xee\x81\xf2\xaf\x99\xc9\xecG\xb1\xd8\x12\xa7.\xf5/*\xf5\
\x7f)\x8e\xea\xb4\x1d\xcd)\xac\x9a\x98\x8eS\xabb#\'p\x1e\xf4\xd8\xd1\x1d\xb1\
\xaa\x9c\x13\xbd&\xa7\xde351\xefD\xc9C\xdbq\x1cW\x14\xcf\xe9;~\x9dg\xac)\x03\
\xa7\xe7\x9c\xc67\xce\x93s\xec\xfc\xb5o\x9d{\xe7\xb7(L\xcc\xbcy\x8f\x85v\xa1\
<8\xf5\x8e\xb9\xb3\x0c\x95%\xda\x8c\x94\xffTC\x0fc\xfa\x97\xdc\xb3\xce\xb5s\
\xe0\x1cZ59\xf5\x0c\xcd\xc8I\x9c}!\x1aT\xe7\xce9rN\x9cS\'\xb2\x7f:\xbf\x041\
\xe7\xce\x85\xf3\xc79\x133\xf3\xec\xfch\x88\xa9\xb7}\r\xc6\xaf\xa5\xd8\xc6\
\x7f\x10\xf3\xe8\x1c:W\x82\x04_\x94\x9e\xf8u\xe9\xac9\x1f\x9dL\x90\xb3\xe3\
\xe4\xceg\'u\xeaY\r\xc5\xf6w\xcdQU\x87\x12\xeb@\xe2[r\xa1|H\x1e\x9c;\xebH\
\xfd\xefE\xf6\x7f\x97\x7f\x113\x17\xd6\x83\xcf\xec\x9a(.43[\x82\x98\xc2\x998\
\x0b\x8ea/:\xcb\xce\x8a g\xd5Ywj\xd1\xbc\xe4l;{N\x12~\x12\x7fj\x82\xea_\xf5"\
{\xb3kb6\x9bR_l\xdfu6\xc4\x9fC\xe7\x9d\xf3\xe6|s\xe6\x9d\xf7\x82\x98\x0f\xce\
wg_\x10S\xeb\r$\xcd\xbe\x99B%\xa8\xea\xb9\x89\xaa\x9a\x9c\xbe \xe7R\xfb\xef\
\x99\xf9\xbf\xca\x90\xf7L\xbd\xcc\x1e-!\x9e\xc5\xd0\xe7\xc2\xba\x1c\n\xe9\
\xc6K\xef\xab\xf3\xc5yq\xfe:\xaf\xce\xc4j\xb9\xa6[\xba\x95;u\xbbn\xe2*\xae\
\xea&a\xdb\xadI r\xea_43\x9a\xdbq\xddfn\xe6\x85\x95\xbc\xe6\xd4\xc5\x10\xca\
\xb9P\xa1\xddoB\xb5\xd3]5\x0c\xddT\x10C\xcaO\xd8\x90#t\xcd\xaa^j\x96\x1bU\
\xb6[/\xb6\xc3x\xa69\xff\xa7}\xf3\xefr\xa59M\xba\x85\x7f\\\xf7\xda\xe1\x81\
\xd7\xcb\xccs\xebEW\xd7\xd4\xf3R\x93\xd8w\xeb\xe2\xbb\x03w\xe8\xd6n\xdc\x9e{\
\xe3>\xb9\xc7\xee\xad{\xef\xd6\xc7\xe4\x89^/\xae\r{\x17\xc5v~\xbb\x0f\x82\
\x98M\xe7\xcc\xbd\x16C\xe72j\x88y/Hyr\x0e\\\x9a\x97\xd4\xa9\x17g-\xd0k\xf1,l\
\x0b17\xb7\xe6\x9dKs\xf3!\x11\x02@.4.w\xea\xbfI\x1c*\x86\xfa\xd7\x021G\xae\
\xeb\x9e\xb8\xa7\xeeO\xf1\xe7T\xfc\xfa%\xcay\xf3\xdf\x17M\xf9\xe3>\xbb?Dy\
\x14\xe5\xd0\xbd\x12\x7f.\xdd5\xf7\xa3\x9b\xb9;n\xee~vSw\xcb-\xdc\x89(\x0b\
\xa2L\xc4\xefEw\xd9]qW\xdduQ\x96\xdcmw\xaf)\xdb\xa2|\x12e\xd3\x1d\xbb\xbb\
\xee\x86\xfb\xce}s\xbf\xb9\xf3\xee{\x94\x0f\xeeww\xdf\x9ds\xbf\xba_\xdc\x17\
\xf7\xaf\xfb\xea\xb6<\xd3+\xbd\xf9v\xe5\xf1\xcc\xd8\xd5;e9Y\x13\xcaXO\xc8\
\xb1\x93\xe0\xca\xb0;\x7f\xad\xba\x80\x98\xa9\xd7\xf5\xce\xc5\xf0OD\xa9\xffM\
<&\x86\xc8\xfb\trjb\xae\x04!DLM\x8a\xe2\xa9^\xdb#b\x16Pj\x92\x16]\xcd[m\xc8\
\xd1\xbc\x8e\x17\xa1\x18(+\x82T\xcd[\x14\xcf\x8d\xbc\xc0\xdbj\x88\xf8.,\x8a\
\x9a\xa0\xcfB\xbf\xad\xc9\t\xbd:}_\xcbs<\xd7\xf3\xbc\xdfQ\x91\xf4=_\x94\xa3 \
\x14\x06\xf2\x9aQ\x933\xf0\x12Q\x86\x9eC\xab\xb9&\xc6\xfc\x7f\x91\x8f)\xf6' ))
def getwxPythonBitmap():
return wxBitmapFromXPMData(getwxPythonData())
def getwxPythonImage():
return wxImageFromBitmap(getwxPythonBitmap())
#----------------------------------------------------------------------
def getPythonPoweredData():
return cPickle.loads(zlib.decompress(
'x\xda\xcdXMo\xdb0\x0c\xbd\xf7W\x08\xb0\x9c\x0e\x11"4m\xda\xb50\x0cxE\xbb\
\xe3|\xe8E\xd7\xa2\xd8i\xc5\xb4\xff\x7f\x9aH}\x92\x92\x13\x17]\xd1IH\xa4G\
\xd1~\xa6)\x93\xb4\xbf\xbc\xfe\xd9\x9f=\x9d\xef\xf7\x17\xe2p\x10\xfbk\xb1??{\
~:7\xe2E\xdc\xbf>\xbf\xfcB4;\xd4\xedo\xa1#\x9e\x00?<BG,\x01?~\x85\x8ex\x00|u\
\x07\x1dq\x0f\xf8;6\xc4\x16\xf0\xe1\x12:\xe2\x1d\xe0\x8b[\xe8\x885\xe2\x8b\
\x9b\xabo\xd7\x88G\xc0\x97w\xd0\x11+\xc0\xb7\x07\xe8\x88\x85\xc3?\xec\xef\
\x9f\x086xq7\xd0\x11o\xf1b\xf6\xd0\x11w\x80\xef\x1f\xa0\x87\x83W7\xbd\xd0\
\xdep\x8a\xb5\x94ze\xfb7\x94\xfa\xcd\xed=\x94\xfa\x1d\xed\x8d\x94\x867w\n\
\xd3j\xa7\xe4\xab)\x9d\xaa\x9d\xb1\x03\xb9\x80\x7f\xed\xc7(\x9fq\x9e\xe5\xf1\
\x08\xaeoVS\n5u\xd2\xf5I\xcd0Wx&7\xceA\x8e+\x85\\\x18\xbf\xc2\xf5\x81[\xaf\
\xa0t\xf7\xc4N\xbdoR\xcdn>Yw\n7J\x15\xe5}?)\x99\xe4\x93\x9d\x1d\xaa\xf5q\xac\
\xdcZQ\x82\xe7\xcd\xdc\xf5\x12\xad\xd9H\xb5\xed\xfanv\x87:Y\xb7\x05[$\xacML\
\xee4\x1b\xfa\xb3\xa7\xa4\xa4\x8c\xd2o6c%^/\\\xbb\x84\x1f^5\x8cQ\x06~+\xe4\
\x8a\xe9\xbb\xfbk\xe2z\xb5\x81\te\xdc\xdfx\x85\xa3\xd9\x99\xd1\x8d\x03\xbb\
\xea\xd68\xd0\xb9\x04NbeIZR\xa6\xc5\xcaJ8C\xf2]i]\xe3N\xa0Wa\x85Z\x9993e\xf1\
\x14\x13_\xce\xe0\'5\xe2\xbf\xa0\xd6y\x1d\xd9\xb0\xd2\xe9\x0e\xdc\xcaH\x9a(\
\xcb\x15\xb8\xda\xb4c\xd1>wf\xef!be\x9f\xb4\x98_\xbb\xf0\xb3\x8cR\x97\x94d!Y\
0!\x0b\xda\xb9\t\x8ck\xac\xec\x068B\xd6V"g\xa0\xa4\xf2\xe4\'\xebC\xdf\xac\
\x92\x8d\xab|)\xc3sZ[\t\x9cm\xcahIl%^\xb1c;\xf4F\xd3\xcaD\xa9\x1bV\xda\x1c\
\xa3\x0b\xac\x89\x95K\xcf\xa5\rw\xa6a\xa5^\xa0$V\x96\xb8\x98\xcf+\xa3O\xcc,\
\x94RWV\xe6\xf8\xc8\xb1\xe11\xf4T\x8c\r\x99%\xb76e\xcc\x06\r\xcc3\xc5\xa9L\
\x923\xcaq\xca\x90\x03M\x03\xa79\x1bY\xbe\xcc#\xbbc-J\x7f\xf3w\xd1\x8d<\xdb\
\xa75>\xee\x92\xd2\x8e\x1cR\xc5\xda\x8a\x92T\x04z1\xdb3\xb9H\xcfp\x96\xc79\
\xdf\xb95eY\x11\x98E\x1fQ\xf9\xe8\x10\xd7\xf7\xf3\xa9\x8e\xb5\xd5CB*\x02\xb3\
\xb4\x13\xa9\x1c\xe2i\xa5\x1f\xe6U\xac\xad\x9f\xcb:\x8b4\xab\x03"\x97\x88\
\x98~\x98W\xb1\xb6\x0ex\x18M:\xab\xac\xbb\xba\xa9\x8a*\xc17*\xeb\xc4\xfc8\
\xaa\xa0_\xc8\xbd\xb4g\xd5AM\xb9T\xf7\x0c\xbe\xf6A\xd9@\xb3\x88\xaf\x02\xfc\
\x1a\xcb.U\xacm$/\x92+\xab8\x9a\x7f$W\xe2n\x11x\x07x\x0ee\xb1\xb6\x95\xa2I\
\xae\xe4\xd9\xc2\x86_\xb2\xb2\xa8\xf4L\x99C\x0b\xf9\xc8+\xbd\xaa\x10!\xb9\
\x12k\xd7\xc2\x971\xdb\x07\x9f\rj\x9b\x9f\xbb\x10i\xb2\xbc86Z\xd9.\xb7H\x06\
\x10|\x07nB}\x10\xe5\xc5\x9d \xfa\xf8\xbc\x86y\xf2\xe5RQ\x993@\xac\x07Z5P\
\x94OvWf\x99B\x9e\xe7}X_,\x9dS\x94\x89\x9c$\x9a@\x9c!QF\x90\xacS\xca\xe3<\
\xa2\xe5\x17\x04\x9aEx\xcc\x14E\x9e`\x99\xa3\xa9\x9f\xdf\xdf\x8eP\n\x9a\xc8\
\xcd\xeavJ\xff\xd8\x9b\x17\xad\x1d\xca\x93.\xcc\xd7\xe8\x1f\xa7\x14\xb4Zi\
\xbe1\xebF&=\xa6_\xbe\xdb\x1e\xf9V\xa0\xdf\xdd\xfe\xf3\xcf\x13\x9f\xf8\x11\
\xe6\xb3>5}\xc0\x075\xfd\x17\x19\xafZq' ))
def getPythonPoweredBitmap():
return wxBitmapFromXPMData(getPythonPoweredData())
def getPythonPoweredImage():
return wxImageFromBitmap(getPythonPoweredBitmap())
# The following could appear at the end of (e.g.) the
# otherwise-wxDesigner-generated Python file ErrorDialogs_wdr.py,
# instead of the function of the same name there... However, instead of cut-
# and-pasting, the version here will be imported, so all you need do is
# delete the similarly-named function automatically generated at the end of
# the ..._wdr.py file...
def PythonBitmaps( index ):
if index:
return getPythonPoweredBitmap()
else:
return getwxPythonBitmap()
return wxNullBitmap
PythonBitmaps = wx.lib.PythonBitmaps.PythonBitmaps
getPythonPoweredBitmap = wx.lib.PythonBitmaps.getPythonPoweredBitmap
getPythonPoweredData = wx.lib.PythonBitmaps.getPythonPoweredData
getPythonPoweredImage = wx.lib.PythonBitmaps.getPythonPoweredImage
getwxPythonBitmap = wx.lib.PythonBitmaps.getwxPythonBitmap
getwxPythonData = wx.lib.PythonBitmaps.getwxPythonData
getwxPythonImage = wx.lib.PythonBitmaps.getwxPythonImage

View File

@@ -1,4 +1 @@
#

View File

@@ -1,141 +1,14 @@
#----------------------------------------------------------------------
# Name: wxPython.lib.activexwrapper
# Purpose: a wxWindow derived class that can hold an ActiveX control
#
# Author: Robin Dunn
#
# RCS-ID: $Id$
# Copyright: (c) 2000 by Total Control Software
# Licence: wxWindows license
#----------------------------------------------------------------------
from wxPython.wx import *
try:
import win32ui
import pywin.mfc.activex
import win32com.client
except ImportError:
raise ImportError( "ActiveXWrapper requires PythonWin. Please install the win32all-xxx.exe package.")
##from win32con import WS_TABSTOP, WS_VISIBLE
WS_TABSTOP = 0x00010000
WS_VISIBLE = 0x10000000
#----------------------------------------------------------------------
def MakeActiveXClass(CoClass, eventClass=None, eventObj=None):
"""
Dynamically construct a new class that derives from wxWindow, the
ActiveX control and the appropriate COM classes. This new class
can be used just like the wxWindow class, but will also respond
appropriately to the methods and properties of the COM object. If
this class, a derived class or a mix-in class has method names
that match the COM object's event names, they will be called
automatically.
CoClass -- A COM control class from a module generated by
makepy.py from a COM TypeLibrary. Can also accept a
CLSID.
eventClass -- If given, this class will be added to the set of
base classes that the new class is drived from. It is
good for mix-in classes for catching events.
eventObj -- If given, this object will be searched for attributes
by the new class's __getattr__ method, (like a mix-in
object.) This is useful if you want to catch COM
callbacks in an existing object, (such as the parent
window.)
"""
if type(CoClass) == type(""):
# use the CLSID to get the real class
CoClass = win32com.client.CLSIDToClass(CoClass)
# determine the base classes
axEventClass = CoClass.default_source
baseClasses = [wxWindow, pywin.mfc.activex.Control, CoClass, axEventClass]
if eventClass:
baseClasses.append(eventClass)
baseClasses = tuple(baseClasses)
# define the class attributes
className = 'AXControl_'+CoClass.__name__
classDict = { '__init__' : axw__init__,
'__getattr__' : axw__getattr__,
'axw_OnSize' : axw_OnSize,
'axw_OEB' : axw_OEB,
'_name' : className,
'_eventBase' : axEventClass,
'_eventObj' : eventObj,
'Cleanup' : axw_Cleanup,
}
# make a new class object
import new
classObj = new.classobj(className, baseClasses, classDict)
return classObj
# These functions will be used as methods in the new class
def axw__init__(self, parent, ID, pos=wxDefaultPosition, size=wxDefaultSize, style=0):
# init base classes
pywin.mfc.activex.Control.__init__(self)
wxWindow.__init__(self, parent, -1, pos, size, style|wxNO_FULL_REPAINT_ON_RESIZE)
win32ui.EnableControlContainer()
self._eventObj = self._eventObj # move from class to instance
# create a pythonwin wrapper around this wxWindow
handle = self.GetHandle()
self._wnd = win32ui.CreateWindowFromHandle(handle)
# create the control
sz = self.GetSize()
self.CreateControl(self._name, WS_TABSTOP | WS_VISIBLE,
(0, 0, sz.width, sz.height), self._wnd, ID)
# init the ax events part of the object
self._eventBase.__init__(self, self._dispobj_)
# hook some wx events
EVT_SIZE(self, self.axw_OnSize)
#EVT_ERASE_BACKGROUND(self, self.axw_OEB)
def axw__getattr__(self, attr):
try:
return pywin.mfc.activex.Control.__getattr__(self, attr)
except AttributeError:
try:
eo = self.__dict__['_eventObj']
return getattr(eo, attr)
except AttributeError:
raise AttributeError('Attribute not found: %s' % attr)
def axw_OnSize(self, event):
sz = self.GetClientSize() # get wxWindow size
self.MoveWindow((0, 0, sz.width, sz.height), 1) # move the AXControl
def axw_OEB(self, event):
pass
def axw_Cleanup(self):
del self._wnd
self.close()
pass
## anything else???
## This file imports items from the wx package into the wxPython package for
## backwards compatibility. Some names will also have a 'wx' added on if
## that is how they used to be named in the old wxPython package.
import wx.lib.activexwrapper
__doc__ = wx.lib.activexwrapper.__doc__
MakeActiveXClass = wx.lib.activexwrapper.MakeActiveXClass
axw_Cleanup = wx.lib.activexwrapper.axw_Cleanup
axw_OEB = wx.lib.activexwrapper.axw_OEB
axw_OnSize = wx.lib.activexwrapper.axw_OnSize
axw__getattr__ = wx.lib.activexwrapper.axw__getattr__
axw__init__ = wx.lib.activexwrapper.axw__init__

View File

@@ -1,201 +1,9 @@
#----------------------------------------------------------------------
# Name: wxPython.lib.analogclock
# Purpose: A simple analog clock window
#
# Author: several folks on wxPython-users
#
# Created: 16-April-2003
# RCS-ID: $Id$
# Copyright: (c) 2003 by Total Control Software
# Licence: wxWindows license
#----------------------------------------------------------------------
import math, sys, string, time
from wxPython.wx import *
class AnalogClockWindow(wxWindow):
"""A simple analog clock window"""
TICKS_NONE = 0
TICKS_SQUARE = 1
TICKS_CIRCLE = 2
def __init__(self, parent, ID=-1, pos=wxDefaultPosition, size=wxDefaultSize,
style=0, name="clock"):
# Initialize the wxWindow...
wxWindow.__init__(self, parent, ID, pos, size, style, name)
# Initialize the default clock settings...
self.minuteMarks = 60
self.hourMarks = 12
self.tickMarksBrushC = self.GetForegroundColour()
self.tickMarksPenC = self.GetForegroundColour()
self.tickMarkStyle = self.TICKS_SQUARE
# Make an initial bitmap for the face, it will be updated and
# painted at the first EVT_SIZE event.
W, H = size
self.faceBitmap = wxEmptyBitmap(max(W,1), max(H,1))
# Initialize the timer that drives the update of the clock
# face. Update every half second to ensure that there is at
# least one true update during each realtime second.
self.timer = wxTimer(self)
self.timer.Start(500)
# Set event handlers...
EVT_PAINT(self, self.OnPaint)
EVT_ERASE_BACKGROUND(self, lambda x: None)
EVT_SIZE(self, self.OnSize)
EVT_TIMER(self, -1, self.OnTimerExpire)
EVT_WINDOW_DESTROY(self, self.OnQuit)
def SetTickMarkStyle(self, style):
"""
Set the style of the marks around the edge of the clock.
Options are TICKS_NONE, TICKS_SQUARE, and TICKS_CIRCLE
"""
self.tickMarkStyle = style
def SetTickMarkColours(self, brushC, penC="BLACK"):
"""
Set the brush colour and optionally the pen colour of
the marks around the edge of the clock.
"""
self.tickMarksBrushC = brushC
self.tickMarksPenC = penC
SetTickMarkColour = SetTickMarkColours
def SetHandsColour(self, c):
"""An alias for SetForegroundColour"""
self.SetForegroundColour(c) # the hands just use the foreground colour
# Using the current settings, render the points and line endings for the
# circle inside the specified device context. In this case, the DC is
# a memory based device context that will be blitted to the actual
# display DC inside the OnPaint() event handler.
def OnSize(self, event):
# The faceBitmap init is done here, to make sure the buffer is always
# the same size as the Window
size = self.GetClientSize()
self.faceBitmap = wxEmptyBitmap(size.width, size.height)
self.DrawFace()
def OnPaint(self, event):
self.DrawHands(wxPaintDC(self))
def OnQuit(self, event):
self.timer.Stop()
del self.timer
def OnTimerExpire(self, event):
self.DrawHands(wxClientDC(self))
def DrawHands(self, drawDC):
# Start by drawing the face bitmap
drawDC.DrawBitmap(self.faceBitmap,0,0)
currentTime = time.localtime(time.time())
hour, minutes, seconds = currentTime[3:6]
W,H = self.faceBitmap.GetWidth(), self.faceBitmap.GetHeight()
centerX = W / 2
centerY = H / 2
radius = min(centerX, centerY)
hour += minutes / 60.0 # added so the hour hand moves continuously
x, y = self.point(hour, 12, (radius * .65))
hourX, hourY = (x + centerX), (centerY - y)
x, y = self.point(minutes, 60, (radius * .85))
minutesX, minutesY = (x + centerX), (centerY - y)
x, y = self.point(seconds, 60, (radius * .85))
secondsX, secondsY = (x + centerX), (centerY - y)
# Draw the hour hand...
drawDC.SetPen(wxPen(self.GetForegroundColour(), 5, wxSOLID))
drawDC.DrawLine(centerX, centerY, hourX, hourY)
# Draw the minutes hand...
drawDC.SetPen(wxPen(self.GetForegroundColour(), 3, wxSOLID))
drawDC.DrawLine(centerX, centerY, minutesX, minutesY)
# Draw the seconds hand...
drawDC.SetPen(wxPen(self.GetForegroundColour(), 1, wxSOLID))
drawDC.DrawLine(centerX, centerY, secondsX, secondsY)
# Draw the specified set of line marks inside the clock face for the
# hours or minutes...
def DrawFace(self):
backgroundBrush = wxBrush(self.GetBackgroundColour(), wxSOLID)
drawDC = wxMemoryDC()
drawDC.SelectObject(self.faceBitmap)
drawDC.SetBackground(backgroundBrush)
drawDC.Clear()
W,H = self.faceBitmap.GetWidth(), self.faceBitmap.GetHeight()
centerX = W / 2
centerY = H / 2
# Draw the marks for hours and minutes...
self.DrawTimeMarks(drawDC, self.minuteMarks, centerX, centerY, 4)
self.DrawTimeMarks(drawDC, self.hourMarks, centerX, centerY, 9)
def DrawTimeMarks(self, drawDC, markCount, centerX, centerY, markSize):
for i in range(markCount):
x, y = self.point(i + 1, markCount, min(centerX,centerY) - 16)
scaledX = x + centerX - markSize/2
scaledY = centerY - y - markSize/2
drawDC.SetBrush(wxBrush(self.tickMarksBrushC, wxSOLID))
drawDC.SetPen(wxPen(self.tickMarksPenC, 1, wxSOLID))
if self.tickMarkStyle != self.TICKS_NONE:
if self.tickMarkStyle == self.TICKS_CIRCLE:
drawDC.DrawEllipse(scaledX - 2, scaledY, markSize, markSize)
else:
drawDC.DrawRectangle(scaledX - 3, scaledY, markSize, markSize)
def point(self, tick, range, radius):
angle = tick * (360.0 / range)
radiansPerDegree = math.pi / 180
pointX = int(round(radius * math.sin(angle * radiansPerDegree)))
pointY = int(round(radius * math.cos(angle * radiansPerDegree)))
return wxPoint(pointX, pointY)
if __name__ == "__main__":
class App(wxApp):
def OnInit(self):
frame = wxFrame(None, -1, "AnalogClockWindow Test", size=(375,375))
clock = AnalogClockWindow(frame)
clock.SetTickMarkColours("RED")
clock.SetHandsColour("WHITE")
clock.SetBackgroundColour("BLUE")
frame.Centre(wxBOTH)
frame.Show(True)
self.SetTopWindow(frame)
return true
theApp = App(0)
theApp.MainLoop()
## This file imports items from the wx package into the wxPython package for
## backwards compatibility. Some names will also have a 'wx' added on if
## that is how they used to be named in the old wxPython package.
import wx.lib.analogclock
__doc__ = wx.lib.analogclock.__doc__
AnalogClockWindow = wx.lib.analogclock.AnalogClockWindow

View File

@@ -1,91 +1,9 @@
#----------------------------------------------------------------------
# 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
#----------------------------------------------------------------------
## This file imports items from the wx package into the wxPython package for
## backwards compatibility. Some names will also have a 'wx' added on if
## that is how they used to be named in the old wxPython package.
from wxPython.wx import wxLayoutConstraints, wxTop, wxLeft, wxBottom, wxRight, \
wxHeight, wxWidth
import wx.lib.anchors
class LayoutAnchors(wxLayoutConstraints):
""" A class that implements Delphi's Anchors with wxLayoutConstraints.
__doc__ = wx.lib.anchors.__doc__
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))
LayoutAnchors = wx.lib.anchors.LayoutAnchors

View File

@@ -1,554 +1,14 @@
#----------------------------------------------------------------------
# Name: wxPython.lib.buttons
# Purpose: Various kinds of generic buttons, (not native controls but
# self-drawn.)
#
# Author: Robin Dunn
#
# Created: 9-Dec-1999
# RCS-ID: $Id$
# Copyright: (c) 1999 by Total Control Software
# Licence: wxWindows license
#----------------------------------------------------------------------
## This file reverse renames symbols in the wx package to give
## them their wx prefix again, for backwards compatibility.
"""
This module implements various forms of generic buttons, meaning that
they are not built on native controls but are self-drawn.
The wxGenButton is the base. It acts like a normal button but you
are able to better control how it looks, bevel width, colours, etc.
wxGenBitmapButton is a button with one or more bitmaps that show
the various states the button can be in.
wxGenToggleButton stays depressed when clicked, until clicked again.
wxGenBitmapToggleButton the same but with bitmaps.
"""
from wxPython.wx import *
import imageutils
#----------------------------------------------------------------------
class wxGenButtonEvent(wxPyCommandEvent):
def __init__(self, eventType, ID):
wxPyCommandEvent.__init__(self, eventType, ID)
self.isDown = False
self.theButton = None
def SetIsDown(self, isDown):
self.isDown = isDown
def GetIsDown(self):
return self.isDown
def SetButtonObj(self, btn):
self.theButton = btn
def GetButtonObj(self):
return self.theButton
#----------------------------------------------------------------------
class wxGenButton(wxPyControl):
labelDelta = 1
def __init__(self, parent, ID, label,
pos = wxDefaultPosition, size = wxDefaultSize,
style = 0, validator = wxDefaultValidator,
name = "genbutton"):
if style == 0:
style = wxNO_BORDER
wxPyControl.__init__(self, parent, ID, pos, size, style, validator, name)
self.up = True
self.bezelWidth = 2
self.hasFocus = False
self.useFocusInd = True
self.SetLabel(label)
self.SetPosition(pos)
font = parent.GetFont()
if not font.Ok():
font = wxSystemSettings_GetSystemFont(wxSYS_DEFAULT_GUI_FONT)
self.SetFont(font)
self.SetBestSize(size)
self.InitColours()
EVT_LEFT_DOWN(self, self.OnLeftDown)
EVT_LEFT_UP(self, self.OnLeftUp)
if wxPlatform == '__WXMSW__':
EVT_LEFT_DCLICK(self, self.OnLeftDown)
EVT_MOTION(self, self.OnMotion)
EVT_SET_FOCUS(self, self.OnGainFocus)
EVT_KILL_FOCUS(self, self.OnLoseFocus)
EVT_KEY_DOWN(self, self.OnKeyDown)
EVT_KEY_UP(self, self.OnKeyUp)
EVT_ERASE_BACKGROUND(self, self.OnEraseBackground)
EVT_PAINT(self, self.OnPaint)
def SetBestSize(self, size=None):
"""
Given the current font and bezel width settings, calculate
and set a good size.
"""
if size is None:
size = wxSize(-1,-1)
if type(size) == type(()):
size = wxSize(size[0], size[1])
size = wxSize(size.width, size.height) # make a copy
best = self.GetBestSize()
if size.width == -1:
size.width = best.width
if size.height == -1:
size.height = best.height
self.SetSize(size)
def DoGetBestSize(self):
"""Overridden base class virtual. Determines the best size of the
button based on the label and bezel size."""
w, h, useMin = self._GetLabelSize()
defSize = wxButton_GetDefaultSize()
width = 12 + w
if useMin and width < defSize.width:
width = defSize.width
height = 11 + h
if useMin and height < defSize.height:
height = defSize.height
width = width + self.bezelWidth - 1
height = height + self.bezelWidth - 1
return (width, height)
def AcceptsFocus(self):
"""Overridden base class virtual."""
return self.IsShown() and self.IsEnabled()
def Enable(self, enable=True):
wxPyControl.Enable(self, enable)
self.Refresh()
def SetBezelWidth(self, width):
"""Set the width of the 3D effect"""
self.bezelWidth = width
def GetBezelWidth(self):
"""Return the width of the 3D effect"""
return self.bezelWidth
def SetUseFocusIndicator(self, flag):
"""Specifiy if a focus indicator (dotted line) should be used"""
self.useFocusInd = flag
def GetUseFocusIndicator(self):
"""Return focus indicator flag"""
return self.useFocusInd
def InitColours(self):
faceClr = wxSystemSettings_GetSystemColour(wxSYS_COLOUR_BTNFACE)
textClr = wxSystemSettings_GetSystemColour(wxSYS_COLOUR_BTNTEXT)
self.faceDnClr = faceClr
self.SetBackgroundColour(faceClr)
self.SetForegroundColour(textClr)
shadowClr = wxSystemSettings_GetSystemColour(wxSYS_COLOUR_BTNSHADOW)
highlightClr = wxSystemSettings_GetSystemColour(wxSYS_COLOUR_BTNHIGHLIGHT)
self.shadowPen = wxPen(shadowClr, 1, wxSOLID)
self.highlightPen = wxPen(highlightClr, 1, wxSOLID)
if wxPlatform == "__WXMAC__":
self.focusIndPen = wxPen(textClr, 1, wxSOLID)
else:
self.focusIndPen = wxPen(textClr, 1, wxUSER_DASH)
self.focusIndPen.SetDashes([1,1])
self.focusIndPen.SetCap(wxCAP_BUTT)
self.focusClr = highlightClr
def SetBackgroundColour(self, colour):
wxPyControl.SetBackgroundColour(self, colour)
colour = self.GetBackgroundColour()
# Calculate a new set of highlight and shadow colours based on
# the new background colour. Works okay if the colour is dark...
r, g, b = colour.Get()
fr, fg, fb = min(255,r+32), min(255,g+32), min(255,b+32)
self.faceDnClr = wxColour(fr, fg, fb)
sr, sg, sb = max(0,r-32), max(0,g-32), max(0,b-32)
self.shadowPen = wxPen(wxColour(sr,sg,sb), 1, wxSOLID)
hr, hg, hb = min(255,r+64), min(255,g+64), min(255,b+64)
self.highlightPen = wxPen(wxColour(hr,hg,hb), 1, wxSOLID)
self.focusClr = wxColour(hr, hg, hb)
def _GetLabelSize(self):
""" used internally """
w, h = self.GetTextExtent(self.GetLabel())
return w, h, True
def Notify(self):
evt = wxGenButtonEvent(wxEVT_COMMAND_BUTTON_CLICKED, self.GetId())
evt.SetIsDown(not self.up)
evt.SetButtonObj(self)
evt.SetEventObject(self)
self.GetEventHandler().ProcessEvent(evt)
def DrawBezel(self, dc, x1, y1, x2, y2):
# draw the upper left sides
if self.up:
dc.SetPen(self.highlightPen)
else:
dc.SetPen(self.shadowPen)
for i in range(self.bezelWidth):
dc.DrawLine(x1+i, y1, x1+i, y2-i)
dc.DrawLine(x1, y1+i, x2-i, y1+i)
# draw the lower right sides
if self.up:
dc.SetPen(self.shadowPen)
else:
dc.SetPen(self.highlightPen)
for i in range(self.bezelWidth):
dc.DrawLine(x1+i, y2-i, x2+1, y2-i)
dc.DrawLine(x2-i, y1+i, x2-i, y2)
def DrawLabel(self, dc, width, height, dw=0, dy=0):
dc.SetFont(self.GetFont())
if self.IsEnabled():
dc.SetTextForeground(self.GetForegroundColour())
else:
dc.SetTextForeground(wxSystemSettings_GetSystemColour(wxSYS_COLOUR_GRAYTEXT))
label = self.GetLabel()
tw, th = dc.GetTextExtent(label)
if not self.up:
dw = dy = self.labelDelta
dc.DrawText(label, (width-tw)/2+dw, (height-th)/2+dy)
def DrawFocusIndicator(self, dc, w, h):
bw = self.bezelWidth
## if self.hasFocus:
## self.focusIndPen.SetColour(self.GetForegroundColour())
## else:
## #self.focusIndPen.SetColour(self.GetBackgroundColour())
## self.focusIndPen.SetColour(self.GetForegroundColour())
self.focusIndPen.SetColour(self.focusClr)
dc.SetLogicalFunction(wxINVERT)
dc.SetPen(self.focusIndPen)
dc.SetBrush(wxTRANSPARENT_BRUSH)
dc.DrawRectangle(bw+2,bw+2, w-bw*2-4, h-bw*2-4)
dc.SetLogicalFunction(wxCOPY)
def OnPaint(self, event):
(width, height) = self.GetClientSizeTuple()
x1 = y1 = 0
x2 = width-1
y2 = height-1
dc = wxBufferedPaintDC(self)
if self.up:
dc.SetBackground(wxBrush(self.GetBackgroundColour(), wxSOLID))
else:
dc.SetBackground(wxBrush(self.faceDnClr, wxSOLID))
dc.Clear()
self.DrawBezel(dc, x1, y1, x2, y2)
self.DrawLabel(dc, width, height)
if self.hasFocus and self.useFocusInd:
self.DrawFocusIndicator(dc, width, height)
def OnEraseBackground(self, event):
pass
def OnLeftDown(self, event):
if not self.IsEnabled():
return
self.up = False
self.CaptureMouse()
self.SetFocus()
self.Refresh()
event.Skip()
def OnLeftUp(self, event):
if not self.IsEnabled() or not self.HasCapture():
return
if self.HasCapture():
self.ReleaseMouse()
if not self.up: # if the button was down when the mouse was released...
self.Notify()
self.up = True
self.Refresh()
event.Skip()
def OnMotion(self, event):
if not self.IsEnabled() or not self.HasCapture():
return
if event.LeftIsDown() and self.HasCapture():
x,y = event.GetPositionTuple()
w,h = self.GetClientSizeTuple()
if self.up and x<w and x>=0 and y<h and y>=0:
self.up = False
self.Refresh()
return
if not self.up and (x<0 or y<0 or x>=w or y>=h):
self.up = True
self.Refresh()
return
event.Skip()
def OnGainFocus(self, event):
self.hasFocus = True
dc = wxClientDC(self)
w, h = self.GetClientSizeTuple()
if self.useFocusInd:
self.DrawFocusIndicator(dc, w, h)
def OnLoseFocus(self, event):
self.hasFocus = False
dc = wxClientDC(self)
w, h = self.GetClientSizeTuple()
if self.useFocusInd:
self.DrawFocusIndicator(dc, w, h)
def OnKeyDown(self, event):
if self.hasFocus and event.KeyCode() == ord(" "):
self.up = False
self.Refresh()
event.Skip()
def OnKeyUp(self, event):
if self.hasFocus and event.KeyCode() == ord(" "):
self.up = True
self.Notify()
self.Refresh()
event.Skip()
#----------------------------------------------------------------------
class wxGenBitmapButton(wxGenButton):
def __init__(self, parent, ID, bitmap,
pos = wxDefaultPosition, size = wxDefaultSize,
style = 0, validator = wxDefaultValidator,
name = "genbutton"):
self.bmpDisabled = None
self.bmpFocus = None
self.bmpSelected = None
self.SetBitmapLabel(bitmap)
wxGenButton.__init__(self, parent, ID, "", pos, size, style, validator, name)
def GetBitmapLabel(self):
return self.bmpLabel
def GetBitmapDisabled(self):
return self.bmpDisabled
def GetBitmapFocus(self):
return self.bmpFocus
def GetBitmapSelected(self):
return self.bmpSelected
def SetBitmapDisabled(self, bitmap):
"""Set bitmap to display when the button is disabled"""
self.bmpDisabled = bitmap
def SetBitmapFocus(self, bitmap):
"""Set bitmap to display when the button has the focus"""
self.bmpFocus = bitmap
self.SetUseFocusIndicator(False)
def SetBitmapSelected(self, bitmap):
"""Set bitmap to display when the button is selected (pressed down)"""
self.bmpSelected = bitmap
def SetBitmapLabel(self, bitmap, createOthers=True):
"""
Set the bitmap to display normally.
This is the only one that is required. If
createOthers is True, then the other bitmaps
will be generated on the fly. Currently,
only the disabled bitmap is generated.
"""
self.bmpLabel = bitmap
if bitmap is not None and createOthers:
image = wxImageFromBitmap(bitmap)
imageutils.grayOut(image)
self.SetBitmapDisabled(wxBitmapFromImage(image))
def _GetLabelSize(self):
""" used internally """
if not self.bmpLabel:
return -1, -1, False
return self.bmpLabel.GetWidth()+2, self.bmpLabel.GetHeight()+2, False
def DrawLabel(self, dc, width, height, dw=0, dy=0):
bmp = self.bmpLabel
if self.bmpDisabled and not self.IsEnabled():
bmp = self.bmpDisabled
if self.bmpFocus and self.hasFocus:
bmp = self.bmpFocus
if self.bmpSelected and not self.up:
bmp = self.bmpSelected
bw,bh = bmp.GetWidth(), bmp.GetHeight()
if not self.up:
dw = dy = self.labelDelta
hasMask = bmp.GetMask() != None
dc.DrawBitmap(bmp, (width-bw)/2+dw, (height-bh)/2+dy, hasMask)
#----------------------------------------------------------------------
class wxGenBitmapTextButton(wxGenBitmapButton): # generic bitmapped button with Text Label
def __init__(self, parent, ID, bitmap, label,
pos = wxDefaultPosition, size = wxDefaultSize,
style = 0, validator = wxDefaultValidator,
name = "genbutton"):
wxGenBitmapButton.__init__(self, parent, ID, bitmap, pos, size, style, validator, name)
self.SetLabel(label)
def _GetLabelSize(self):
""" used internally """
w, h = self.GetTextExtent(self.GetLabel())
if not self.bmpLabel:
return w, h, True # if there isn't a bitmap use the size of the text
w_bmp = self.bmpLabel.GetWidth()+2
h_bmp = self.bmpLabel.GetHeight()+2
width = w + w_bmp
if h_bmp > h:
height = h_bmp
else:
height = h
return width, height, True
def DrawLabel(self, dc, width, height, dw=0, dy=0):
bmp = self.bmpLabel
if bmp != None: # if the bitmap is used
if self.bmpDisabled and not self.IsEnabled():
bmp = self.bmpDisabled
if self.bmpFocus and self.hasFocus:
bmp = self.bmpFocus
if self.bmpSelected and not self.up:
bmp = self.bmpSelected
bw,bh = bmp.GetWidth(), bmp.GetHeight()
if not self.up:
dw = dy = self.labelDelta
hasMask = bmp.GetMask() != None
else:
bw = bh = 0 # no bitmap -> size is zero
dc.SetFont(self.GetFont())
if self.IsEnabled():
dc.SetTextForeground(self.GetForegroundColour())
else:
dc.SetTextForeground(wxSystemSettings_GetSystemColour(wxSYS_COLOUR_GRAYTEXT))
label = self.GetLabel()
tw, th = dc.GetTextExtent(label) # size of text
if not self.up:
dw = dy = self.labelDelta
pos_x = (width-bw-tw)/2+dw # adjust for bitmap and text to centre
if bmp !=None:
dc.DrawBitmap(bmp, pos_x, (height-bh)/2+dy, hasMask) # draw bitmap if available
pos_x = pos_x + 2 # extra spacing from bitmap
dc.DrawText(label, pos_x + dw+bw, (height-th)/2+dy) # draw the text
#----------------------------------------------------------------------
class __ToggleMixin:
def SetToggle(self, flag):
self.up = not flag
self.Refresh()
SetValue = SetToggle
def GetToggle(self):
return not self.up
GetValue = GetToggle
def OnLeftDown(self, event):
if not self.IsEnabled():
return
self.saveUp = self.up
self.up = not self.up
self.CaptureMouse()
self.SetFocus()
self.Refresh()
def OnLeftUp(self, event):
if not self.IsEnabled() or not self.HasCapture():
return
if self.HasCapture():
if self.up != self.saveUp:
self.Notify()
self.ReleaseMouse()
self.Refresh()
def OnKeyDown(self, event):
event.Skip()
def OnMotion(self, event):
if not self.IsEnabled():
return
if event.LeftIsDown() and self.HasCapture():
x,y = event.GetPositionTuple()
w,h = self.GetClientSizeTuple()
if x<w and x>=0 and y<h and y>=0:
self.up = not self.saveUp
self.Refresh()
return
if (x<0 or y<0 or x>=w or y>=h):
self.up = self.saveUp
self.Refresh()
return
event.Skip()
def OnKeyUp(self, event):
if self.hasFocus and event.KeyCode() == ord(" "):
self.up = not self.up
self.Notify()
self.Refresh()
event.Skip()
class wxGenToggleButton(__ToggleMixin, wxGenButton):
pass
class wxGenBitmapToggleButton(__ToggleMixin, wxGenBitmapButton):
pass
class wxGenBitmapTextToggleButton(__ToggleMixin, wxGenBitmapTextButton):
pass
#----------------------------------------------------------------------
import wx.lib.buttons
__doc__ = wx.lib.buttons.__doc__
wxGenButtonEvent = wx.lib.buttons.GenButtonEvent
wxGenButton = wx.lib.buttons.GenButton
wxGenBitmapButton = wx.lib.buttons.GenBitmapButton
wxGenBitmapTextButton = wx.lib.buttons.GenBitmapTextButton
wxGenToggleButton = wx.lib.buttons.GenToggleButton
wxGenBitmapToggleButton = wx.lib.buttons.GenBitmapToggleButton
wxGenBitmapTextToggleButton = wx.lib.buttons.GenBitmapTextToggleButton

View File

@@ -1,799 +1,13 @@
#----------------------------------------------------------------------------
# Name: calendar.py
# Purpose: Calendar display control
#
# Author: Lorne White (email: lorne.white@telusplanet.net)
#
# Created:
# Version 0.92
# Date: Nov 26, 2001
# Licence: wxWindows license
#----------------------------------------------------------------------------
from wxPython.wx import *
from CDate import *
CalDays = [6, 0, 1, 2, 3, 4, 5]
AbrWeekday = {6:"Sun", 0:"Mon", 1:"Tue", 2:"Wed", 3:"Thu", 4:"Fri", 5:"Sat"}
_MIDSIZE = 180
BusCalDays = [0, 1, 2, 3, 4, 5, 6]
# calendar drawing routing
def GetMonthList():
monthlist = []
for i in range(13):
name = Month[i]
if name != None:
monthlist.append(name)
return monthlist
class CalDraw:
def __init__(self, parent):
self.pwidth = 1
self.pheight = 1
try:
self.scale = parent.scale
except:
self.scale = 1
self.DefParms()
def DefParms(self):
self.num_auto = True # auto scale of the cal number day size
self.num_size = 12 # default size of calendar if no auto size
self.max_num_size = 12 # maximum size for calendar number
self.num_align_horz = wxALIGN_CENTRE # alignment of numbers
self.num_align_vert = wxALIGN_CENTRE
self.num_indent_horz = 0 # points indent from position, used to offset if not centered
self.num_indent_vert = 0
self.week_auto = True # auto scale of week font text
self.week_size = 10
self.max_week_size = 12
self.grid_color = 'BLACK' # grid and selection colors
self.back_color = 'WHITE'
self.sel_color = 'RED'
self.high_color = 'LIGHT BLUE'
self.border_color = 'BLACK'
self.week_color = 'LIGHT GREY'
self.week_font_color = 'BLACK' # font colors
self.day_font_color = 'BLACK'
self.font = wxSWISS
self.bold = wxNORMAL
self.hide_title = False
self.hide_grid = False
self.outer_border = True
self.title_offset = 0
self.cal_week_scale = 0.7
self.show_weekend = False
self.cal_type = "NORMAL"
def SetWeekColor(self, font_color, week_color): # set font and background color for week title
self.week_font_color = font_color
self.week_color = week_color
def SetSize(self, size):
self.set_sizew = size.width
self.set_sizeh = size.height
def InitValues(self): # default dimensions of various elements of the calendar
self.rg = {}
self.cal_sel = {}
self.set_cy_st = 0 # start position
self.set_cx_st = 0
self.set_y_mrg = 15 # start of vertical draw default
self.set_x_mrg = 10
self.set_y_end = 10
def SetPos(self, xpos, ypos):
self.set_cx_st = xpos
self.set_cy_st = ypos
def SetMarg(self, xmarg, ymarg):
self.set_x_st = xmarg
self.set_y_st = ymarg
self.set_y_end = ymarg
def InitScale(self): # scale position values
self.sizew = self.set_sizew * self.pwidth
self.sizeh = self.set_sizeh * self.pheight
self.cx_st = self.set_cx_st * self.pwidth # draw start position
self.cy_st = self.set_cy_st * self.pheight
self.x_mrg = self.set_x_mrg * self.pwidth # calendar draw margins
self.y_mrg = self.set_y_mrg * self.pheight
self.y_end = self.set_y_end * self.pheight
def DrawCal(self, DC, sel_lst=[]):
self.DC = DC
self.InitScale()
self.DrawBorder()
if self.hide_title is False:
self.DrawMonth()
self.Center()
self.DrawGrid()
self.GetRect()
if self.show_weekend is True: # highlight weekend dates
self.SetWeekEnd()
self.AddSelect(sel_lst) # overrides the weekend highlight
self.DrawSel() # highlighted days
self.DrawWeek()
self.DrawNum()
def AddSelect(self, list, cfont=None, cbackgrd = None):
if cfont is None:
cfont = self.sel_color # font digit color
if cbackgrd is None:
cbackgrd = self.high_color # select background color
for val in list:
self.cal_sel[val] = (cfont, cbackgrd)
def DrawBorder(self): # draw border around the outside of the main display rectangle
brush = wxBrush(wxNamedColour(self.back_color), wxSOLID)
self.DC.SetBrush(brush)
self.DC.SetPen(wxPen(wxNamedColour(self.border_color), 1))
if self.outer_border is True:
rect = wxRect(self.cx_st, self.cy_st, self.sizew, self.sizeh) # full display window area
self.DC.DrawRectangle(rect.x, rect.y, rect.width, rect.height)
def DrawNumVal(self):
self.DrawNum()
# calculate the calendar days and offset position
def SetCal(self, year, month):
self.InitValues() # reset initial values
self.year = year
self.month = month
day = 1
t = Date(year, month, day)
dow = self.dow = t.day_of_week # start day in month
dim = self.dim = t.days_in_month # number of days in month
if self.cal_type == "NORMAL":
start_pos = dow+1
else:
start_pos = dow
self.st_pos = start_pos
self.cal = []
for i in range(start_pos):
self.cal.append('')
i = 1
while i <= dim:
self.cal.append(str(i))
i = i + 1
return start_pos
def SetWeekEnd(self, font_color='BLACK', backgrd = 'LIGHT GREY'):
date = 6 - int(self.dow) # start day of first saturday
while date <= self.dim:
self.cal_sel[date] = (font_color, backgrd) # Saturday
date = date + 1
if date <= self.dim:
self.cal_sel[date] = (font_color, backgrd) # Sunday
date = date + 6
else:
date = date + 7
def GetRect(self): # get the display rectange list of the day grid
cnt = 0
for y in self.gridy[1:-1]:
for x in self.gridx[:-1]:
rect = wxRect(x, y, self.dl_w, self.dl_h) # create rect region
self.rg[cnt] = rect
cnt = cnt + 1
return self.rg
def GetCal(self):
return self.cal
def GetOffset(self):
return self.st_pos
def DrawMonth(self): # month and year title
month = Month[self.month]
sizef = 11
if self.sizeh < _MIDSIZE:
sizef = 10
f = wxFont(sizef, self.font, wxNORMAL, self.bold)
self.DC.SetFont(f)
tw,th = self.DC.GetTextExtent(month)
adjust = self.cx_st + (self.sizew-tw)/2
self.DC.DrawText(month, adjust, self.cy_st + th)
year = str(self.year)
tw,th = self.DC.GetTextExtent(year)
adjust = self.sizew - tw - self.x_mrg
self.title_offset = th * 2
f = wxFont(sizef, self.font, wxNORMAL, self.bold)
self.DC.SetFont(f)
self.DC.DrawText(year, self.cx_st + adjust, self.cy_st + th)
def DrawWeek(self): # draw the week days
width = self.gridx[1]-self.gridx[0]
height = self.gridy[1] - self.gridy[0]
rect_w = self.gridx[7]-self.gridx[0]
f = wxFont(10, self.font, wxNORMAL, self.bold) # initial font setting
if self.week_auto == True:
test_size = self.max_week_size # max size
test_day = ' Sun '
while test_size > 2:
f.SetPointSize(test_size)
self.DC.SetFont(f)
tw,th = self.DC.GetTextExtent(test_day)
if tw < width and th < height:
break
test_size = test_size - 1
else:
f.SetPointSize(self.week_size) # set fixed size
self.DC.SetFont(f)
self.DC.SetTextForeground(wxNamedColour(self.week_font_color))
cnt_x = 0
cnt_y = 0
brush = wxBrush(wxNamedColour(self.week_color), wxSOLID)
self.DC.SetBrush(brush)
# self.DC.DrawRectangle(self.gridx[0], self.gridy[0], rect_w+1, height)
if self.cal_type == "NORMAL":
cal_days = CalDays
else:
cal_days = BusCalDays
for val in cal_days:
day = AbrWeekday[val]
if self.sizew < 200:
day = day[0]
dw,dh = self.DC.GetTextExtent(day)
diffx = (width-dw)/2
diffy = (height-dh)/2
x = self.gridx[cnt_x]
y = self.gridy[cnt_y]
self.DC.DrawRectangle(self.gridx[cnt_x], self.gridy[0], width+1, height)
self.DC.DrawText(day, x+diffx, y+diffy)
cnt_x = cnt_x + 1
def DrawNum(self): # draw the day numbers
f = wxFont(10, self.font, wxNORMAL, self.bold) # initial font setting
if self.num_auto == True:
test_size = self.max_num_size # max size
test_day = ' 99 '
while test_size > 2:
f.SetPointSize(test_size)
self.DC.SetFont(f)
tw,th = self.DC.GetTextExtent(test_day)
if tw < self.dl_w and th < self.dl_h:
sizef = test_size
break
test_size = test_size - 1
else:
f.SetPointSize(self.num_size) # set fixed size
self.DC.SetFont(f)
cnt_x = 0
cnt_y = 1
for val in self.cal:
x = self.gridx[cnt_x]
y = self.gridy[cnt_y]
try:
num_val = int(val)
num_color = self.cal_sel[num_val][0]
except:
num_color = self.day_font_color
self.DC.SetTextForeground(wxNamedColour(num_color))
self.DC.SetFont(f)
tw,th = self.DC.GetTextExtent(val)
if self.num_align_horz == wxALIGN_CENTRE:
adj_h = (self.dl_w - tw)/2
elif self.num_align_horz == wxALIGN_RIGHT:
adj_h = self.dl_w - tw
else:
adj_h = 0 # left alignment
adj_h = adj_h + self.num_indent_horz
if self.num_align_vert == wxALIGN_CENTRE:
adj_v = (self.dl_h - th)/2
elif self.num_align_horz == wxALIGN_RIGHT:
adj_v = self.dl_h - th
else:
adj_v = 0 # left alignment
adj_v = adj_v + self.num_indent_vert
self.DC.DrawText(val, x+adj_h, y+adj_v)
if cnt_x < 6:
cnt_x = cnt_x + 1
else:
cnt_x = 0
cnt_y = cnt_y + 1
def Center(self): # calculate the dimensions in the center of the drawing area
bdw = self.x_mrg * 2
bdh = self.y_mrg + self.y_end + self.title_offset
self.dl_w = int((self.sizew-bdw)/7)
self.dl_h = int((self.sizeh-bdh)/7)
self.dl_th = int(self.dl_h*self.cal_week_scale) # week title adjustment
self.cwidth = self.dl_w * 7
self.cheight = self.dl_h * 6 + self.dl_th
def DrawSel(self): # highlighted selected days
for key in self.cal_sel.keys():
sel_color = self.cal_sel[key][1]
brush = wxBrush(wxNamedColour(sel_color), wxSOLID)
self.DC.SetBrush(brush)
if self.hide_grid is False:
self.DC.SetPen(wxPen(wxNamedColour(self.grid_color), 0))
else:
self.DC.SetPen(wxPen(wxNamedColour(self.back_color), 0))
nkey = key + self.st_pos -1
rect = self.rg[nkey]
self.DC.DrawRectangle(rect.x, rect.y, rect.width+1, rect.height+1)
def DrawGrid(self): # calculate and draw the grid lines
self.DC.SetPen(wxPen(wxNamedColour(self.grid_color), 0))
self.gridx = []
self.gridy = []
self.x_st = self.cx_st + self.x_mrg
self.y_st = self.cy_st + self.y_mrg + self.title_offset # start postion of draw
x1 = self.x_st
y1 = self.y_st
y2 = y1 + self.cheight
for i in range(8):
if self.hide_grid is False:
self.DC.DrawLine(x1, y1, x1, y2)
self.gridx.append(x1)
x1 = x1 + self.dl_w
x1 = self.x_st
y1 = self.y_st
x2 = x1 + self.cwidth
for i in range(8):
if self.hide_grid is False:
self.DC.DrawLine(x1, y1, x2, y1)
self.gridy.append(y1)
if i == 0:
y1 = y1 + self.dl_th
else:
y1 = y1 + self.dl_h
class PrtCalDraw(CalDraw):
def InitValues(self):
self.rg = {}
self.cal_sel = {}
self.set_cx_st = 1.0 # start draw border location
self.set_cy_st = 1.0
self.set_y_mrg = 0.2 # draw offset position
self.set_x_mrg = 0.2
self.set_y_end = 0.2
def SetPSize(self, pwidth, pheight): # calculate the dimensions in the center of the drawing area
self.pwidth = int(pwidth)/self.scale
self.pheight = int(pheight)/self.scale
def SetPreview(self, preview):
self.preview = preview
class wxCalendar(wxWindow):
def __init__(self, parent, id, pos=wxDefaultPosition, size=wxDefaultSize):
wxWindow.__init__(self, parent, id, pos, size)
# set the calendar control attributes
self.grid_color = 'BLACK'
self.back_color = 'WHITE'
self.hide_grid = False
self.sel_color = 'RED'
self.hide_title = False
self.show_weekend = False
self.cal_type = "NORMAL"
self.week_color = 'LIGHT GREY'
self.week_font_color = 'BLACK' # font colors
self.select_list = []
self.SetBackgroundColour(wxNamedColor(self.back_color))
self.Connect(-1, -1, wxEVT_LEFT_DOWN, self.OnLeftEvent)
self.Connect(-1, -1, wxEVT_LEFT_DCLICK, self.OnLeftDEvent)
self.Connect(-1, -1, wxEVT_RIGHT_DOWN, self.OnRightEvent)
self.Connect(-1, -1, wxEVT_RIGHT_DCLICK, self.OnRightDEvent)
self.sel_key = None # last used by
self.sel_lst = [] # highlighted selected days
self.SetNow() # default calendar for current month
self.size = None
self.set_day = None
EVT_PAINT(self, self.OnPaint)
EVT_SIZE(self, self.OnSize)
# control some of the main calendar attributes
def HideTitle(self):
self.hide_title = True
def HideGrid(self):
self.hide_grid = True
# determine the calendar rectangle click area and draw a selection
def ProcessClick(self, event):
self.x, self.y = event.GetX(), event.GetY()
key = self.GetDayHit(self.x, self.y)
self.SelectDay(key)
# tab mouse click events and process
def OnLeftEvent(self, event):
self.click = 'LEFT'
self.shiftkey = event.ShiftDown()
self.ctrlkey = event.ControlDown()
self.ProcessClick(event)
def OnLeftDEvent(self, event):
self.click = 'DLEFT'
self.ProcessClick(event)
def OnRightEvent(self, event):
self.click = 'RIGHT'
self.ProcessClick(event)
def OnRightDEvent(self, event):
self.click = 'DRIGHT'
self.ProcessClick(event)
def SetSize(self, set_size):
self.size = set_size
def SetSelDay(self, sel):
self.sel_lst = sel # list of highlighted days
# get the current date
def SetNow(self):
dt = now()
self.month = dt.month
self.year = dt.year
self.day = dt.day
# set the current day
def SetCurrentDay(self):
self.SetNow()
self.set_day = self.day
# get the date, day, month, year set in calendar
def GetDate(self):
return self.day, self.month, self.year
def GetDay(self):
return self.day
def GetMonth(self):
return self.month
def GetYear(self):
return self.year
# set the day, month, and year
def SetDayValue(self, day):
self.set_day = day
def SetMonth(self, month):
if month >= 1 and month <= 12:
self.month = month
else:
self.month = 1
self.set_day = None
def SetYear(self, year):
self.year = year
# increment year and month
def IncYear(self):
self.year = self.year + 1
self.set_day = None
def DecYear(self):
self.year = self.year - 1
self.set_day = None
def IncMonth(self):
self.month = self.month + 1
if self.month > 12:
self.month = 1
self.year = self.year + 1
self.set_day = None
def DecMonth(self):
self.month = self.month - 1
if self.month < 1:
self.month = 12
self.year = self.year - 1
self.set_day = None
# test to see if the selection has a date and create event
def TestDay(self, key):
try:
self.day = int(self.cal[key])
except:
return None
if self.day == "":
return None
else:
evt = wxPyCommandEvent(2100, self.GetId())
evt.click, evt.day, evt.month, evt.year = self.click, self.day, self.month, self.year
evt.shiftkey = self.shiftkey
evt.ctrlkey = self.ctrlkey
self.GetEventHandler().ProcessEvent(evt)
self.set_day = self.day
return key
# find the clicked area rectangle
def GetDayHit(self, mx, my):
for key in self.rg.keys():
val = self.rg[key]
ms_rect = wxRect(mx, my, 1, 1)
if wxIntersectRect(ms_rect, val) is not None:
result = self.TestDay(key)
return result
return None
# calendar drawing
def SetWeekColor(self, font_color, week_color): # set font and background color for week title
self.week_font_color = font_color
self.week_color = week_color
def AddSelect(self, list, font_color, back_color):
list_val = [list, font_color, back_color]
self.select_list.append(list_val)
def ShowWeekEnd(self):
self.show_weekend = True # highlight weekend
def SetBusType(self):
self.cal_type = "BUS"
def OnSize(self, evt):
self.Refresh(False)
evt.Skip()
def OnPaint(self, event):
DC = wxPaintDC(self)
self.DoDrawing(DC)
def DoDrawing(self, DC):
DC = wxPaintDC(self)
DC.BeginDrawing()
self.cal = cal = CalDraw(self)
cal.grid_color = self.grid_color
cal.back_color = self.back_color
cal.hide_grid = self.hide_grid
cal.grid_color = self.grid_color
cal.hide_title = self.hide_title
cal.show_weekend = self.show_weekend
cal.cal_type = self.cal_type
if self.size is None:
size = self.GetClientSize()
else:
size = self.size
# drawing attributes
cal.week_font_color = self.week_font_color
cal.week_color = self.week_color
cal.SetSize(size)
cal.SetCal(self.year, self.month)
for val in self.select_list:
cal.AddSelect(val[0], val[1], val[2])
cal.DrawCal(DC, self.sel_lst)
self.rg = cal.GetRect()
self.cal = cal.GetCal()
self.st_pos = cal.GetOffset()
self.ymax = DC.MaxY()
if self.set_day != None:
self.SetDay(self.set_day)
DC.EndDrawing()
# draw the selection rectangle
def DrawRect(self, key, color = 'BLACK', width = 0):
if key == None:
return
DC = wxClientDC(self)
DC.BeginDrawing()
brush = wxBrush(wxColour(0, 0xFF, 0x80), wxTRANSPARENT)
DC.SetBrush(brush)
DC.SetPen(wxPen(wxNamedColour(color), width))
rect = self.rg[key]
DC.DrawRectangle(rect.x, rect.y, rect.width+1, rect.height+1)
DC.EndDrawing()
# set the day selection
def SetDay(self, day):
day = day + self.st_pos - 1
self.SelectDay(day)
def SelectDay(self, key):
sel_size = 1
self.DrawRect(self.sel_key, self.back_color, sel_size) # clear large selection
if self.hide_grid is False:
self.DrawRect(self.sel_key, self.grid_color)
self.DrawRect(key, self.sel_color, sel_size)
self.sel_key = key # store last used by
self.select_day = None
def ClearDsp(self):
self.Clear()
class CalenDlg(wxDialog):
def __init__(self, parent, month=None, day = None, year=None):
wxDialog.__init__(self, parent, -1, "Event Calendar", wxPyDefaultPosition, wxSize(280, 360))
# set the calendar and attributes
self.calend = wxCalendar(self, -1, wxPoint(20, 60), wxSize(240, 200))
if month == None:
self.calend.SetCurrentDay()
start_month = self.calend.GetMonth()
start_year = self.calend.GetYear()
else:
self.calend.month = start_month = month
self.calend.year = start_year = year
self.calend.SetDayValue(day)
self.calend.HideTitle()
self.ResetDisplay()
# get month list from DateTime
monthlist = GetMonthList()
# select the month
mID = wxNewId()
self.date = wxComboBox(self, mID, Month[start_month], wxPoint(20, 20), wxSize(90, -1), monthlist, wxCB_DROPDOWN)
EVT_COMBOBOX(self, mID, self.EvtComboBox)
# alternate spin button to control the month
mID = wxNewId()
h = self.date.GetSize().height
self.m_spin = wxSpinButton(self, mID, wxPoint(130, 20), wxSize(h*2, h), wxSP_VERTICAL)
self.m_spin.SetRange(1, 12)
self.m_spin.SetValue(start_month)
EVT_SPIN(self, mID, self.OnMonthSpin)
# spin button to control the year
mID = wxNewId()
self.dtext = wxTextCtrl(self, -1, str(start_year), wxPoint(160, 20), wxSize(60, -1))
h = self.dtext.GetSize().height
self.y_spin = wxSpinButton(self, mID, wxPoint(220, 20), wxSize(h*2, h), wxSP_VERTICAL)
self.y_spin.SetRange(1980, 2010)
self.y_spin.SetValue(start_year)
EVT_SPIN(self, mID, self.OnYrSpin)
self.Connect(self.calend.GetId(), -1, 2100, self.MouseClick)
x_pos = 50
y_pos = 280
but_size = wxSize(60, 25)
mID = wxNewId()
wxButton(self, mID, ' Ok ', wxPoint(x_pos, y_pos), but_size)
EVT_BUTTON(self, mID, self.OnOk)
mID = wxNewId()
wxButton(self, mID, ' Close ', wxPoint(x_pos + 120, y_pos), but_size)
EVT_BUTTON(self, mID, self.OnCancel)
def OnOk(self, event):
self.EndModal(wxID_OK)
def OnCancel(self, event):
self.EndModal(wxID_CANCEL)
# log the mouse clicks
def MouseClick(self, evt):
self.month = evt.month
self.result = [evt.click, str(evt.day), Month[evt.month], str(evt.year)] # result click type and date
if evt.click == 'DLEFT':
self.EndModal(wxID_OK)
# month and year spin selection routines
def OnMonthSpin(self, event):
month = event.GetPosition()
self.date.SetValue(Month[month])
self.calend.SetMonth(month)
self.calend.Refresh()
def OnYrSpin(self, event):
year = event.GetPosition()
self.dtext.SetValue(str(year))
self.calend.SetYear(year)
self.calend.Refresh()
def EvtComboBox(self, event):
name = event.GetString()
monthval = self.date.FindString(name)
self.m_spin.SetValue(monthval+1)
self.calend.SetMonth(monthval+1)
self.ResetDisplay()
# set the calendar for highlighted days
def ResetDisplay(self):
month = self.calend.GetMonth()
self.calend.Refresh()
## This file imports items from the wx package into the wxPython package for
## backwards compatibility. Some names will also have a 'wx' added on if
## that is how they used to be named in the old wxPython package.
import wx.lib.calendar
__doc__ = wx.lib.calendar.__doc__
CalDraw = wx.lib.calendar.CalDraw
CalenDlg = wx.lib.calendar.CalenDlg
GetMonthList = wx.lib.calendar.GetMonthList
PrtCalDraw = wx.lib.calendar.PrtCalDraw
wxCalendar = wx.lib.calendar.wxCalendar

View File

@@ -1,26 +1 @@
"""
wxPyColourChooser
Copyright (C) 2002 Michael Gilfix <mgilfix@eecs.tufts.edu>
This file is part of wxPyColourChooser.
This version of wxPyColourChooser is open source; you can redistribute it
and/or modify it under the licensed terms.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
"""
from pycolourchooser import *
# For the American in you
wxPyColorChooser = wxPyColourChooser
__all__ = [
'canvas',
'pycolourbox',
'pycolourchooser',
'pycolourslider',
'pypalette',
]
#

View File

@@ -1,120 +1,10 @@
"""
wxPyColourChooser
Copyright (C) 2002 Michael Gilfix <mgilfix@eecs.tufts.edu>
## This file imports items from the wx package into the wxPython package for
## backwards compatibility. Some names will also have a 'wx' added on if
## that is how they used to be named in the old wxPython package.
This file is part of wxPyColourChooser.
import wx.lib.colourchooser.canvas
This version of wxPyColourChooser is open source; you can redistribute it
and/or modify it under the licensed terms.
__doc__ = wx.lib.colourchooser.canvas.__doc__
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
"""
from wxPython.wx import *
class BitmapBuffer(wxMemoryDC):
"""A screen buffer class.
This class implements a screen output buffer. Data is meant to
be drawn in the buffer class and then blitted directly to the
output device, or on-screen window.
"""
def __init__(self, width, height, colour):
"""Initialize the empty buffer object."""
wxMemoryDC.__init__(self)
self.width = width
self.height = height
self.colour = colour
self.bitmap = wxEmptyBitmap(self.width, self.height)
self.SelectObject(self.bitmap)
# Initialize the buffer to the background colour
self.SetBackground(wxBrush(self.colour, wxSOLID))
self.Clear()
# Make each logical unit of the buffer equal to 1 pixel
self.SetMapMode(wxMM_TEXT)
def GetBitmap(self):
"""Returns the internal bitmap for direct drawing."""
return self.bitmap
class Canvas(wxWindow):
"""A canvas class for arbitrary drawing.
The Canvas class implements a window that allows for drawing
arbitrary graphics. It implements a double buffer scheme and
blits the off-screen buffer to the window during paint calls
by the windowing system for speed.
Some other methods for determining the canvas colour and size
are also provided.
"""
def __init__(self, parent, id,
pos=wxDefaultPosition,
size=wxDefaultSize,
style=wxSIMPLE_BORDER):
"""Creates a canvas instance and initializes the off-screen
buffer. Also sets the handler for rendering the canvas
automatically via size and paint calls from the windowing
system."""
wxWindow.__init__(self, parent, id, pos, size, style)
# Perform an intial sizing
self.ReDraw()
# Register event handlers
EVT_SIZE(self, self.onSize)
EVT_PAINT(self, self.onPaint)
def MakeNewBuffer(self):
size = self.GetSizeTuple()
self.buffer = BitmapBuffer(size[0], size[1],
self.GetBackgroundColour())
def onSize(self, event):
"""Perform actual redraw to off-screen buffer only when the
size of the canvas has changed. This saves a lot of computation
since the same image can be re-used, provided the canvas size
hasn't changed."""
self.MakeNewBuffer()
self.DrawBuffer()
self.Refresh()
def ReDraw(self):
"""Explicitly tells the canvas to redraw it's contents."""
self.onSize(None)
def Refresh(self):
"""Re-draws the buffer contents on-screen."""
dc = wxClientDC(self)
self.Blit(dc)
def onPaint(self, event):
"""Renders the off-screen buffer on-screen."""
dc = wxPaintDC(self)
self.Blit(dc)
def Blit(self, dc):
"""Performs the blit of the buffer contents on-screen."""
width, height = self.buffer.GetSize()
dc.BeginDrawing()
dc.Blit(0, 0, width, height, self.buffer, 0, 0)
dc.EndDrawing()
def GetBoundingRect(self):
"""Returns a tuple that contains the co-ordinates of the
top-left and bottom-right corners of the canvas."""
x, y = self.GetPositionTuple()
w, h = self.GetSize()
return(x, y + h, x + w, y)
def DrawBuffer(self):
"""Actual drawing function for drawing into the off-screen
buffer. To be overrideen in the implementing class. Do nothing
by default."""
pass
BitmapBuffer = wx.lib.colourchooser.canvas.BitmapBuffer
Canvas = wx.lib.colourchooser.canvas.Canvas

View File

@@ -1,24 +1,8 @@
"""
wxPyColourChooser
Copyright (C) 2002 Michael Gilfix <mgilfix@eecs.tufts.edu>
## This file imports items from the wx package into the wxPython package for
## backwards compatibility. Some names will also have a 'wx' added on if
## that is how they used to be named in the old wxPython package.
This file is part of wxPyColourChooser.
import wx.lib.colourchooser.intl
This version of wxPyColourChooser is open source; you can redistribute it
and/or modify it under the licensed terms.
__doc__ = wx.lib.colourchooser.intl.__doc__
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
"""
try:
import gettext
gettext.bindtextdomain('wxpycolourchooser')
gettext.textdomain('wxpycolourchooser')
_ = gettext.gettext
except Exception, strerror:
print "Warning: Couldn't import translation function: %(str)s" %{ 'str' : strerror }
print "Defaulting to En"
_ = lambda x: x

View File

@@ -1,79 +1,9 @@
"""
wxPyColourChooser
Copyright (C) 2002 Michael Gilfix <mgilfix@eecs.tufts.edu>
## This file imports items from the wx package into the wxPython package for
## backwards compatibility. Some names will also have a 'wx' added on if
## that is how they used to be named in the old wxPython package.
This file is part of wxPyColourChooser.
import wx.lib.colourchooser.pycolourbox
This version of wxPyColourChooser is open source; you can redistribute it
and/or modify it under the licensed terms.
__doc__ = wx.lib.colourchooser.pycolourbox.__doc__
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
"""
from wxPython.wx import *
class PyColourBox(wxPanel):
"""A Colour Selection Box
The Colour selection box implements button like behavior but contains
a solid-filled, coloured sub-box. Placing the colour in a sub-box allows
for filling in the main panel's background for a high-lighting effect.
"""
def __init__(self, parent, id, colour=(0, 0, 0), size=(25, 20)):
"""Creates a new colour box instance and initializes the colour
content."""
wxPanel.__init__(self, parent, id,
size=wxSize(size[0], size[1]))
self.colour_box = wxPanel(self, -1, style=wxSIMPLE_BORDER)
sizer = wxGridSizer(1, 1)
sizer.Add(self.colour_box, 0, wxALIGN_CENTER_VERTICAL | wxALIGN_CENTER_HORIZONTAL)
sizer.SetItemMinSize(self.colour_box, size[0] - 5, size[1] - 5)
self.SetAutoLayout(True)
self.SetSizer(sizer)
self.Layout()
self.real_bg = self.GetBackgroundColour()
self.SetColourTuple(colour)
def GetColourBox(self):
"""Returns a reference to the internal box object containing the
color. This function is useful for setting up event handlers for
the box."""
return self.colour_box
def GetColour(self):
"""Returns a wxColour object indicating the box's current colour."""
return self.colour_box.GetBackgroundColour()
def SetColour(self, colour):
"""Accepts a wxColour object and sets the box's current color."""
self.colour_box.SetBackgroundColour(colour)
self.colour_box.Refresh()
def SetColourTuple(self, colour):
"""Sets the box's current couple to the given tuple."""
self.colour = colour
self.colour_box.SetBackgroundColour(wxColour(*self.colour))
def Update(self):
wxPanel.Update(self)
self.colour_box.Update()
def SetHighlight(self, val):
"""Accepts a boolean 'val' toggling the box's highlighting."""
# XXX This code has been disabled for now until I can figure out
# how to get this to work reliably across all platforms.
if val:
#A wxColourPtr is returned in windows, making this difficult
red =(self.real_bg.Red() - 45) % 255
green =(self.real_bg.Green() - 45) % 255
blue =(self.real_bg.Blue() - 45) % 255
new_colour = wxColour(red, green, blue)
self.SetBackgroundColour(new_colour)
else:
self.SetBackgroundColour(self.real_bg)
self.Refresh()
PyColourBox = wx.lib.colourchooser.pycolourbox.PyColourBox

View File

@@ -1,385 +1,10 @@
"""
wxPyColourChooser
Copyright (C) 2002 Michael Gilfix <mgilfix@eecs.tufts.edu>
## This file imports items from the wx package into the wxPython package for
## backwards compatibility. Some names will also have a 'wx' added on if
## that is how they used to be named in the old wxPython package.
This file is part of wxPyColourChooser.
import wx.lib.colourchooser.pycolourchooser
This version of wxPyColourChooser is open source; you can redistribute it
and/or modify it under the licensed terms.
__doc__ = wx.lib.colourchooser.pycolourchooser.__doc__
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
"""
import pycolourbox
import pypalette
import pycolourslider
import colorsys
from intl import _
from wxPython.wx import *
class wxPyColourChooser(wxPanel):
"""A Pure-Python implementation of the colour chooser dialog.
The PyColourChooser is a pure python implementation of the colour
chooser dialog. It's useful for embedding the colour choosing functionality
inside other widgets, when the pop-up dialog is undesirable. It can also
be used as a drop-in replacement on the GTK platform, as the native
dialog is kind of ugly.
"""
colour_names = [
'ORANGE',
'GOLDENROD',
'WHEAT',
'SPRING GREEN',
'SKY BLUE',
'SLATE BLUE',
'MEDIUM VIOLET RED',
'PURPLE',
'RED',
'YELLOW',
'MEDIUM SPRING GREEN',
'PALE GREEN',
'CYAN',
'LIGHT STEEL BLUE',
'ORCHID',
'LIGHT MAGENTA',
'BROWN',
'YELLOW',
'GREEN',
'CADET BLUE',
'MEDIUM BLUE',
'MAGENTA',
'MAROON',
'ORANGE RED',
'FIREBRICK',
'CORAL',
'FOREST GREEN',
'AQUAMARINE',
'BLUE',
'NAVY',
'THISTLE',
'MEDIUM VIOLET RED',
'INDIAN RED',
'GOLD',
'MEDIUM SEA GREEN',
'MEDIUM BLUE',
'MIDNIGHT BLUE',
'GREY',
'PURPLE',
'KHAKI',
'BLACK',
'MEDIUM FOREST GREEN',
'KHAKI',
'DARK GREY',
'SEA GREEN',
'LIGHT GREY',
'MEDIUM SLATE BLUE',
'WHITE',
]
# Generate the custom colours. These colours are shared across
# all instances of the colour chooser
NO_CUSTOM_COLOURS = 16
custom_colours = [ (wxColour(255, 255, 255),
pycolourslider.PyColourSlider.HEIGHT / 2)
] * NO_CUSTOM_COLOURS
last_custom = 0
idADD_CUSTOM = wxNewId()
idSCROLL = wxNewId()
def __init__(self, parent, id):
"""Creates an instance of the colour chooser. Note that it is best to
accept the given size of the colour chooser as it is currently not
resizeable."""
wxPanel.__init__(self, parent, id)
self.basic_label = wxStaticText(self, -1, _("Basic Colours:"))
self.custom_label = wxStaticText(self, -1, _("Custom Colours:"))
self.add_button = wxButton(self, self.idADD_CUSTOM, _("Add to Custom Colours"))
EVT_BUTTON(self, self.idADD_CUSTOM, self.onAddCustom)
# Since we're going to be constructing widgets that require some serious
# computation, let's process any events (like redraws) right now
wxYield()
# Create the basic colours palette
self.colour_boxs = [ ]
colour_grid = wxGridSizer(6, 8)
for name in self.colour_names:
new_id = wxNewId()
box = pycolourbox.PyColourBox(self, new_id)
EVT_LEFT_DOWN(box.GetColourBox(), lambda x, b=box: self.onBasicClick(x, b))
self.colour_boxs.append(box)
colour_grid.Add(box, 0, wxEXPAND)
# Create the custom colours palette
self.custom_boxs = [ ]
custom_grid = wxGridSizer(2, 8)
for wxcolour, slidepos in self.custom_colours:
new_id = wxNewId()
custom = pycolourbox.PyColourBox(self, new_id)
EVT_LEFT_DOWN(custom.GetColourBox(), lambda x, b=custom: self.onCustomClick(x, b))
custom.SetColour(wxcolour)
custom_grid.Add(custom, 0, wxEXPAND)
self.custom_boxs.append(custom)
csizer = wxBoxSizer(wxVERTICAL)
csizer.Add(1, 25)
csizer.Add(self.basic_label, 0, wxEXPAND)
csizer.Add(1, 5)
csizer.Add(colour_grid, 0, wxEXPAND)
csizer.Add(1, 25)
csizer.Add(self.custom_label, 0, wxEXPAND)
csizer.Add(1, 5)
csizer.Add(custom_grid, 0, wxEXPAND)
csizer.Add(1, 5)
csizer.Add(self.add_button, 0, wxEXPAND)
self.palette = pypalette.PyPalette(self, -1)
self.colour_slider = pycolourslider.PyColourSlider(self, -1)
self.slider = wxSlider(self, self.idSCROLL, 86, 0, self.colour_slider.HEIGHT - 1,
style=wxSL_VERTICAL, size=wxSize(15, self.colour_slider.HEIGHT))
EVT_COMMAND_SCROLL(self, self.idSCROLL, self.onScroll)
psizer = wxBoxSizer(wxHORIZONTAL)
psizer.Add(self.palette, 0, 0)
psizer.Add(10, 1)
psizer.Add(self.colour_slider, 0, wxALIGN_CENTER_VERTICAL)
psizer.Add(self.slider, 0, wxALIGN_CENTER_VERTICAL)
# Register mouse events for dragging across the palette
EVT_LEFT_DOWN(self.palette, self.onPaletteDown)
EVT_LEFT_UP(self.palette, self.onPaletteUp)
EVT_MOTION(self.palette, self.onPaletteMotion)
self.mouse_down = False
self.solid = pycolourbox.PyColourBox(self, -1, size=wxSize(75, 50))
slabel = wxStaticText(self, -1, _("Solid Colour"))
ssizer = wxBoxSizer(wxVERTICAL)
ssizer.Add(self.solid, 0, 0)
ssizer.Add(1, 2)
ssizer.Add(slabel, 0, wxALIGN_CENTER_HORIZONTAL)
hlabel = wxStaticText(self, -1, _("H:"))
self.hentry = wxTextCtrl(self, -1)
self.hentry.SetSize((40, -1))
slabel = wxStaticText(self, -1, _("S:"))
self.sentry = wxTextCtrl(self, -1)
self.sentry.SetSize((40, -1))
vlabel = wxStaticText(self, -1, _("V:"))
self.ventry = wxTextCtrl(self, -1)
self.ventry.SetSize((40, -1))
hsvgrid = wxFlexGridSizer(1, 6, 2, 2)
hsvgrid.AddMany ([
(hlabel, 0, wxALIGN_CENTER_VERTICAL), (self.hentry, 0, 0),
(slabel, 0, wxALIGN_CENTER_VERTICAL), (self.sentry, 0, 0),
(vlabel, 0, wxALIGN_CENTER_VERTICAL), (self.ventry, 0, 0),
])
rlabel = wxStaticText(self, -1, _("R:"))
self.rentry = wxTextCtrl(self, -1)
self.rentry.SetSize((40, -1))
glabel = wxStaticText(self, -1, _("G:"))
self.gentry = wxTextCtrl(self, -1)
self.gentry.SetSize((40, -1))
blabel = wxStaticText(self, -1, _("B:"))
self.bentry = wxTextCtrl(self, -1)
self.bentry.SetSize((40, -1))
lgrid = wxFlexGridSizer(1, 6, 2, 2)
lgrid.AddMany([
(rlabel, 0, wxALIGN_CENTER_VERTICAL), (self.rentry, 0, 0),
(glabel, 0, wxALIGN_CENTER_VERTICAL), (self.gentry, 0, 0),
(blabel, 0, wxALIGN_CENTER_VERTICAL), (self.bentry, 0, 0),
])
gsizer = wxGridSizer(2, 1)
gsizer.SetVGap (10)
gsizer.SetHGap (2)
gsizer.Add(hsvgrid, 0, wxALIGN_CENTER_VERTICAL | wxALIGN_CENTER_HORIZONTAL)
gsizer.Add(lgrid, 0, wxALIGN_CENTER_VERTICAL | wxALIGN_CENTER_HORIZONTAL)
hsizer = wxBoxSizer(wxHORIZONTAL)
hsizer.Add(ssizer, 0, wxALIGN_CENTER_VERTICAL | wxALIGN_CENTER_HORIZONTAL)
hsizer.Add(gsizer, 0, wxALIGN_CENTER_VERTICAL | wxALIGN_CENTER_HORIZONTAL)
vsizer = wxBoxSizer(wxVERTICAL)
vsizer.Add(1, 5)
vsizer.Add(psizer, 0, 0)
vsizer.Add(1, 15)
vsizer.Add(hsizer, 0, wxEXPAND)
sizer = wxBoxSizer(wxHORIZONTAL)
sizer.Add(5, 1)
sizer.Add(csizer, 0, wxEXPAND)
sizer.Add(10, 1)
sizer.Add(vsizer, 0, wxEXPAND)
self.SetAutoLayout(True)
self.SetSizer(sizer)
sizer.Fit(self)
self.InitColours()
self.UpdateColour(self.solid.GetColour())
def InitColours(self):
"""Initializes the pre-set palette colours."""
for i in range(len(self.colour_names)):
colour = wxTheColourDatabase.FindColour(self.colour_names[i])
self.colour_boxs[i].SetColourTuple((colour.Red(),
colour.Green(),
colour.Blue()))
def onBasicClick(self, event, box):
"""Highlights the selected colour box and updates the solid colour
display and colour slider to reflect the choice."""
if hasattr(self, '_old_custom_highlight'):
self._old_custom_highlight.SetHighlight(False)
if hasattr(self, '_old_colour_highlight'):
self._old_colour_highlight.SetHighlight(False)
box.SetHighlight(True)
self._old_colour_highlight = box
self.UpdateColour(box.GetColour())
def onCustomClick(self, event, box):
"""Highlights the selected custom colour box and updates the solid
colour display and colour slider to reflect the choice."""
if hasattr(self, '_old_colour_highlight'):
self._old_colour_highlight.SetHighlight(False)
if hasattr(self, '_old_custom_highlight'):
self._old_custom_highlight.SetHighlight(False)
box.SetHighlight(True)
self._old_custom_highlight = box
# Update the colour panel and then the slider accordingly
box_index = self.custom_boxs.index(box)
base_colour, slidepos = self.custom_colours[box_index]
self.UpdateColour(box.GetColour())
self.slider.SetValue(slidepos)
def onAddCustom(self, event):
"""Adds a custom colour to the custom colour box set. Boxes are
chosen in a round-robin fashion, eventually overwriting previously
added colours."""
# Store the colour and slider position so we can restore the
# custom colours just as they were
self.setCustomColour(self.last_custom,
self.solid.GetColour(),
self.colour_slider.GetBaseColour(),
self.slider.GetValue())
self.last_custom = (self.last_custom + 1) % self.NO_CUSTOM_COLOURS
def setCustomColour (self, index, true_colour, base_colour, slidepos):
"""Sets the custom colour at the given index. true_colour is wxColour
object containing the actual rgb value of the custom colour.
base_colour (wxColour) and slidepos (int) are used to configure the
colour slider and set everything to its original position."""
self.custom_boxs[index].SetColour(true_colour)
self.custom_colours[index] = (base_colour, slidepos)
def UpdateColour(self, colour):
"""Performs necessary updates for when the colour selection has
changed."""
# Reset the palette to erase any highlighting
self.palette.ReDraw()
# Set the color info
self.solid.SetColour(colour)
self.colour_slider.SetBaseColour(colour)
self.colour_slider.ReDraw()
self.slider.SetValue(0)
self.UpdateEntries(colour)
def UpdateEntries(self, colour):
"""Updates the color levels to display the new values."""
# Temporary bindings
r = colour.Red()
g = colour.Green()
b = colour.Blue()
# Update the RGB entries
self.rentry.SetValue(str(r))
self.gentry.SetValue(str(g))
self.bentry.SetValue(str(b))
# Convert to HSV
h,s,v = colorsys.rgb_to_hsv(r / 255.0, g / 255.0, b / 255.0)
self.hentry.SetValue("%.2f" % (h))
self.sentry.SetValue("%.2f" % (s))
self.ventry.SetValue("%.2f" % (v))
def onPaletteDown(self, event):
"""Stores state that the mouse has been pressed and updates
the selected colour values."""
self.mouse_down = True
self.palette.ReDraw()
self.doPaletteClick(event.m_x, event.m_y)
def onPaletteUp(self, event):
"""Stores state that the mouse is no longer depressed."""
self.mouse_down = False
def onPaletteMotion(self, event):
"""Updates the colour values during mouse motion while the
mouse button is depressed."""
if self.mouse_down:
self.doPaletteClick(event.m_x, event.m_y)
def doPaletteClick(self, m_x, m_y):
"""Updates the colour values based on the mouse location
over the palette."""
# Get the colour value and update
colour = self.palette.GetValue(m_x, m_y)
self.UpdateColour(colour)
# Highlight a fresh selected area
self.palette.ReDraw()
self.palette.HighlightPoint(m_x, m_y)
# Force an onscreen update
self.solid.Update()
self.colour_slider.Refresh()
def onScroll(self, event):
"""Updates the solid colour display to reflect the changing slider."""
value = self.slider.GetValue()
colour = self.colour_slider.GetValue(value)
self.solid.SetColour(colour)
self.UpdateEntries(colour)
def SetValue(self, colour):
"""Updates the colour chooser to reflect the given wxColour."""
self.UpdateColour(colour)
def GetValue(self):
"""Returns a wxColour object indicating the current colour choice."""
return self.solid.GetColour()
def main():
"""Simple test display."""
class App(wxApp):
def OnInit(self):
frame = wxFrame(NULL, -1, 'PyColourChooser Test')
chooser = wxPyColourChooser(frame, -1)
sizer = wxBoxSizer(wxVERTICAL)
sizer.Add(chooser, 0, 0)
frame.SetAutoLayout(True)
frame.SetSizer(sizer)
sizer.Fit(frame)
frame.Show(True)
self.SetTopWindow(frame)
return True
app = App()
app.MainLoop()
if __name__ == '__main__':
main()
main = wx.lib.colourchooser.pycolourchooser.main
wxPyColourChooser = wx.lib.colourchooser.pycolourchooser.wxPyColourChooser

View File

@@ -1,82 +1,9 @@
"""
wxPyColourChooser
Copyright (C) 2002 Michael Gilfix
## This file imports items from the wx package into the wxPython package for
## backwards compatibility. Some names will also have a 'wx' added on if
## that is how they used to be named in the old wxPython package.
This file is part of wxPyColourChooser.
import wx.lib.colourchooser.pycolourslider
You should have received a file COPYING containing license terms
along with this program; if not, write to Michael Gilfix
(mgilfix@eecs.tufts.edu) for a copy.
__doc__ = wx.lib.colourchooser.pycolourslider.__doc__
This version of wxPyColourChooser is open source; you can redistribute it and/or
modify it under the terms listed in the file COPYING.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
"""
import canvas
import colorsys
from wxPython.wx import *
class PyColourSlider(canvas.Canvas):
"""A Pure-Python Colour Slider
The colour slider displays transitions from value 0 to value 1 in
HSV, allowing the user to select a colour within the transition
spectrum.
This class is best accompanying by a wxSlider that allows the user
to select a particular colour shade.
"""
HEIGHT = 172
WIDTH = 12
def __init__(self, parent, id, colour=None):
"""Creates a blank slider instance. A colour must be set before the
slider will be filled in."""
# Set the base colour first since our base class calls the buffer
# drawing function
self.SetBaseColour(colour)
canvas.Canvas.__init__(self, parent, id,
size=wxSize(self.WIDTH, self.HEIGHT))
def SetBaseColour(self, colour):
"""Sets the base, or target colour, to use as the central colour
when calculating colour transitions."""
self.base_colour = colour
def GetBaseColour(self):
"""Return the current colour used as a colour base for filling out
the slider."""
return self.base_colour
def GetValue(self, pos):
"""Returns the colour value for a position on the slider. The position
must be within the valid height of the slider, or results can be
unpredictable."""
return self.buffer.GetPixel(0, pos)
def DrawBuffer(self):
"""Actual implementation of the widget's drawing. We simply draw
from value 0.0 to value 1.0 in HSV."""
if self.base_colour is None:
return
target_red = self.base_colour.Red()
target_green = self.base_colour.Green()
target_blue = self.base_colour.Blue()
h,s,v = colorsys.rgb_to_hsv(target_red / 255.0, target_green / 255.0,
target_blue / 255.0)
v = 1.0
vstep = 1.0 / self.HEIGHT
for y_pos in range(0, self.HEIGHT):
r,g,b = [c * 255.0 for c in colorsys.hsv_to_rgb(h,s,v)]
colour = wxColour(int(r), int(g), int(b))
self.buffer.SetPen(wxPen(colour, 1, wxSOLID))
self.buffer.DrawRectangle(0, y_pos, 15, 1)
v = v - vstep
PyColourSlider = wx.lib.colourchooser.pycolourslider.PyColourSlider

View File

@@ -1,214 +1,12 @@
"""
wxPyColourChooser
Copyright (C) 2002 Michael Gilfix
## This file imports items from the wx package into the wxPython package for
## backwards compatibility. Some names will also have a 'wx' added on if
## that is how they used to be named in the old wxPython package.
This file is part of wxPyColourChooser.
import wx.lib.colourchooser.pypalette
You should have received a file COPYING containing license terms
along with this program; if not, write to Michael Gilfix
(mgilfix@eecs.tufts.edu) for a copy.
__doc__ = wx.lib.colourchooser.pypalette.__doc__
This version of wxPyColourChooser is open source; you can redistribute it and/or
modify it under the terms listed in the file COPYING.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
"""
import canvas
import colorsys
import cStringIO, zlib
from wxPython.wx import *
# Bitmap functions generated from img2py
def getData():
return zlib.decompress(
'x\xdaUV{<\x93{\x18\x1f:\xe3\xc8Xj\xa3a\xe6R\x9db*B.3\x93\xeb\xe9\x1c\xb7\
\xe4\xb2r9\x8c\xe5\x12e\xc9\xda\x88\x9a\xb4\x83\xcet\xa1N\xae\x85\xe3\xb2\
\xe1,\xb7\xc2\x8a\xd0\x99D\xc8t\xdc\x86r\x1f\x96\\\x16k:\xebC\xe78\xef\xe7\
\xf3\xbe\xbf?\xde\xf7\xf9=\xcf\xf3\xbd<\xbf\xf7WgG;\x90,L\x16\x00\x00\x80\
\x1c\xec\xad]\xc5+[|7\xc8\x00\xc5O\xccv\xddE\xf1\xb2\x8d`\xe5\xe0&#\xbebdpT\
\x00`\xbb\x94\x835\xc6\x8d\x989\x97\xd5N\xca\xb3\x05\xdb\xdc\x9c[\xd0\xf4\
\xd2\xe6\x7f\xb9\xd3\xaa\xe9\x85\xd3\xd5\xd9\xbe]\xa7\xf2\xf1\xf2\x1b\xef\
\x1b\xe6\xb7\tF\xca\t`\xef\xf9\xb5\xa2\x87\xe1\x8d\xd3\x8ft\xef\x06z\xa5\x8f\
\xd7\x04\xf6y\xaf\xfbT\x0e\xad~\xce\xf1E\xa7\xc7\xe9\r\x8c\xab\xb7\xad_\xe4/\
r\xf9\xb1\xbe\x97[\xb3\x88\xfcx\xd6\\\xdf\x15\x88\xca\xcc\xc0\xb0\x10\xef\
\x81B\x9a\xf3Xzq\x1c\xb9\xa2E\xb2\xd3v\x80\xfd90@Ju[\xc3H\xe0\xea\xca\xdc\
\xfbr\xde\xbb\xf0U\xcd\xf4\xd7\xfe\xabc\xbaN\xc2\xe3\xcc>T\xa6)(\xaa\x9f\xe7\
\n\xaa\xe9\x00gcz\xa8Y\xb4\x8a\xc4\x0fr\x9a\x89\xe4\x9eJ\xe7\xa6z\xaf\xf7\
\xcc\xc4\x11YI\xbfx\n@y\x04\x01\x00\nL\xd8\xb3#\xfa\x0e\'\xb7\xc1n\x98\xd3h\
\xd5\x14\xd50\xeaA\x0bd\x8a\x16\x07\x96\xa0#\x13/!\xbf\xf1\xe5\x94)\xd5\xc3\
\xfe\x9ej\x0c<\x8b<8\x89\x98\xcb\x9ek\x18X^\xf9\xa9\xffJ\r/\xd93\xda\xc2\xfd\
\xfa\tt\xb9\xa3\x07\xe8u1\xc5\\O\xe9w\x94\xd6\n\x1e\xe8\xb1Q#@Z\xe2\x10\xd1\
\xcb\xc7\x17\xbd\x9e\x94\x14~\xf9\xd6\xe0\xb1\xb3\xe8\xd8\x07E\xe4\xa6F\x87\
\xbe6:K\xf8\xfanrn\x8b\xa4=e\xb3\x98\xf3\xc8\xde|\x0b\xf0\xb5\xb7\xfb\x0e\
\xf5\x83:m3\xcbs\xfe*T\xc7\x89\xe1\x1a\xc8X=\xbfZ\xc4#\xd0\xee\x93d\xb6lL\
\x15\xe4\xe3\xf7\xd8w\r\x1eK\xe0\xce\xad-`\x19g\xe6\x1f\xc8}\xcc}\xee\xecF\
\x19_\xa6PUq\xee\xa2\x80\x1d\xbc\xf5\x14g\xe04\xa4\xc0EZB\xe6[\x1al\xb2!,\
\xac\xa4\xf3O\x83\xa5y\x96(\xa7\xdd\xc61\x1aX\xa4X\xa8\x96\xdf2\x93\x067\x1c\
\xf0\xed\x10\xaa\xe3\xe9\x96\xac\'l\x14\xb7\xc1\x0ed\x85\x96\xb1\x84m&d\x872\
\x1f)\xe6wt\xd6\tV\xbe\xd4\xbe\xeaE\xcf\xaca\x92f4*Z\xce\xf8\xa0\xd9\x97\xa2\
+\xcc\x90$\xbb\xac8\x0b\xf7\x93\xfa\xb6\xf2\x92\x9d\xa0M\xec\xc6\xaa<\x17\
\xad\x8d\'\xc29\xd1uQjcU}\x8a\x1c\xbf\x9fg\x12\x9c\x1f\\4RZ8\xe2\xf5s@J\t\
\xc5\rU\x92\xab\xf6B\xb3\x97\x8f^\xb8\xa5_\xd0\x98tQ\xa6KA\x12\x0c\x14gl\xc0\
\x00\xe4f*=\xa3\x1ef\x0c\rU<\xb1sO\xaa\x0c\x82;\r)\xc8\x9c\xc0\x1f9CMch\xd4\
\x9fn\xde/g\xc3C\xb0\xb0\x8cuS6\xf3;\x8d2q\x7fG7\x88;\xb4~9\xd5e\xa1}\x7f\
\xd5\xa9Z\x88\x99\xaft+\xeca?\xa2qh\xaf\x8af\xbf\x82\xfe%\xac\xf6\nC_\xc6D\
\xc6Ry\xb3\xb7N\x11"\xcfU\xbb@m\x86AY\na\xfa;\xa1\x93\x96\xf2i\xd0\x04S\x90~\
\x1b\xb8z[1C\xde\x15w\xed\x0b\xd8\xd0\xbe\\\x19\x84\x84\xfe\x1bE\re\xda\x1az\
6\xe6\xbe!+\x86V\xbd\xfb\xc3\xfb\xd9[\xff\xc0\x8c\xc5\nH<\x82U#2S\t\xc8\x1en\
\xa7\xb5E\xde\x14W\xd2w\xe3\xf0\x18\x02\xa0\xf7\xad\xb6\xb2\x96\xfb\xbbH\x02\
\x0b\x85P\xb7\xe4\x02!\xe6a\xc4d\xe8]\x17\xa4\x8bk2G\xaf\xa2p\\\x8e\xd0\x8e\
\t\nf\xce\xf0\x10}O\xc1\x95\x9e\x80\xa6\x91\x8d\xae0\xcf\xa0\xc7\x97-h\xc3\
\x1f\xb8"l\x14\xcaz9\xffYl\x15.l|\xc4\x94\xdd&\x9c\x9f\xf8\xb8f7\x08cA\x1e\
\x85\x11,\xb0\xba\xf1\x87639\xfbJ\xef~e\xf3\xdbK\xd4\xe7\xec\xa5\x92\x17\xf7\
\x1aO\xe3*\xd5\xf3\xcbA\xef\xf4\xa4[\x1d\xaf\xd7>M-\xf1\xb9@\xea\x96x\xd9(\
\x06Z\xec+J\xed\xe5\xd45\x95\xe1\xba\xeb\xf4\xa4\xa3i\xbb\x82}\xd0\xf6Lh\xe8\
E4;0\x9aPk\x0emo~G\x04\xb6&u\xb31\x80\xdao\x01\xf5P\x1d\xd8\x05\x92qmV\xf6R\
\x17\x89\x1a-\xf4\x15P*\xf9?|\xcea\xa9\x8f\x99~6\x92^\xf8\x03s\x11;v\xe2D\
\xc4^\x1c>Q\xbfY\xd0n\xbaE\xc0b=\x91\x0c=[U\x86\xfb\x06\xb52\x92\x19M1uz<\
\xb1\xa4r~4\x83E\xe2y\x08\x0f\nQ\x84\xe8\xfa\xfa\xea\x13\x0e\xd4\x95\x91\\\
\x7f\xf6)\x08`\xb6\x89\xc5\x95^\xff\xe2\\\x03X\xe4\xbe\x88x\x8f\xe34\xb7\xe6\
\xbe\t\xf8\\w\x9c\xd3\x1a\xee\x98\xeeW\x92\xad\x83\x99\xb6B\xcb\x8f\xbdD\x86\
\xc6\xe3\xab\x1b\xb2\xdf\x08:9\xbc\x9e\xf3\xf9h\xd1\xec\xd98\xc8%\x0b\x87c\
\xb8\xbc\x0f\xad\x89\xca\xa5\x94J\xa9\x88j\x1ddo\x91u\x84\xf3\xcd\xea\xc5\
\xf6\x99\xab\xe0\xd7-\x92\xff:\xe6)T\x07\x0bd\x1b\xa9+9\xa4\x86\xec2F\xa1\
\xa6\x7f\xbc\xd1C\x9e\xf4=D\x12\xa2\x07\x94\t\xb1\xe8\xb5\xfb\x94\x14q~R\xa1\
\xe6Y<\xad\xcb\x94j\xbc\xb3##\x0f\xd0 \xbf\xc9\x01\xf8\xad\xb8V\x82sdO7\xbd\
\xbe\xd5Bd\x9f\xc0m#\xd4h<j\xf5*\x84\x86VKt\x0c4\xc1QkD\xbd\xee\xd0\xdc\xcc\
\xad\xc5bN\'\x8f\x1b\x92\x95\x8e\xdf,\xb1\xfa\xe0\xc7f\xd5\xc7\x95\xd1&\xe06\
\xcb\xb4t/\xa0KTj\xd0\xe2\xfb\xd2\xc3!\xf1\xcb?\r7_\x14K$xs(\xfa}~\xe2\xd9\
\xe5gP\xd4\xfaq\x97\xb1\x0b\xd2]\xe5|\x19o2(Vm\xfe>\xe5\x13jZ\xdan\x98\xf3\
\xe4:\x1ep\x93B\xec6?\tO\x0eaB\x99>\xc6Zkr\xcf!\x1b\x84|\xb5\xdb\x8b*O\xb4\
\xe7\x14Ko\xa0\x93\xecmq\xd7\xf0\xbd\x12\x07\x8d\x95\xd7\x7f\xf5&\xb8bmj\xda\
/&`>e\xeb\xfc\x14a\x19\x94S\x7f\xd2\xb5:\x8c\x04\x8f\x91\x03\xc2Q\x0e\xff{\
\x93\xc7\xea\xd6\xbb\x1b\x0e7\xe7E\xa6\xae\x9d\xc6\x85%\x9e\xfbnc\xe3\xff\
\xd4\xa2`9\x13\xa3\x97\x9e\xa4\x9b\x06\xa5\x9f\xec\x9f\x1a\x0c\xf0\xfe\xcd\
\x021\x9b\x0cM\xc06\xfd u:\xe7:g\x02\xc1r\x926\x9b\x7f\xe2\xf9\xe3\xed\xf1qU\
\xbe\xbf\xe8\x91\t\x0c0\xfb-\xe5%d\xef\x19v\x966\xec\xaaB\xe2`N[\x8c\xda\x98\
\xf4\xb4\x83\x13\xcc\x8a\x83\x81\xa3\x91%\xdb\xad\xab\xff\x87\xe1\xba\xda\
\xb5\xdb\xf0\x17\xfd\xf4F\x18KTNH\xf5J\xbc\x97\xdfB:\xa7\x96\xdf/k\x1c\xeaF_\
\x8c\xfc\xdfap\x1e\x99\xae8\x94b\xa1t<\xb54.3c\xd9\xe8y=u9FM;D\xa6\xc0\xea~\
\x0f"O\xee\x81\xdc\xa3\xb2\x1a\xa0\xa7\x02\xb9\x7f>\xfdg\x974\xc8\x0b\xbaU6P\
\xe7\x14\xd8\xd5 \x90\xbc\x0b\xf0\xb7\xc4\x7f\x08\xfaPl\xf5\xa7\x96\xac\xc2\
\x0f*\x05\xf3\x83\xe8\xce\xa7\xc4\x8c\xdbX\xa4U\x9b\xeeW\xe9\xf1\xbf\xa4Q#\
\xcbDQ\x18h\x02\xca\'\xca\xee),1"\x8d\xfb<\x15\xafl\xb8\xb3z\x18\x18\xaf\xb6\
I$\xa2\xbc\xe5\xe5J\xbe\x00\r\x08&<\x0eK\x98\x0e.[\xd1\xea`\xa9\xe2\x96\xae-\
d9%\xc0 \x85\xc5{c_\x03x\xaf\x8f\x98P= 0\x8e\xff\xaa\xf5>7\xfeO\x7f\x1b\xcbm\
\xb1W\xa7\t\x9b\xe1w\x02\xc5\xb5\x9fM/\x8d\xab\xe4u\r\x06\xa0\xd6\xc9\xb5\
\xf2\xb7J\x01\xda<\r\x9f\xd1\x06\x03\xea>\xab\x9d\xe6\xde\xb4\xbb\xb1\xc6\
\xa3EP\x1e\x17\x16\xf2\x1c\xa7\x823\xa7\xcc~\xd1\xdb\xb2\xcb\xbd\xe1\xdb\xf0\
W(,\xe9XD)3I\xc4\x15z_\x98\x8b\xb2v\xdb\x13\xd0\xb8\xf3U"\xb713\xaf\xa0\x1dC\
j\x0b\xb0\xf9\xfd\xef\x0ex\xd7l\xa5\xc1\xf7Z\xd2\x12\x1f\xbe\r\x87Shjm\xe3\
\x1c\x92\xbc\xc7^\x9e\xe5\x84\xf9\xb8\xcb\x88+\x12\xb4M\xee\xb0\xbb\xcd\xc4\
\x9c\xc7V\x1f\xde\x1b\x02\xb0!\x0c\xbeY&\xf6\xe9\xdd[u:0\x0f)(\xc5g\n\xd5\
\xb6\xcc\xf0st\n\x113\x81Q\xcc\xef\xaa\x1b\x9a#\xad|\x12\x98\xd8\xf7"\xa2\
\xa2\xd7\xdbwz+\x08\xb8\x0c\x9d&mZ\\-<\xbaG6j\x9cy@\x8ah\x10@\x8e\xd9\x12\
\x9dK\x00\xf3\xabdo\x1f\x8b\x80\x9c\xf7i^#\xc1X\x7f-\x13R](\x17\xa0\x89p\x9c\
L\x1a\xc5\x9c\x88U\xde\xc7\x9d\xd04\x04\x8en\x11\x8112\xbd\xf6J\x96wP\x06\
\xcd\xa9x\x08\xf7\xc3\xfc\x0e\xceE\xef\xf9j\xd50\x19~\x02~\xf7C\x13\xae\xd8\
\xea\x8e\xc9\x8c\xafpU\xc8\x8d\xaa\xe5\x88Q\xfan\x93\xf7\xf0(\xb0\x93\xf5NH\
\x1f\xae\xc5\xf8\xaa\x97F4\x19;\x19\xe4=\x89\xe0\xae\x15\xc9\xb6\xfe\xe2\xce\
\x1e\xca\xe6\x1a\n<\t\xa9].x\x03\xfd\x1c\x86Fd?\xbd\x17|z\x03\xa8\xafX[N"|\
\x16\xa3#\x0e\x92\xf0h{^+K\x04/!\x8f\xac\xf4\xe4\xbbH\xa9.\x85q\xdd\x93\xc7\
\xbb`\x96\xbb\xb5\xefQ\xdc\x9ch+G\xf8\xbf\xf6b\xdc\xfbww\xcf\xc7\x85\xf7\n@\
\x8d[\xdc\x1b\x8e\xd5\x85\x1c\xf0@JG\x08\xc9;\n\xfb\x9dX\xc5\x8e\t\\\xb3g#\
\xa0\xa2\xb7`\n\x96\x116?\xda\x83\xea\xa1\x7f.Y\x9f\xcb\xda_\x8c\xe9\x01s\
\x0f\xf6\x03\xb7:\xa0\xc6\x94\xaat\xc4\x96r\x1c\x12\x06\x1dZ\xf7\x10V\xd5\
\x088\x02N\xc6\xcc\x05y\xd7\xc0T\x07,c\xea\xb2\xcf\xc7=>y\x87M_\x9a\x86\x12\
\xa5\x92\x83\n_"\x84\xff\x8b7\x95\xfeu\x02\x9c\xf7\xe4\xfacQyo\xda\xbb\t\xed\
\xdeS\xd3\xb7\x04/j\xdb\x96\xae\xec\xd3\x01\xb8P\x8ap\x8c7\x88\xc2\xa8\xfd\
\x1d\xd5\xd1=\xab$*\x8c\x9dd\xacu\x07\xe3\xa6X\xed\x1d\xb9eHd@\x8f\xb7\xd4V\
\xdc\x95\x0f\xa91\xba\xe3s?\n\x12\xf2\x97\xefh\xf4\x1d\x89\x04\xccC)\x8f\x83\
\xbf\x84\xd5\xe0A\xb7\xccC\xf9\xc3fGA\x92\xe4\x12\x89\x03\x14bb\xdfe\xd9\x7f\
\x0f\x86\xc6R\xf9wC\x114\xe0\xdd\xae9\xc9ef\x92\xb6\x12\x1eU\'ZW\xa2\xe9\xa7\
4\x15\xfdb\nr\x17\xf1\xe15IkA\xe5\x12aM[&\x93T\x16\xa5\x92x\xf8\xc3\xd4\xca\
\xd8[\x96]wPNO\t!5\xaf&\xfarlLC\xdd\x00\xdd\x8e\x13qc\xea&]nAb\x8b1>)9\x047\
\xc5\x8e\x1a\xd5\x84\x8b\x7f\x8f\x01\x0e6\x8e\xd6eV~W\xff\x01[x\x1b=' )
def getBitmap():
return wxBitmapFromImage(getImage())
def getImage():
stream = cStringIO.StringIO(getData())
return wxImageFromStream(stream)
class PyPalette(canvas.Canvas):
"""The Pure-Python Palette
The PyPalette is a pure python implementation of a colour palette. The
palette implementation here imitates the palette layout used by MS
Windows and Adobe Photoshop.
The actual palette image has been embedded as an XPM for speed. The
actual reverse-engineered drawing algorithm is provided in the
GeneratePaletteBMP() method. The algorithm is tweakable by supplying
the granularity factor to improve speed at the cost of display
beauty. Since the generator isn't used in real time, no one will
likely care :) But if you need it for some sort of unforeseen realtime
application, it's there.
"""
HORIZONTAL_STEP = 2
VERTICAL_STEP = 4
def __init__(self, parent, id):
"""Creates a palette object."""
# Load the pre-generated palette XPM
self.palette = getBitmap ()
canvas.Canvas.__init__ (self, parent, id, size=wxSize(200, 192))
def GetValue(self, x, y):
"""Returns a colour value at a specific x, y coordinate pair. This
is useful for determining the colour found a specific mouse click
in an external event handler."""
return self.buffer.GetPixel(x, y)
def DrawBuffer(self):
"""Draws the palette XPM into the memory buffer."""
#self.GeneratePaletteBMP ("foo.bmp")
self.buffer.DrawBitmap(self.palette, 0, 0, 0)
def HighlightPoint(self, x, y):
"""Highlights an area of the palette with a little circle around
the coordinate point"""
colour = wxColour(0, 0, 0)
self.buffer.SetPen(wxPen(colour, 1, wxSOLID))
self.buffer.SetBrush(wxBrush(colour, wxTRANSPARENT))
self.buffer.DrawCircle(x, y, 3)
self.Refresh()
def GeneratePaletteBMP(self, file_name, granularity=1):
"""The actual palette drawing algorithm.
This used to be 100% reverse engineered by looking at the
values on the MS map, but has since been redone Correctly(tm)
according to the HSV (hue, saturation, value) colour model by
Charl P. Botha <http://cpbotha.net/>.
Speed is tweakable by changing the granularity factor, but
that affects how nice the output looks (makes the vertical
blocks bigger. This method was used to generate the embedded
XPM data."""
self.vertical_step = self.VERTICAL_STEP * granularity
width, height = self.GetSize ()
# simply iterate over hue (horizontal) and saturation (vertical)
value = 1.0
for y in range(0, height, self.vertical_step):
saturation = 1.0 - float(y) / float(height)
for x in range(0, width, self.HORIZONTAL_STEP):
hue = float(x) / float(width)
r,g,b = colorsys.hsv_to_rgb(hue, saturation, value)
colour = wxColour(int(r * 255.0), int(g * 255.0), int(b * 255.0))
self.buffer.SetPen(wxPen(colour, 1, wxSOLID))
self.buffer.SetBrush(wxBrush(colour, wxSOLID))
self.buffer.DrawRectangle(x, y,
self.HORIZONTAL_STEP,
self.vertical_step)
# this code is now simpler (and works)
bitmap = self.buffer.GetBitmap()
image = wxImageFromBitmap(bitmap)
image.SaveFile (file_name, wxBITMAP_TYPE_XPM)
PyPalette = wx.lib.colourchooser.pypalette.PyPalette
getBitmap = wx.lib.colourchooser.pypalette.getBitmap
getData = wx.lib.colourchooser.pypalette.getData
getImage = wx.lib.colourchooser.pypalette.getImage

View File

@@ -1,669 +1,11 @@
#----------------------------------------------------------------------
# Name: wxPython.lib.colourdb.py
# Purpose: Adds a bunch of colour names and RGB values to the
# colour database so they can be found by name
#
# Author: Robin Dunn
#
# Created: 13-March-2001
# RCS-ID: $Id$
# Copyright: (c) 2001 by Total Control Software
# Licence: wxWindows license
#----------------------------------------------------------------------
## This file imports items from the wx package into the wxPython package for
## backwards compatibility. Some names will also have a 'wx' added on if
## that is how they used to be named in the old wxPython package.
"""
Load color names/values from the rgb.txt file on my system...
"""
def getColourList():
return [ x[0] for x in getColourInfoList() ]
def getColourInfoList():
return [
("SNOW", 255, 250, 250),
("GHOST WHITE", 248, 248, 255),
("GHOSTWHITE", 248, 248, 255),
("WHITE SMOKE", 245, 245, 245),
("WHITESMOKE", 245, 245, 245),
("GAINSBORO", 220, 220, 220),
("FLORAL WHITE", 255, 250, 240),
("FLORALWHITE", 255, 250, 240),
("OLD LACE", 253, 245, 230),
("OLDLACE", 253, 245, 230),
("LINEN", 250, 240, 230),
("ANTIQUE WHITE", 250, 235, 215),
("ANTIQUEWHITE", 250, 235, 215),
("PAPAYA WHIP", 255, 239, 213),
("PAPAYAWHIP", 255, 239, 213),
("BLANCHED ALMOND", 255, 235, 205),
("BLANCHEDALMOND", 255, 235, 205),
("BISQUE", 255, 228, 196),
("PEACH PUFF", 255, 218, 185),
("PEACHPUFF", 255, 218, 185),
("NAVAJO WHITE", 255, 222, 173),
("NAVAJOWHITE", 255, 222, 173),
("MOCCASIN", 255, 228, 181),
("CORNSILK", 255, 248, 220),
("IVORY", 255, 255, 240),
("LEMON CHIFFON", 255, 250, 205),
("LEMONCHIFFON", 255, 250, 205),
("SEASHELL", 255, 245, 238),
("HONEYDEW", 240, 255, 240),
("MINT CREAM", 245, 255, 250),
("MINTCREAM", 245, 255, 250),
("AZURE", 240, 255, 255),
("ALICE BLUE", 240, 248, 255),
("ALICEBLUE", 240, 248, 255),
("LAVENDER", 230, 230, 250),
("LAVENDER BLUSH", 255, 240, 245),
("LAVENDERBLUSH", 255, 240, 245),
("MISTY ROSE", 255, 228, 225),
("MISTYROSE", 255, 228, 225),
("WHITE", 255, 255, 255),
("BLACK", 0, 0, 0),
("DARK SLATE GREY", 47, 79, 79),
("DARKSLATEGREY", 47, 79, 79),
("DIM GREY", 105, 105, 105),
("DIMGREY", 105, 105, 105),
("SLATE GREY", 112, 128, 144),
("SLATEGREY", 112, 128, 144),
("LIGHT SLATE GREY", 119, 136, 153),
("LIGHTSLATEGREY", 119, 136, 153),
("GREY", 190, 190, 190),
("LIGHT GREY", 211, 211, 211),
("LIGHTGREY", 211, 211, 211),
("MIDNIGHT BLUE", 25, 25, 112),
("MIDNIGHTBLUE", 25, 25, 112),
("NAVY", 0, 0, 128),
("NAVY BLUE", 0, 0, 128),
("NAVYBLUE", 0, 0, 128),
("CORNFLOWER BLUE", 100, 149, 237),
("CORNFLOWERBLUE", 100, 149, 237),
("DARK SLATE BLUE", 72, 61, 139),
("DARKSLATEBLUE", 72, 61, 139),
("SLATE BLUE", 106, 90, 205),
("SLATEBLUE", 106, 90, 205),
("MEDIUM SLATE BLUE", 123, 104, 238),
("MEDIUMSLATEBLUE", 123, 104, 238),
("LIGHT SLATE BLUE", 132, 112, 255),
("LIGHTSLATEBLUE", 132, 112, 255),
("MEDIUM BLUE", 0, 0, 205),
("MEDIUMBLUE", 0, 0, 205),
("ROYAL BLUE", 65, 105, 225),
("ROYALBLUE", 65, 105, 225),
("BLUE", 0, 0, 255),
("DODGER BLUE", 30, 144, 255),
("DODGERBLUE", 30, 144, 255),
("DEEP SKY BLUE", 0, 191, 255),
("DEEPSKYBLUE", 0, 191, 255),
("SKY BLUE", 135, 206, 235),
("SKYBLUE", 135, 206, 235),
("LIGHT SKY BLUE", 135, 206, 250),
("LIGHTSKYBLUE", 135, 206, 250),
("STEEL BLUE", 70, 130, 180),
("STEELBLUE", 70, 130, 180),
("LIGHT STEEL BLUE", 176, 196, 222),
("LIGHTSTEELBLUE", 176, 196, 222),
("LIGHT BLUE", 173, 216, 230),
("LIGHTBLUE", 173, 216, 230),
("POWDER BLUE", 176, 224, 230),
("POWDERBLUE", 176, 224, 230),
("PALE TURQUOISE", 175, 238, 238),
("PALETURQUOISE", 175, 238, 238),
("DARK TURQUOISE", 0, 206, 209),
("DARKTURQUOISE", 0, 206, 209),
("MEDIUM TURQUOISE", 72, 209, 204),
("MEDIUMTURQUOISE", 72, 209, 204),
("TURQUOISE", 64, 224, 208),
("CYAN", 0, 255, 255),
("LIGHT CYAN", 224, 255, 255),
("LIGHTCYAN", 224, 255, 255),
("CADET BLUE", 95, 158, 160),
("CADETBLUE", 95, 158, 160),
("MEDIUM AQUAMARINE", 102, 205, 170),
("MEDIUMAQUAMARINE", 102, 205, 170),
("AQUAMARINE", 127, 255, 212),
("DARK GREEN", 0, 100, 0),
("DARKGREEN", 0, 100, 0),
("DARK OLIVE GREEN", 85, 107, 47),
("DARKOLIVEGREEN", 85, 107, 47),
("DARK SEA GREEN", 143, 188, 143),
("DARKSEAGREEN", 143, 188, 143),
("SEA GREEN", 46, 139, 87),
("SEAGREEN", 46, 139, 87),
("MEDIUM SEA GREEN", 60, 179, 113),
("MEDIUMSEAGREEN", 60, 179, 113),
("LIGHT SEA GREEN", 32, 178, 170),
("LIGHTSEAGREEN", 32, 178, 170),
("PALE GREEN", 152, 251, 152),
("PALEGREEN", 152, 251, 152),
("SPRING GREEN", 0, 255, 127),
("SPRINGGREEN", 0, 255, 127),
("LAWN GREEN", 124, 252, 0),
("LAWNGREEN", 124, 252, 0),
("GREEN", 0, 255, 0),
("CHARTREUSE", 127, 255, 0),
("MEDIUM SPRING GREEN", 0, 250, 154),
("MEDIUMSPRINGGREEN", 0, 250, 154),
("GREEN YELLOW", 173, 255, 47),
("GREENYELLOW", 173, 255, 47),
("LIME GREEN", 50, 205, 50),
("LIMEGREEN", 50, 205, 50),
("YELLOW GREEN", 154, 205, 50),
("YELLOWGREEN", 154, 205, 50),
("FOREST GREEN", 34, 139, 34),
("FORESTGREEN", 34, 139, 34),
("OLIVE DRAB", 107, 142, 35),
("OLIVEDRAB", 107, 142, 35),
("DARK KHAKI", 189, 183, 107),
("DARKKHAKI", 189, 183, 107),
("KHAKI", 240, 230, 140),
("PALE GOLDENROD", 238, 232, 170),
("PALEGOLDENROD", 238, 232, 170),
("LIGHT GOLDENROD YELLOW", 250, 250, 210),
("LIGHTGOLDENRODYELLOW", 250, 250, 210),
("LIGHT YELLOW", 255, 255, 224),
("LIGHTYELLOW", 255, 255, 224),
("YELLOW", 255, 255, 0),
("GOLD", 255, 215, 0),
("LIGHT GOLDENROD", 238, 221, 130),
("LIGHTGOLDENROD", 238, 221, 130),
("GOLDENROD", 218, 165, 32),
("DARK GOLDENROD", 184, 134, 11),
("DARKGOLDENROD", 184, 134, 11),
("ROSY BROWN", 188, 143, 143),
("ROSYBROWN", 188, 143, 143),
("INDIAN RED", 205, 92, 92),
("INDIANRED", 205, 92, 92),
("SADDLE BROWN", 139, 69, 19),
("SADDLEBROWN", 139, 69, 19),
("SIENNA", 160, 82, 45),
("PERU", 205, 133, 63),
("BURLYWOOD", 222, 184, 135),
("BEIGE", 245, 245, 220),
("WHEAT", 245, 222, 179),
("SANDY BROWN", 244, 164, 96),
("SANDYBROWN", 244, 164, 96),
("TAN", 210, 180, 140),
("CHOCOLATE", 210, 105, 30),
("FIREBRICK", 178, 34, 34),
("BROWN", 165, 42, 42),
("DARK SALMON", 233, 150, 122),
("DARKSALMON", 233, 150, 122),
("SALMON", 250, 128, 114),
("LIGHT SALMON", 255, 160, 122),
("LIGHTSALMON", 255, 160, 122),
("ORANGE", 255, 165, 0),
("DARK ORANGE", 255, 140, 0),
("DARKORANGE", 255, 140, 0),
("CORAL", 255, 127, 80),
("LIGHT CORAL", 240, 128, 128),
("LIGHTCORAL", 240, 128, 128),
("TOMATO", 255, 99, 71),
("ORANGE RED", 255, 69, 0),
("ORANGERED", 255, 69, 0),
("RED", 255, 0, 0),
("HOT PINK", 255, 105, 180),
("HOTPINK", 255, 105, 180),
("DEEP PINK", 255, 20, 147),
("DEEPPINK", 255, 20, 147),
("PINK", 255, 192, 203),
("LIGHT PINK", 255, 182, 193),
("LIGHTPINK", 255, 182, 193),
("PALE VIOLET RED", 219, 112, 147),
("PALEVIOLETRED", 219, 112, 147),
("MAROON", 176, 48, 96),
("MEDIUM VIOLET RED", 199, 21, 133),
("MEDIUMVIOLETRED", 199, 21, 133),
("VIOLET RED", 208, 32, 144),
("VIOLETRED", 208, 32, 144),
("MAGENTA", 255, 0, 255),
("VIOLET", 238, 130, 238),
("PLUM", 221, 160, 221),
("ORCHID", 218, 112, 214),
("MEDIUM ORCHID", 186, 85, 211),
("MEDIUMORCHID", 186, 85, 211),
("DARK ORCHID", 153, 50, 204),
("DARKORCHID", 153, 50, 204),
("DARK VIOLET", 148, 0, 211),
("DARKVIOLET", 148, 0, 211),
("BLUE VIOLET", 138, 43, 226),
("BLUEVIOLET", 138, 43, 226),
("PURPLE", 160, 32, 240),
("MEDIUM PURPLE", 147, 112, 219),
("MEDIUMPURPLE", 147, 112, 219),
("THISTLE", 216, 191, 216),
("SNOW1", 255, 250, 250),
("SNOW2", 238, 233, 233),
("SNOW3", 205, 201, 201),
("SNOW4", 139, 137, 137),
("SEASHELL1", 255, 245, 238),
("SEASHELL2", 238, 229, 222),
("SEASHELL3", 205, 197, 191),
("SEASHELL4", 139, 134, 130),
("ANTIQUEWHITE1", 255, 239, 219),
("ANTIQUEWHITE2", 238, 223, 204),
("ANTIQUEWHITE3", 205, 192, 176),
("ANTIQUEWHITE4", 139, 131, 120),
("BISQUE1", 255, 228, 196),
("BISQUE2", 238, 213, 183),
("BISQUE3", 205, 183, 158),
("BISQUE4", 139, 125, 107),
("PEACHPUFF1", 255, 218, 185),
("PEACHPUFF2", 238, 203, 173),
("PEACHPUFF3", 205, 175, 149),
("PEACHPUFF4", 139, 119, 101),
("NAVAJOWHITE1", 255, 222, 173),
("NAVAJOWHITE2", 238, 207, 161),
("NAVAJOWHITE3", 205, 179, 139),
("NAVAJOWHITE4", 139, 121, 94),
("LEMONCHIFFON1", 255, 250, 205),
("LEMONCHIFFON2", 238, 233, 191),
("LEMONCHIFFON3", 205, 201, 165),
("LEMONCHIFFON4", 139, 137, 112),
("CORNSILK1", 255, 248, 220),
("CORNSILK2", 238, 232, 205),
("CORNSILK3", 205, 200, 177),
("CORNSILK4", 139, 136, 120),
("IVORY1", 255, 255, 240),
("IVORY2", 238, 238, 224),
("IVORY3", 205, 205, 193),
("IVORY4", 139, 139, 131),
("HONEYDEW1", 240, 255, 240),
("HONEYDEW2", 224, 238, 224),
("HONEYDEW3", 193, 205, 193),
("HONEYDEW4", 131, 139, 131),
("LAVENDERBLUSH1", 255, 240, 245),
("LAVENDERBLUSH2", 238, 224, 229),
("LAVENDERBLUSH3", 205, 193, 197),
("LAVENDERBLUSH4", 139, 131, 134),
("MISTYROSE1", 255, 228, 225),
("MISTYROSE2", 238, 213, 210),
("MISTYROSE3", 205, 183, 181),
("MISTYROSE4", 139, 125, 123),
("AZURE1", 240, 255, 255),
("AZURE2", 224, 238, 238),
("AZURE3", 193, 205, 205),
("AZURE4", 131, 139, 139),
("SLATEBLUE1", 131, 111, 255),
("SLATEBLUE2", 122, 103, 238),
("SLATEBLUE3", 105, 89, 205),
("SLATEBLUE4", 71, 60, 139),
("ROYALBLUE1", 72, 118, 255),
("ROYALBLUE2", 67, 110, 238),
("ROYALBLUE3", 58, 95, 205),
("ROYALBLUE4", 39, 64, 139),
("BLUE1", 0, 0, 255),
("BLUE2", 0, 0, 238),
("BLUE3", 0, 0, 205),
("BLUE4", 0, 0, 139),
("DODGERBLUE1", 30, 144, 255),
("DODGERBLUE2", 28, 134, 238),
("DODGERBLUE3", 24, 116, 205),
("DODGERBLUE4", 16, 78, 139),
("STEELBLUE1", 99, 184, 255),
("STEELBLUE2", 92, 172, 238),
("STEELBLUE3", 79, 148, 205),
("STEELBLUE4", 54, 100, 139),
("DEEPSKYBLUE1", 0, 191, 255),
("DEEPSKYBLUE2", 0, 178, 238),
("DEEPSKYBLUE3", 0, 154, 205),
("DEEPSKYBLUE4", 0, 104, 139),
("SKYBLUE1", 135, 206, 255),
("SKYBLUE2", 126, 192, 238),
("SKYBLUE3", 108, 166, 205),
("SKYBLUE4", 74, 112, 139),
("LIGHTSKYBLUE1", 176, 226, 255),
("LIGHTSKYBLUE2", 164, 211, 238),
("LIGHTSKYBLUE3", 141, 182, 205),
("LIGHTSKYBLUE4", 96, 123, 139),
("LIGHTSTEELBLUE1", 202, 225, 255),
("LIGHTSTEELBLUE2", 188, 210, 238),
("LIGHTSTEELBLUE3", 162, 181, 205),
("LIGHTSTEELBLUE4", 110, 123, 139),
("LIGHTBLUE1", 191, 239, 255),
("LIGHTBLUE2", 178, 223, 238),
("LIGHTBLUE3", 154, 192, 205),
("LIGHTBLUE4", 104, 131, 139),
("LIGHTCYAN1", 224, 255, 255),
("LIGHTCYAN2", 209, 238, 238),
("LIGHTCYAN3", 180, 205, 205),
("LIGHTCYAN4", 122, 139, 139),
("PALETURQUOISE1", 187, 255, 255),
("PALETURQUOISE2", 174, 238, 238),
("PALETURQUOISE3", 150, 205, 205),
("PALETURQUOISE4", 102, 139, 139),
("CADETBLUE1", 152, 245, 255),
("CADETBLUE2", 142, 229, 238),
("CADETBLUE3", 122, 197, 205),
("CADETBLUE4", 83, 134, 139),
("TURQUOISE1", 0, 245, 255),
("TURQUOISE2", 0, 229, 238),
("TURQUOISE3", 0, 197, 205),
("TURQUOISE4", 0, 134, 139),
("CYAN1", 0, 255, 255),
("CYAN2", 0, 238, 238),
("CYAN3", 0, 205, 205),
("CYAN4", 0, 139, 139),
("AQUAMARINE1", 127, 255, 212),
("AQUAMARINE2", 118, 238, 198),
("AQUAMARINE3", 102, 205, 170),
("AQUAMARINE4", 69, 139, 116),
("DARKSEAGREEN1", 193, 255, 193),
("DARKSEAGREEN2", 180, 238, 180),
("DARKSEAGREEN3", 155, 205, 155),
("DARKSEAGREEN4", 105, 139, 105),
("SEAGREEN1", 84, 255, 159),
("SEAGREEN2", 78, 238, 148),
("SEAGREEN3", 67, 205, 128),
("SEAGREEN4", 46, 139, 87),
("PALEGREEN1", 154, 255, 154),
("PALEGREEN2", 144, 238, 144),
("PALEGREEN3", 124, 205, 124),
("PALEGREEN4", 84, 139, 84),
("SPRINGGREEN1", 0, 255, 127),
("SPRINGGREEN2", 0, 238, 118),
("SPRINGGREEN3", 0, 205, 102),
("SPRINGGREEN4", 0, 139, 69),
("GREEN1", 0, 255, 0),
("GREEN2", 0, 238, 0),
("GREEN3", 0, 205, 0),
("GREEN4", 0, 139, 0),
("CHARTREUSE1", 127, 255, 0),
("CHARTREUSE2", 118, 238, 0),
("CHARTREUSE3", 102, 205, 0),
("CHARTREUSE4", 69, 139, 0),
("OLIVEDRAB1", 192, 255, 62),
("OLIVEDRAB2", 179, 238, 58),
("OLIVEDRAB3", 154, 205, 50),
("OLIVEDRAB4", 105, 139, 34),
("DARKOLIVEGREEN1", 202, 255, 112),
("DARKOLIVEGREEN2", 188, 238, 104),
("DARKOLIVEGREEN3", 162, 205, 90),
("DARKOLIVEGREEN4", 110, 139, 61),
("KHAKI1", 255, 246, 143),
("KHAKI2", 238, 230, 133),
("KHAKI3", 205, 198, 115),
("KHAKI4", 139, 134, 78),
("LIGHTGOLDENROD1", 255, 236, 139),
("LIGHTGOLDENROD2", 238, 220, 130),
("LIGHTGOLDENROD3", 205, 190, 112),
("LIGHTGOLDENROD4", 139, 129, 76),
("LIGHTYELLOW1", 255, 255, 224),
("LIGHTYELLOW2", 238, 238, 209),
("LIGHTYELLOW3", 205, 205, 180),
("LIGHTYELLOW4", 139, 139, 122),
("YELLOW1", 255, 255, 0),
("YELLOW2", 238, 238, 0),
("YELLOW3", 205, 205, 0),
("YELLOW4", 139, 139, 0),
("GOLD1", 255, 215, 0),
("GOLD2", 238, 201, 0),
("GOLD3", 205, 173, 0),
("GOLD4", 139, 117, 0),
("GOLDENROD1", 255, 193, 37),
("GOLDENROD2", 238, 180, 34),
("GOLDENROD3", 205, 155, 29),
("GOLDENROD4", 139, 105, 20),
("DARKGOLDENROD1", 255, 185, 15),
("DARKGOLDENROD2", 238, 173, 14),
("DARKGOLDENROD3", 205, 149, 12),
("DARKGOLDENROD4", 139, 101, 8),
("ROSYBROWN1", 255, 193, 193),
("ROSYBROWN2", 238, 180, 180),
("ROSYBROWN3", 205, 155, 155),
("ROSYBROWN4", 139, 105, 105),
("INDIANRED1", 255, 106, 106),
("INDIANRED2", 238, 99, 99),
("INDIANRED3", 205, 85, 85),
("INDIANRED4", 139, 58, 58),
("SIENNA1", 255, 130, 71),
("SIENNA2", 238, 121, 66),
("SIENNA3", 205, 104, 57),
("SIENNA4", 139, 71, 38),
("BURLYWOOD1", 255, 211, 155),
("BURLYWOOD2", 238, 197, 145),
("BURLYWOOD3", 205, 170, 125),
("BURLYWOOD4", 139, 115, 85),
("WHEAT1", 255, 231, 186),
("WHEAT2", 238, 216, 174),
("WHEAT3", 205, 186, 150),
("WHEAT4", 139, 126, 102),
("TAN1", 255, 165, 79),
("TAN2", 238, 154, 73),
("TAN3", 205, 133, 63),
("TAN4", 139, 90, 43),
("CHOCOLATE1", 255, 127, 36),
("CHOCOLATE2", 238, 118, 33),
("CHOCOLATE3", 205, 102, 29),
("CHOCOLATE4", 139, 69, 19),
("FIREBRICK1", 255, 48, 48),
("FIREBRICK2", 238, 44, 44),
("FIREBRICK3", 205, 38, 38),
("FIREBRICK4", 139, 26, 26),
("BROWN1", 255, 64, 64),
("BROWN2", 238, 59, 59),
("BROWN3", 205, 51, 51),
("BROWN4", 139, 35, 35),
("SALMON1", 255, 140, 105),
("SALMON2", 238, 130, 98),
("SALMON3", 205, 112, 84),
("SALMON4", 139, 76, 57),
("LIGHTSALMON1", 255, 160, 122),
("LIGHTSALMON2", 238, 149, 114),
("LIGHTSALMON3", 205, 129, 98),
("LIGHTSALMON4", 139, 87, 66),
("ORANGE1", 255, 165, 0),
("ORANGE2", 238, 154, 0),
("ORANGE3", 205, 133, 0),
("ORANGE4", 139, 90, 0),
("DARKORANGE1", 255, 127, 0),
("DARKORANGE2", 238, 118, 0),
("DARKORANGE3", 205, 102, 0),
("DARKORANGE4", 139, 69, 0),
("CORAL1", 255, 114, 86),
("CORAL2", 238, 106, 80),
("CORAL3", 205, 91, 69),
("CORAL4", 139, 62, 47),
("TOMATO1", 255, 99, 71),
("TOMATO2", 238, 92, 66),
("TOMATO3", 205, 79, 57),
("TOMATO4", 139, 54, 38),
("ORANGERED1", 255, 69, 0),
("ORANGERED2", 238, 64, 0),
("ORANGERED3", 205, 55, 0),
("ORANGERED4", 139, 37, 0),
("RED1", 255, 0, 0),
("RED2", 238, 0, 0),
("RED3", 205, 0, 0),
("RED4", 139, 0, 0),
("DEEPPINK1", 255, 20, 147),
("DEEPPINK2", 238, 18, 137),
("DEEPPINK3", 205, 16, 118),
("DEEPPINK4", 139, 10, 80),
("HOTPINK1", 255, 110, 180),
("HOTPINK2", 238, 106, 167),
("HOTPINK3", 205, 96, 144),
("HOTPINK4", 139, 58, 98),
("PINK1", 255, 181, 197),
("PINK2", 238, 169, 184),
("PINK3", 205, 145, 158),
("PINK4", 139, 99, 108),
("LIGHTPINK1", 255, 174, 185),
("LIGHTPINK2", 238, 162, 173),
("LIGHTPINK3", 205, 140, 149),
("LIGHTPINK4", 139, 95, 101),
("PALEVIOLETRED1", 255, 130, 171),
("PALEVIOLETRED2", 238, 121, 159),
("PALEVIOLETRED3", 205, 104, 137),
("PALEVIOLETRED4", 139, 71, 93),
("MAROON1", 255, 52, 179),
("MAROON2", 238, 48, 167),
("MAROON3", 205, 41, 144),
("MAROON4", 139, 28, 98),
("VIOLETRED1", 255, 62, 150),
("VIOLETRED2", 238, 58, 140),
("VIOLETRED3", 205, 50, 120),
("VIOLETRED4", 139, 34, 82),
("MAGENTA1", 255, 0, 255),
("MAGENTA2", 238, 0, 238),
("MAGENTA3", 205, 0, 205),
("MAGENTA4", 139, 0, 139),
("ORCHID1", 255, 131, 250),
("ORCHID2", 238, 122, 233),
("ORCHID3", 205, 105, 201),
("ORCHID4", 139, 71, 137),
("PLUM1", 255, 187, 255),
("PLUM2", 238, 174, 238),
("PLUM3", 205, 150, 205),
("PLUM4", 139, 102, 139),
("MEDIUMORCHID1", 224, 102, 255),
("MEDIUMORCHID2", 209, 95, 238),
("MEDIUMORCHID3", 180, 82, 205),
("MEDIUMORCHID4", 122, 55, 139),
("DARKORCHID1", 191, 62, 255),
("DARKORCHID2", 178, 58, 238),
("DARKORCHID3", 154, 50, 205),
("DARKORCHID4", 104, 34, 139),
("PURPLE1", 155, 48, 255),
("PURPLE2", 145, 44, 238),
("PURPLE3", 125, 38, 205),
("PURPLE4", 85, 26, 139),
("MEDIUMPURPLE1", 171, 130, 255),
("MEDIUMPURPLE2", 159, 121, 238),
("MEDIUMPURPLE3", 137, 104, 205),
("MEDIUMPURPLE4", 93, 71, 139),
("THISTLE1", 255, 225, 255),
("THISTLE2", 238, 210, 238),
("THISTLE3", 205, 181, 205),
("THISTLE4", 139, 123, 139),
("GREY0", 0, 0, 0),
("GREY1", 3, 3, 3),
("GREY2", 5, 5, 5),
("GREY3", 8, 8, 8),
("GREY4", 10, 10, 10),
("GREY5", 13, 13, 13),
("GREY6", 15, 15, 15),
("GREY7", 18, 18, 18),
("GREY8", 20, 20, 20),
("GREY9", 23, 23, 23),
("GREY10", 26, 26, 26),
("GREY11", 28, 28, 28),
("GREY12", 31, 31, 31),
("GREY13", 33, 33, 33),
("GREY14", 36, 36, 36),
("GREY15", 38, 38, 38),
("GREY16", 41, 41, 41),
("GREY17", 43, 43, 43),
("GREY18", 46, 46, 46),
("GREY19", 48, 48, 48),
("GREY20", 51, 51, 51),
("GREY21", 54, 54, 54),
("GREY22", 56, 56, 56),
("GREY23", 59, 59, 59),
("GREY24", 61, 61, 61),
("GREY25", 64, 64, 64),
("GREY26", 66, 66, 66),
("GREY27", 69, 69, 69),
("GREY28", 71, 71, 71),
("GREY29", 74, 74, 74),
("GREY30", 77, 77, 77),
("GREY31", 79, 79, 79),
("GREY32", 82, 82, 82),
("GREY33", 84, 84, 84),
("GREY34", 87, 87, 87),
("GREY35", 89, 89, 89),
("GREY36", 92, 92, 92),
("GREY37", 94, 94, 94),
("GREY38", 97, 97, 97),
("GREY39", 99, 99, 99),
("GREY40", 102, 102, 102),
("GREY41", 105, 105, 105),
("GREY42", 107, 107, 107),
("GREY43", 110, 110, 110),
("GREY44", 112, 112, 112),
("GREY45", 115, 115, 115),
("GREY46", 117, 117, 117),
("GREY47", 120, 120, 120),
("GREY48", 122, 122, 122),
("GREY49", 125, 125, 125),
("GREY50", 127, 127, 127),
("GREY51", 130, 130, 130),
("GREY52", 133, 133, 133),
("GREY53", 135, 135, 135),
("GREY54", 138, 138, 138),
("GREY55", 140, 140, 140),
("GREY56", 143, 143, 143),
("GREY57", 145, 145, 145),
("GREY58", 148, 148, 148),
("GREY59", 150, 150, 150),
("GREY60", 153, 153, 153),
("GREY61", 156, 156, 156),
("GREY62", 158, 158, 158),
("GREY63", 161, 161, 161),
("GREY64", 163, 163, 163),
("GREY65", 166, 166, 166),
("GREY66", 168, 168, 168),
("GREY67", 171, 171, 171),
("GREY68", 173, 173, 173),
("GREY69", 176, 176, 176),
("GREY70", 179, 179, 179),
("GREY71", 181, 181, 181),
("GREY72", 184, 184, 184),
("GREY73", 186, 186, 186),
("GREY74", 189, 189, 189),
("GREY75", 191, 191, 191),
("GREY76", 194, 194, 194),
("GREY77", 196, 196, 196),
("GREY78", 199, 199, 199),
("GREY79", 201, 201, 201),
("GREY80", 204, 204, 204),
("GREY81", 207, 207, 207),
("GREY82", 209, 209, 209),
("GREY83", 212, 212, 212),
("GREY84", 214, 214, 214),
("GREY85", 217, 217, 217),
("GREY86", 219, 219, 219),
("GREY87", 222, 222, 222),
("GREY88", 224, 224, 224),
("GREY89", 227, 227, 227),
("GREY90", 229, 229, 229),
("GREY91", 232, 232, 232),
("GREY92", 235, 235, 235),
("GREY93", 237, 237, 237),
("GREY94", 240, 240, 240),
("GREY95", 242, 242, 242),
("GREY96", 245, 245, 245),
("GREY97", 247, 247, 247),
("GREY98", 250, 250, 250),
("GREY99", 252, 252, 252),
("GREY100", 255, 255, 255),
("DARK GREY", 169, 169, 169),
("DARKGREY", 169, 169, 169),
("DARK BLUE", 0, 0, 139),
("DARKBLUE", 0, 0, 139),
("DARK CYAN", 0, 139, 139),
("DARKCYAN", 0, 139, 139),
("DARK MAGENTA", 139, 0, 139),
("DARKMAGENTA", 139, 0, 139),
("DARK RED", 139, 0, 0),
("DARKRED", 139, 0, 0),
("LIGHT GREEN", 144, 238, 144),
("LIGHTGREEN", 144, 238, 144),
]
_haveUpdated = False
def updateColourDB():
global _haveUpdated
if not _haveUpdated:
from wxPython.wx import wxTheColourDatabase
cl = getColourInfoList()
for info in cl:
wxTheColourDatabase.Append(*info)
import wx.lib.colourdb
__doc__ = wx.lib.colourdb.__doc__
getColourInfoList = wx.lib.colourdb.getColourInfoList
getColourList = wx.lib.colourdb.getColourList
updateColourDB = wx.lib.colourdb.updateColourDB

View File

@@ -1,90 +1,11 @@
#----------------------------------------------------------------------------
# Name: ColourSelect.py
# Purpose: Colour Box Selection Control
#
# Author: Lorne White, Lorne.White@telusplanet.net
#
# Created: Feb 25, 2001
# Licence: wxWindows license
#----------------------------------------------------------------------------
## This file imports items from the wx package into the wxPython package for
## backwards compatibility. Some names will also have a 'wx' added on if
## that is how they used to be named in the old wxPython package.
from wxPython.wx import *
import wx.lib.colourselect
# creates a colour wxButton with selectable color
# button click provides a colour selection box
# button colour will change to new colour
# GetColour method to get the selected colour
# Updates:
# call back to function if changes made
# Cliff Wells, logiplexsoftware@earthlink.net:
# - Made ColourSelect into "is a button" rather than "has a button"
# - Added label parameter and logic to adjust the label colour according to the background
# colour
# - Added id argument
# - Rearranged arguments to more closely follow wx conventions
# - Simplified some of the code
# Cliff Wells, 2002/02/07
# - Added ColourSelect Event
EVT_COMMAND_COLOURSELECT = wxNewId()
class ColourSelectEvent(wxPyCommandEvent):
def __init__(self, id, value):
wxPyCommandEvent.__init__(self, id = id)
self.SetEventType(EVT_COMMAND_COLOURSELECT)
self.value = value
def GetValue(self):
return self.value
def EVT_COLOURSELECT(win, id, func):
win.Connect(id, -1, EVT_COMMAND_COLOURSELECT, func)
class ColourSelect(wxButton):
def __init__(self, parent, id, label = "", bcolour=(0, 0, 0),
pos = wxDefaultPosition, size = wxDefaultSize,
callback = None):
wxButton.__init__(self, parent, id, label, pos=pos, size=size)
self.SetColour(bcolour)
self.callback = callback
EVT_BUTTON(parent, self.GetId(), self.OnClick)
def GetColour(self):
return self.set_colour
def GetValue(self):
return self.set_colour
def SetColour(self, bcolour):
self.set_colour_val = wxColor(bcolour[0], bcolour[1], bcolour[2])
self.SetBackgroundColour(self.set_colour_val)
avg = reduce(lambda a, b: a + b, bcolour) / 3
fcolour = avg > 128 and (0, 0, 0) or (255, 255, 255)
self.SetForegroundColour(apply(wxColour, fcolour))
self.set_colour = bcolour
def SetValue(self, bcolour):
self.SetColour(bcolour)
def OnChange(self):
wxPostEvent(self, ColourSelectEvent(self.GetId(), self.GetValue()))
if self.callback is not None:
self.callback()
def OnClick(self, event):
data = wxColourData()
data.SetChooseFull(True)
data.SetColour(self.set_colour_val)
dlg = wxColourDialog(self.GetParent(), data)
changed = dlg.ShowModal() == wxID_OK
if changed:
data = dlg.GetColourData()
self.SetColour(data.GetColour().Get())
dlg.Destroy()
if changed:
self.OnChange() # moved after dlg.Destroy, since who knows what the callback will do...
__doc__ = wx.lib.colourselect.__doc__
ColourSelect = wx.lib.colourselect.ColourSelect
ColourSelectEvent = wx.lib.colourselect.ColourSelectEvent
EVT_COLOURSELECT = wx.lib.colourselect.EVT_COLOURSELECT

View File

@@ -1,385 +1,27 @@
#----------------------------------------------------------------------
# Name: wxPython.lib.dialogs
# Purpose: wxScrolledMessageDialog, wxMultipleChoiceDialog and
# function wrappers for the common dialogs by Kevin Altis.
#
# Author: Various
#
# Created: 3-January-2002
# RCS-ID: $Id$
# Copyright: (c) 2002 by Total Control Software
# Licence: wxWindows license
#----------------------------------------------------------------------
## This file imports items from the wx package into the wxPython package for
## backwards compatibility. Some names will also have a 'wx' added on if
## that is how they used to be named in the old wxPython package.
from wxPython import wx
from layoutf import Layoutf
import wx.lib.dialogs
#----------------------------------------------------------------------
__doc__ = wx.lib.dialogs.__doc__
class wxScrolledMessageDialog(wx.wxDialog):
def __init__(self, parent, msg, caption, pos = wx.wxDefaultPosition, size = (500,300)):
wx.wxDialog.__init__(self, parent, -1, caption, pos, size)
x, y = pos
if x == -1 and y == -1:
self.CenterOnScreen(wx.wxBOTH)
text = wx.wxTextCtrl(self, -1, msg, wx.wxDefaultPosition,
wx.wxDefaultSize,
wx.wxTE_MULTILINE | wx.wxTE_READONLY)
ok = wx.wxButton(self, wx.wxID_OK, "OK")
text.SetConstraints(Layoutf('t=t5#1;b=t5#2;l=l5#1;r=r5#1', (self,ok)))
ok.SetConstraints(Layoutf('b=b5#1;x%w50#1;w!80;h!25', (self,)))
self.SetAutoLayout(1)
self.Layout()
class wxMultipleChoiceDialog(wx.wxDialog):
def __init__(self, parent, msg, title, lst, pos = wx.wxDefaultPosition,
size = (200,200), style = wx.wxDEFAULT_DIALOG_STYLE):
wx.wxDialog.__init__(self, parent, -1, title, pos, size, style)
x, y = pos
if x == -1 and y == -1:
self.CenterOnScreen(wx.wxBOTH)
dc = wx.wxClientDC(self)
height = 0
for line in msg.splitlines():
height = height + dc.GetTextExtent(line)[1] + 2
stat = wx.wxStaticText(self, -1, msg)
self.lbox = wx.wxListBox(self, 100, wx.wxDefaultPosition,
wx.wxDefaultSize, lst, wx.wxLB_MULTIPLE)
ok = wx.wxButton(self, wx.wxID_OK, "OK")
cancel = wx.wxButton(self, wx.wxID_CANCEL, "Cancel")
stat.SetConstraints(Layoutf('t=t10#1;l=l5#1;r=r5#1;h!%d' % (height,),
(self,)))
self.lbox.SetConstraints(Layoutf('t=b10#2;l=l5#1;r=r5#1;b=t5#3',
(self, stat, ok)))
ok.SetConstraints(Layoutf('b=b5#1;x%w25#1;w!80;h!25', (self,)))
cancel.SetConstraints(Layoutf('b=b5#1;x%w75#1;w!80;h!25', (self,)))
self.SetAutoLayout(1)
self.lst = lst
self.Layout()
def GetValue(self):
return self.lbox.GetSelections()
def GetValueString(self):
sel = self.lbox.GetSelections()
val = []
for i in sel:
val.append(self.lst[i])
return tuple(val)
#----------------------------------------------------------------------
"""
function wrappers for wxPython system dialogs
Author: Kevin Altis
Date: 2003-1-2
Rev: 3
This is the third refactor of the PythonCard dialog.py module
for inclusion in the main wxPython distribution. There are a number of
design decisions and subsequent code refactoring to be done, so I'm
releasing this just to get some feedback.
rev 3:
- result dictionary replaced by DialogResults class instance
- should message arg be replaced with msg? most wxWindows dialogs
seem to use the abbreviation?
rev 2:
- All dialog classes have been replaced by function wrappers
- Changed arg lists to more closely match wxWindows docs and wxPython.lib.dialogs
- changed 'returned' value to the actual button id the user clicked on
- added a returnedString value for the string version of the return value
- reworked colorDialog and fontDialog so you can pass in just a color or font
for the most common usage case
- probably need to use colour instead of color to match the English English
spelling in wxWindows (sigh)
- I still think we could lose the parent arg and just always use None
"""
class DialogResults:
def __init__(self, returned):
self.returned = returned
self.accepted = returned in (wx.wxID_OK, wx.wxID_YES)
self.returnedString = returnedString(returned)
def __repr__(self):
return str(self.__dict__)
def returnedString(ret):
if ret == wx.wxID_OK:
return "Ok"
elif ret == wx.wxID_CANCEL:
return "Cancel"
elif ret == wx.wxID_YES:
return "Yes"
elif ret == wx.wxID_NO:
return "No"
# findDialog was created before wxPython got a Find/Replace dialog
# but it may be instructive as to how a function wrapper can
# be added for your own custom dialogs
# this dialog is always modal, while wxFindReplaceDialog is
# modeless and so doesn't lend itself to a function wrapper
def findDialog(parent=None, searchText='', wholeWordsOnly=0, caseSensitive=0):
dlg = wx.wxDialog(parent, -1, "Find", wx.wxDefaultPosition, wx.wxSize(370, 120))
wx.wxStaticText(dlg, -1, 'Find what:', wx.wxPoint(7, 10))
wSearchText = wx.wxTextCtrl(dlg, -1, searchText,
wx.wxPoint(70, 7), wx.wxSize(195, -1))
wSearchText.SetValue(searchText)
wx.wxButton(dlg, wx.wxID_OK, "Find Next", wx.wxPoint(280, 5), wx.wxDefaultSize).SetDefault()
wx.wxButton(dlg, wx.wxID_CANCEL, "Cancel", wx.wxPoint(280, 35), wx.wxDefaultSize)
wWholeWord = wx.wxCheckBox(dlg, -1, 'Match whole word only',
wx.wxPoint(7, 35), wx.wxDefaultSize, wx.wxNO_BORDER)
if wholeWordsOnly:
wWholeWord.SetValue(1)
wCase = wx.wxCheckBox(dlg, -1, 'Match case',
wx.wxPoint(7, 55), wx.wxDefaultSize, wx.wxNO_BORDER)
if caseSensitive:
wCase.SetValue(1)
wSearchText.SetSelection(0, len(wSearchText.GetValue()))
wSearchText.SetFocus()
result = DialogResults(dlg.ShowModal())
result.text = wSearchText.GetValue()
result.wholeword = wWholeWord.GetValue()
result.casesensitive = wCase.GetValue()
dlg.Destroy()
return result
def colorDialog(parent=None, colorData=None, color=None):
if colorData:
dialog = wx.wxColourDialog(parent, colorData)
else:
dialog = wx.wxColourDialog(parent)
dialog.GetColourData().SetChooseFull(1)
if color is not None:
dialog.GetColourData().SetColour(color)
result = DialogResults(dialog.ShowModal())
result.colorData = dialog.GetColourData()
result.color = result.colorData.GetColour().Get()
dialog.Destroy()
return result
# it is easier to just duplicate the code than
# try and replace color with colour in the result
def colourDialog(parent=None, colourData=None, colour=None):
if colourData:
dialog = wx.wxColourDialog(parent, colourData)
else:
dialog = wx.wxColourDialog(parent)
dialog.GetColourData().SetChooseFull(1)
if colour is not None:
dialog.GetColourData().SetColour(color)
result = DialogResults(dialog.ShowModal())
result.colourData = dialog.GetColourData()
result.colour = result.colourData.GetColour().Get()
dialog.Destroy()
return result
def fontDialog(parent=None, fontData=None, font=None):
if fontData is None:
fontData = wx.wxFontData()
if font is not None:
aFontData.SetInitialFont(font)
dialog = wx.wxFontDialog(parent, fontData)
result = DialogResults(dialog.ShowModal())
if result.accepted:
fontData = dialog.GetFontData()
result.fontData = fontData
result.color = fontData.GetColour().Get()
result.colour = result.color
result.font = fontData.GetChosenFont()
else:
result.color = None
result.colour = None
result.font = None
dialog.Destroy()
return result
def textEntryDialog(parent=None, message='', title='', defaultText='', style=wx.wxOK | wx.wxCANCEL):
dialog = wx.wxTextEntryDialog(parent, message, title, defaultText, style)
result = DialogResults(dialog.ShowModal())
result.text = dialog.GetValue()
dialog.Destroy()
return result
def messageDialog(parent=None, message='', title='Message box',
aStyle = wx.wxOK | wx.wxCANCEL | wx.wxCENTRE,
pos=wx.wxDefaultPosition):
dialog = wx.wxMessageDialog(parent, message, title, aStyle, pos)
result = DialogResults(dialog.ShowModal())
dialog.Destroy()
return result
# KEA alerts are common, so I'm providing a class rather than
# requiring the user code to set up the right icons and buttons
# the with messageDialog function
def alertDialog(parent=None, message='', title='Alert', pos=wx.wxDefaultPosition):
return messageDialog(parent, message, title, wx.wxICON_EXCLAMATION | wx.wxOK, pos)
def scrolledMessageDialog(parent=None, message='', title='', pos=wx.wxDefaultPosition, size=(500,300)):
dialog = wxScrolledMessageDialog(parent, message, title, pos, size)
result = DialogResults(dialog.ShowModal())
dialog.Destroy()
return result
def fileDialog(parent=None, title='Open', directory='', filename='', wildcard='*.*',
style=wx.wxOPEN | wx.wxMULTIPLE):
dialog = wx.wxFileDialog(parent, title, directory, filename, wildcard, style)
result = DialogResults(dialog.ShowModal())
if result.accepted:
result.paths = dialog.GetPaths()
else:
result.paths = None
dialog.Destroy()
return result
# openFileDialog and saveFileDialog are convenience functions
# they represent the most common usages of the fileDialog
# with the most common style options
def openFileDialog(parent=None, title='Open', directory='', filename='',
wildcard='All Files (*.*)|*.*',
style=wx.wxOPEN | wx.wxMULTIPLE):
return fileDialog(parent, title, directory, filename, wildcard, style)
def saveFileDialog(parent=None, title='Save', directory='', filename='',
wildcard='All Files (*.*)|*.*',
style=wx.wxSAVE | wx.wxHIDE_READONLY | wx.wxOVERWRITE_PROMPT):
return fileDialog(parent, title, directory, filename, wildcard, style)
def dirDialog(parent=None, message='Choose a directory', path='', style=0,
pos=wx.wxDefaultPosition, size=wx.wxDefaultSize):
dialog = wx.wxDirDialog(parent, message, path, style, pos, size)
result = DialogResults(dialog.ShowModal())
if result.accepted:
result.path = dialog.GetPath()
else:
result.path = None
dialog.Destroy()
return result
directoryDialog = dirDialog
def singleChoiceDialog(parent=None, message='', title='', lst=[],
style=wx.wxOK | wx.wxCANCEL | wx.wxCENTRE):
dialog = wx.wxSingleChoiceDialog(parent,
message,
title,
lst,
style)
result = DialogResults(dialog.ShowModal())
result.selection = dialog.GetStringSelection()
dialog.Destroy()
return result
def multipleChoiceDialog(parent=None, message='', title='', lst=[], pos=wx.wxDefaultPosition, size=(200,200)):
dialog = wxMultipleChoiceDialog(parent, message, title, lst, pos, size)
result = DialogResults(dialog.ShowModal())
result.selection = dialog.GetValueString()
dialog.Destroy()
return result
if __name__ == '__main__':
class MyApp(wx.wxApp):
def OnInit(self):
frame = wx.wxFrame(wx.NULL, -1, "Dialogs", size=(400, 200))
panel = wx.wxPanel(frame, -1)
self.panel = panel
frame.Show(1)
dialogNames = [
'alertDialog',
'colorDialog',
'directoryDialog',
'fileDialog',
'findDialog',
'fontDialog',
'messageDialog',
'multipleChoiceDialog',
'openFileDialog',
'saveFileDialog',
'scrolledMessageDialog',
'singleChoiceDialog',
'textEntryDialog',
]
self.nameList = wx.wxListBox(panel, -1, (0, 0), (130, 180), dialogNames, style=wx.wxLB_SINGLE)
wx.EVT_LISTBOX(panel, self.nameList.GetId(), self.OnNameListSelected)
tstyle = wx.wxTE_RICH2 | wx.wxTE_PROCESS_TAB | wx.wxTE_MULTILINE
self.text1 = wx.wxTextCtrl(panel, -1, pos=(150, 0), size=(200, 180), style=tstyle)
self.SetTopWindow(frame)
return 1
def OnNameListSelected(self, evt):
import pprint
sel = evt.GetString()
result = None
if sel == 'alertDialog':
result = alertDialog(message='Danger Will Robinson')
elif sel == 'colorDialog':
result = colorDialog()
elif sel == 'directoryDialog':
result = directoryDialog()
elif sel == 'fileDialog':
wildcard = "JPG files (*.jpg;*.jpeg)|*.jpeg;*.JPG;*.JPEG;*.jpg|GIF files (*.gif)|*.GIF;*.gif|All Files (*.*)|*.*"
result = fileDialog(None, 'Open', '', '', wildcard)
elif sel == 'findDialog':
result = findDialog()
elif sel == 'fontDialog':
result = fontDialog()
elif sel == 'messageDialog':
result = messageDialog(None, 'Hello from Python and wxPython!',
'A Message Box', wx.wxOK | wx.wxICON_INFORMATION)
#wx.wxYES_NO | wx.wxNO_DEFAULT | wx.wxCANCEL | wx.wxICON_INFORMATION)
#result = messageDialog(None, 'message', 'title')
elif sel == 'multipleChoiceDialog':
result = multipleChoiceDialog(None, "message", "title", ['one', 'two', 'three'])
elif sel == 'openFileDialog':
result = openFileDialog()
elif sel == 'saveFileDialog':
result = saveFileDialog()
elif sel == 'scrolledMessageDialog':
msg = "Can't find the file dialog.py"
try:
# read this source file and then display it
import sys
filename = sys.argv[-1]
fp = open(filename)
message = fp.read()
fp.close()
except:
pass
result = scrolledMessageDialog(None, message, filename)
elif sel == 'singleChoiceDialog':
result = singleChoiceDialog(None, "message", "title", ['one', 'two', 'three'])
elif sel == 'textEntryDialog':
result = textEntryDialog(None, "message", "title", "text")
if result:
#self.text1.SetValue(pprint.pformat(result.__dict__))
self.text1.SetValue(str(result))
app = MyApp(0)
app.MainLoop()
DialogResults = wx.lib.dialogs.DialogResults
alertDialog = wx.lib.dialogs.alertDialog
colorDialog = wx.lib.dialogs.colorDialog
colourDialog = wx.lib.dialogs.colourDialog
dirDialog = wx.lib.dialogs.dirDialog
directoryDialog = wx.lib.dialogs.directoryDialog
fileDialog = wx.lib.dialogs.fileDialog
findDialog = wx.lib.dialogs.findDialog
fontDialog = wx.lib.dialogs.fontDialog
messageDialog = wx.lib.dialogs.messageDialog
multipleChoiceDialog = wx.lib.dialogs.multipleChoiceDialog
openFileDialog = wx.lib.dialogs.openFileDialog
returnedString = wx.lib.dialogs.returnedString
saveFileDialog = wx.lib.dialogs.saveFileDialog
scrolledMessageDialog = wx.lib.dialogs.scrolledMessageDialog
singleChoiceDialog = wx.lib.dialogs.singleChoiceDialog
textEntryDialog = wx.lib.dialogs.textEntryDialog
wxMultipleChoiceDialog = wx.lib.dialogs.wxMultipleChoiceDialog
wxScrolledMessageDialog = wx.lib.dialogs.wxScrolledMessageDialog

View File

@@ -1,77 +0,0 @@
wxEditor component
------------------
The wxEditor class implements a simple text editor using wxPython. You
can create a custom editor by subclassing wxEditor. Even though much of
the editor is implemented in Python, it runs surprisingly smoothly on
normal hardware with small files.
Keys
----
Keys are similar to Windows-based editors:
Tab: 1 to 4 spaces (to next tab stop)
Cursor movement: Arrow keys
Beginning of line: Home
End of line: End
Beginning of buffer: Control-Home
End of the buffer: Control-End
Select text: Hold down Shift while moving the cursor
Copy: Shift-Insert, Control-C
Cut: Shift-Delete, Control-X
Paste: Control-Insert, Control-V
How to use it
-------------
The demo code (demo/wxEditor.py) shows how to use it as a simple text
box. Use the SetText() and GetText() methods to set or get text from
the component; these both return a list of strings.
The samples/FrogEdit directory has an example of a simple text editor
application that uses the wxEditor component.
Subclassing
-----------
To add or change functionality, you can subclass this
component. One example of this might be to change the key
Alt key commands. In that case you would (for example) override the
SetAltFuncs() method.
History
-------
The original author of this component was Dirk Holtwic. It originally
had limited support for syntax highlighting, but was not a usable text
editor, as it didn't implement select (with keys or mouse), or any of
the usual key sequences you'd expect in an editor. Robin Dunn did some
refactoring work to make it more usable. Steve Howell and Adam Feuer
did a lot of refactoring, and added some functionality, including
keyboard and mouse select, properly working scrollbars, and
overridable keys. Adam and Steve also removed support for
syntax-highlighting while refactoring the code.
To do
-----
Alt/Ctrl Arrow keys move by word
Descriptive help text for keys
Speed improvements
Different fonts/colors
Authors
-------
Steve Howell, Adam Feuer, Dirk Holtwic, Robin Dunn
Contact
-------
You can find the latest code for wxEditor here:
http://www.pobox.com/~adamf/software/
We're not actively maintaining this code, but we can answer
questions about it. You can email us at:
Adam Feuer <adamf at pobox dot com>
Steve Howell <showell at zipcon dot net>
29 November 2001

View File

@@ -1,17 +1 @@
#----------------------------------------------------------------------
# Name: wxPython.lib.editor
# Purpose: A package containing a colourizable text editror
#
# Author: Robin Dunn
#
# Created: 30-Dec-1999
# RCS-ID: $Id$
# Copyright: (c) 1999 by Total Control Software
# Licence: wxWindows license
#----------------------------------------------------------------------
# This file makes this directory into a Python package
# import the main classes into the package namespace.
from editor import wxEditor

View File

@@ -1,956 +1,13 @@
#----------------------------------------------------------------------
# Name: wxPython.lib.editor.wxEditor
# Purpose: An intelligent text editor with colorization capabilities.
#
# Original
# Authors: Dirk Holtwic, Robin Dunn
#
# New
# Authors: Adam Feuer, Steve Howell
#
# History:
# This code used to support a fairly complex subclass that did
# syntax coloring and outliner collapse mode. Adam and Steve
# inherited the code, and added a lot of basic editor
# functionality that had not been there before, such as cut-and-paste.
#
#
# Created: 15-Dec-1999
# RCS-ID: $Id$
# Copyright: (c) 1999 by Dirk Holtwick, 1999
# Licence: wxWindows license
#----------------------------------------------------------------------
## This file imports items from the wx package into the wxPython package for
## backwards compatibility. Some names will also have a 'wx' added on if
## that is how they used to be named in the old wxPython package.
import os, time
import wx.lib.editor.editor
from wxPython.wx import *
import selection
import images
#----------------------------
def ForceBetween(min, val, max):
if val > max:
return max
if val < min:
return min
return val
def LineTrimmer(lineOfText):
if len(lineOfText) == 0:
return ""
elif lineOfText[-1] == '\r':
return lineOfText[:-1]
else:
return lineOfText
def LineSplitter(text):
return map (LineTrimmer, text.split('\n'))
#----------------------------
class Scroller:
def __init__(self, parent):
self.parent = parent
self.ow = 0
self.oh = 0
self.ox = 0
self.oy = 0
def SetScrollbars(self, fw, fh, w, h, x, y):
if (self.ow != w or self.oh != h or self.ox != x or self.oy != y):
self.parent.SetScrollbars(fw, fh, w, h, x, y)
self.ow = w
self.oh = h
self.ox = x
self.oy = y
#----------------------------------------------------------------------
class wxEditor(wxScrolledWindow):
def __init__(self, parent, id,
pos=wxDefaultPosition, size=wxDefaultSize, style=0):
wxScrolledWindow.__init__(self, parent, id,
pos, size,
style|wxWANTS_CHARS)
self.isDrawing = False
self.InitCoords()
self.InitFonts()
self.SetColors()
self.MapEvents()
self.LoadImages()
self.InitDoubleBuffering()
self.InitScrolling()
self.SelectOff()
self.SetFocus()
self.SetText([""])
self.SpacesPerTab = 4
##------------------ Init stuff
def InitCoords(self):
self.cx = 0
self.cy = 0
self.oldCx = 0
self.oldCy = 0
self.sx = 0
self.sy = 0
self.sw = 0
self.sh = 0
self.sco_x = 0
self.sco_y = 0
def MapEvents(self):
EVT_LEFT_DOWN(self, self.OnLeftDown)
EVT_LEFT_UP(self, self.OnLeftUp)
EVT_MOTION(self, self.OnMotion)
EVT_SCROLLWIN(self, self.OnScroll)
EVT_CHAR(self, self.OnChar)
EVT_PAINT(self, self.OnPaint)
EVT_SIZE(self, self.OnSize)
EVT_WINDOW_DESTROY(self, self.OnDestroy)
EVT_ERASE_BACKGROUND(self, self.OnEraseBackground)
##------------------- Platform-specific stuff
def NiceFontForPlatform(self):
if wxPlatform == "__WXMSW__":
return wxFont(10, wxMODERN, wxNORMAL, wxNORMAL)
else:
return wxFont(12, wxMODERN, wxNORMAL, wxNORMAL, False)
def UnixKeyHack(self, key):
# this will be obsolete when we get the new wxWindows patch
if key <= 26:
key += ord('a') - 1
return key
##-------------------- UpdateView/Cursor code
def OnSize(self, event):
self.AdjustScrollbars()
self.SetFocus()
def SetCharDimensions(self):
# TODO: We need a code review on this. It appears that Linux
# improperly reports window dimensions when the scrollbar's there.
self.bw, self.bh = self.GetClientSizeTuple()
if wxPlatform == "__WXMSW__":
self.sh = self.bh / self.fh
self.sw = (self.bw / self.fw) - 1
else:
self.sh = self.bh / self.fh
if self.LinesInFile() >= self.sh:
self.bw = self.bw - wxSystemSettings_GetSystemMetric(wxSYS_VSCROLL_X)
self.sw = (self.bw / self.fw) - 1
self.sw = (self.bw / self.fw) - 1
if self.CalcMaxLineLen() >= self.sw:
self.bh = self.bh - wxSystemSettings_GetSystemMetric(wxSYS_HSCROLL_Y)
self.sh = self.bh / self.fh
def UpdateView(self, dc = None):
if dc is None:
dc = wxClientDC(self)
if dc.Ok():
self.SetCharDimensions()
self.KeepCursorOnScreen()
self.DrawSimpleCursor(0,0,dc, True)
self.Draw(dc)
def OnPaint(self, event):
dc = wxPaintDC(self)
if self.isDrawing:
return
self.isDrawing = True
self.UpdateView(dc)
wxCallAfter(self.AdjustScrollbars)
self.isDrawing = False
def OnEraseBackground(self, evt):
pass
##-------------------- Drawing code
def InitFonts(self):
dc = wxClientDC(self)
self.font = self.NiceFontForPlatform()
dc.SetFont(self.font)
self.fw = dc.GetCharWidth()
self.fh = dc.GetCharHeight()
def SetColors(self):
self.fgColor = wxNamedColour('black')
self.bgColor = wxNamedColour('white')
self.selectColor = wxColour(238, 220, 120) # r, g, b = emacsOrange
def InitDoubleBuffering(self):
pass
def DrawEditText(self, t, x, y, dc):
dc.DrawText(t, x * self.fw, y * self.fh)
def DrawLine(self, line, dc):
if self.IsLine(line):
l = line
t = self.lines[l]
dc.SetTextForeground(self.fgColor)
fragments = selection.Selection(
self.SelectBegin, self.SelectEnd,
self.sx, self.sw, line, t)
x = 0
for (data, selected) in fragments:
if selected:
dc.SetTextBackground(self.selectColor)
if x == 0 and len(data) == 0 and len(fragments) == 1:
data = ' '
else:
dc.SetTextBackground(self.bgColor)
self.DrawEditText(data, x, line - self.sy, dc)
x += len(data)
def Draw(self, odc=None):
if not odc:
odc = wxClientDC(self)
bmp = wxEmptyBitmap(max(1,self.bw), max(1,self.bh))
dc = wxBufferedDC(odc, bmp)
if dc.Ok():
dc.SetFont(self.font)
dc.SetBackgroundMode(wxSOLID)
dc.SetTextBackground(self.bgColor)
dc.SetTextForeground(self.fgColor)
dc.Clear()
for line in range(self.sy, self.sy + self.sh):
self.DrawLine(line, dc)
if len(self.lines) < self.sh + self.sy:
self.DrawEofMarker(dc)
self.DrawCursor(dc)
##------------------ eofMarker stuff
def LoadImages(self):
self.eofMarker = images.GetBitmap(images.EofImageData)
def DrawEofMarker(self,dc):
x = 0
y = (len(self.lines) - self.sy) * self.fh
hasTransparency = 1
dc.DrawBitmap(self.eofMarker, x, y, hasTransparency)
##------------------ cursor-related functions
def DrawCursor(self, dc = None):
if not dc:
dc = wxClientDC(self)
if (self.LinesInFile())<self.cy: #-1 ?
self.cy = self.LinesInFile()-1
s = self.lines[self.cy]
x = self.cx - self.sx
y = self.cy - self.sy
self.DrawSimpleCursor(x, y, dc)
def DrawSimpleCursor(self, xp, yp, dc = None, old=False):
if not dc:
dc = wxClientDC(self)
if old:
xp = self.sco_x
yp = self.sco_y
szx = self.fw
szy = self.fh
x = xp * szx
y = yp * szy
dc.Blit(x,y,szx,szy,dc,x,y,wxSRC_INVERT)
self.sco_x = xp
self.sco_y = yp
##-------- Enforcing screen boundaries, cursor movement
def CalcMaxLineLen(self):
"""get length of longest line on screen"""
maxlen = 0
for line in self.lines[self.sy:self.sy+self.sh]:
if len(line) >maxlen:
maxlen = len(line)
return maxlen
def KeepCursorOnScreen(self):
self.sy = ForceBetween(max(0, self.cy-self.sh), self.sy, self.cy)
self.sx = ForceBetween(max(0, self.cx-self.sw), self.sx, self.cx)
self.AdjustScrollbars()
def HorizBoundaries(self):
self.SetCharDimensions()
maxLineLen = self.CalcMaxLineLen()
self.sx = ForceBetween(0, self.sx, max(self.sw, maxLineLen - self.sw + 1))
self.cx = ForceBetween(self.sx, self.cx, self.sx + self.sw - 1)
def VertBoundaries(self):
self.SetCharDimensions()
self.sy = ForceBetween(0, self.sy, max(self.sh, self.LinesInFile() - self.sh + 1))
self.cy = ForceBetween(self.sy, self.cy, self.sy + self.sh - 1)
def cVert(self, num):
self.cy = self.cy + num
self.cy = ForceBetween(0, self.cy, self.LinesInFile() - 1)
self.sy = ForceBetween(self.cy - self.sh + 1, self.sy, self.cy)
self.cx = min(self.cx, self.CurrentLineLength())
def cHoriz(self, num):
self.cx = self.cx + num
self.cx = ForceBetween(0, self.cx, self.CurrentLineLength())
self.sx = ForceBetween(self.cx - self.sw + 1, self.sx, self.cx)
def AboveScreen(self, row):
return row < self.sy
def BelowScreen(self, row):
return row >= self.sy + self.sh
def LeftOfScreen(self, col):
return col < self.sx
def RightOfScreen(self, col):
return col >= self.sx + self.sw
##----------------- data structure helper functions
def GetText(self):
return self.lines
def SetText(self, lines):
self.InitCoords()
self.lines = lines
self.UnTouchBuffer()
self.SelectOff()
self.AdjustScrollbars()
self.UpdateView(None)
def IsLine(self, lineNum):
return (0<=lineNum) and (lineNum<self.LinesInFile())
def GetTextLine(self, lineNum):
if self.IsLine(lineNum):
return self.lines[lineNum]
return ""
def SetTextLine(self, lineNum, text):
if self.IsLine(lineNum):
self.lines[lineNum] = text
def CurrentLineLength(self):
return len(self.lines[self.cy])
def LinesInFile(self):
return len(self.lines)
def UnTouchBuffer(self):
self.bufferTouched = False
def BufferWasTouched(self):
return self.bufferTouched
def TouchBuffer(self):
self.bufferTouched = True
##-------------------------- Mouse scroll timing functions
def InitScrolling(self):
# we don't rely on the windows system to scroll for us; we just
# redraw the screen manually every time
self.EnableScrolling(False, False)
self.nextScrollTime = 0
self.SCROLLDELAY = 0.050 # seconds
self.scrollTimer = wxTimer(self)
self.scroller = Scroller(self)
def CanScroll(self):
if time.time() > self.nextScrollTime:
self.nextScrollTime = time.time() + self.SCROLLDELAY
return True
else:
return False
def SetScrollTimer(self):
oneShot = True
self.scrollTimer.Start(1000*self.SCROLLDELAY/2, oneShot)
EVT_TIMER(self, -1, self.OnTimer)
def OnTimer(self, event):
screenX, screenY = wxGetMousePosition()
x, y = self.ScreenToClientXY(screenX, screenY)
self.MouseToRow(y)
self.MouseToCol(x)
self.SelectUpdate()
##-------------------------- Mouse off screen functions
def HandleAboveScreen(self, row):
self.SetScrollTimer()
if self.CanScroll():
row = self.sy - 1
row = max(0, row)
self.cy = row
def HandleBelowScreen(self, row):
self.SetScrollTimer()
if self.CanScroll():
row = self.sy + self.sh
row = min(row, self.LinesInFile() - 1)
self.cy = row
def HandleLeftOfScreen(self, col):
self.SetScrollTimer()
if self.CanScroll():
col = self.sx - 1
col = max(0,col)
self.cx = col
def HandleRightOfScreen(self, col):
self.SetScrollTimer()
if self.CanScroll():
col = self.sx + self.sw
col = min(col, self.CurrentLineLength())
self.cx = col
##------------------------ mousing functions
def MouseToRow(self, mouseY):
row = self.sy + (mouseY/ self.fh)
if self.AboveScreen(row):
self.HandleAboveScreen(row)
elif self.BelowScreen(row):
self.HandleBelowScreen(row)
else:
self.cy = min(row, self.LinesInFile() - 1)
def MouseToCol(self, mouseX):
col = self.sx + (mouseX / self.fw)
if self.LeftOfScreen(col):
self.HandleLeftOfScreen(col)
elif self.RightOfScreen(col):
self.HandleRightOfScreen(col)
else:
self.cx = min(col, self.CurrentLineLength())
def MouseToCursor(self, event):
self.MouseToRow(event.GetY())
self.MouseToCol(event.GetX())
def OnMotion(self, event):
if event.LeftIsDown() and self.HasCapture():
self.Selecting = True
self.MouseToCursor(event)
self.SelectUpdate()
def OnLeftDown(self, event):
self.MouseToCursor(event)
self.SelectBegin = (self.cy, self.cx)
self.SelectEnd = None
self.UpdateView()
self.CaptureMouse()
def OnLeftUp(self, event):
if not self.HasCapture():
return
if self.SelectEnd is None:
self.OnClick()
else:
self.Selecting = False
self.SelectNotify(False, self.SelectBegin, self.SelectEnd)
self.ReleaseMouse()
self.scrollTimer.Stop()
#------------------------- Scrolling
def HorizScroll(self, event, eventType):
maxLineLen = self.CalcMaxLineLen()
if eventType == wxEVT_SCROLLWIN_LINEUP:
self.sx -= 1
elif eventType == wxEVT_SCROLLWIN_LINEDOWN:
self.sx += 1
elif eventType == wxEVT_SCROLLWIN_PAGEUP:
self.sx -= self.sw
elif eventType == wxEVT_SCROLLWIN_PAGEDOWN:
self.sx += self.sw
elif eventType == wxEVT_SCROLLWIN_TOP:
self.sx = self.cx = 0
elif eventType == wxEVT_SCROLLWIN_BOTTOM:
self.sx = maxLineLen - self.sw
self.cx = maxLineLen
else:
self.sx = event.GetPosition()
self.HorizBoundaries()
def VertScroll(self, event, eventType):
if eventType == wxEVT_SCROLLWIN_LINEUP:
self.sy -= 1
elif eventType == wxEVT_SCROLLWIN_LINEDOWN:
self.sy += 1
elif eventType == wxEVT_SCROLLWIN_PAGEUP:
self.sy -= self.sh
elif eventType == wxEVT_SCROLLWIN_PAGEDOWN:
self.sy += self.sh
elif eventType == wxEVT_SCROLLWIN_TOP:
self.sy = self.cy = 0
elif eventType == wxEVT_SCROLLWIN_BOTTOM:
self.sy = self.LinesInFile() - self.sh
self.cy = self.LinesInFile()
else:
self.sy = event.GetPosition()
self.VertBoundaries()
def OnScroll(self, event):
dir = event.GetOrientation()
eventType = event.GetEventType()
if dir == wxHORIZONTAL:
self.HorizScroll(event, eventType)
else:
self.VertScroll(event, eventType)
self.UpdateView()
def AdjustScrollbars(self):
for i in range(2):
self.SetCharDimensions()
self.scroller.SetScrollbars(
self.fw, self.fh,
self.CalcMaxLineLen()+3, max(self.LinesInFile()+1, self.sh),
self.sx, self.sy)
#------------ backspace, delete, return
def BreakLine(self, event):
if self.IsLine(self.cy):
t = self.lines[self.cy]
self.lines = self.lines[:self.cy] + [t[:self.cx],t[self.cx:]] + self.lines[self.cy+1:]
self.cVert(1)
self.cx = 0
self.TouchBuffer()
def InsertChar(self,char):
if self.IsLine(self.cy):
t = self.lines[self.cy]
t = t[:self.cx] + char + t[self.cx:]
self.SetTextLine(self.cy, t)
self.cHoriz(1)
self.TouchBuffer()
def JoinLines(self):
t1 = self.lines[self.cy]
t2 = self.lines[self.cy+1]
self.cx = len(t1)
self.lines = self.lines[:self.cy] + [t1 + t2] + self.lines[self.cy+2:]
self.TouchBuffer()
def DeleteChar(self,x,y,oldtext):
newtext = oldtext[:x] + oldtext[x+1:]
self.SetTextLine(y, newtext)
self.TouchBuffer()
def BackSpace(self, event):
t = self.GetTextLine(self.cy)
if self.cx>0:
self.DeleteChar(self.cx-1,self.cy,t)
self.cHoriz(-1)
self.TouchBuffer()
elif self.cx == 0:
if self.cy > 0:
self.cy -= 1
self.JoinLines()
self.TouchBuffer()
else:
wxBell()
def Delete(self, event):
t = self.GetTextLine(self.cy)
if self.cx<len(t):
self.DeleteChar(self.cx,self.cy,t)
self.TouchBuffer()
else:
if self.cy < len(self.lines) - 1:
self.JoinLines()
self.TouchBuffer()
def Escape(self, event):
self.SelectOff()
def TabKey(self, event):
numSpaces = self.SpacesPerTab - (self.cx % self.SpacesPerTab)
self.SingleLineInsert(' ' * numSpaces)
##----------- selection routines
def SelectUpdate(self):
self.SelectEnd = (self.cy, self.cx)
self.SelectNotify(self.Selecting, self.SelectBegin, self.SelectEnd)
self.UpdateView()
def NormalizedSelect(self):
(begin, end) = (self.SelectBegin, self.SelectEnd)
(bRow, bCol) = begin
(eRow, eCol) = end
if (bRow < eRow):
return (begin, end)
elif (eRow < bRow):
return (end, begin)
else:
if (bCol < eCol):
return (begin, end)
else:
return (end, begin)
def FindSelection(self):
if self.SelectEnd is None or self.SelectBegin is None:
wxBell()
return None
(begin, end) = self.NormalizedSelect()
(bRow, bCol) = begin
(eRow, eCol) = end
return (bRow, bCol, eRow, eCol)
def SelectOff(self):
self.SelectBegin = None
self.SelectEnd = None
self.Selecting = False
self.SelectNotify(False,None,None)
def CopySelection(self, event):
selection = self.FindSelection()
if selection is None:
return
(bRow, bCol, eRow, eCol) = selection
if bRow == eRow:
self.SingleLineCopy(bRow, bCol, eCol)
else:
self.MultipleLineCopy(bRow, bCol, eRow, eCol)
def OnCopySelection(self, event):
self.CopySelection(event)
self.SelectOff()
def CopyToClipboard(self, linesOfText):
do = wxTextDataObject()
do.SetText(os.linesep.join(linesOfText))
wxTheClipboard.Open()
wxTheClipboard.SetData(do)
wxTheClipboard.Close()
def SingleLineCopy(self, Row, bCol, eCol):
Line = self.GetTextLine(Row)
self.CopyToClipboard([Line[bCol:eCol]])
def MultipleLineCopy(self, bRow, bCol, eRow, eCol):
bLine = self.GetTextLine(bRow)[bCol:]
eLine = self.GetTextLine(eRow)[:eCol]
self.CopyToClipboard([bLine] + [l for l in self.lines[bRow + 1:eRow]] + [eLine])
def OnDeleteSelection(self, event):
selection = self.FindSelection()
if selection is None:
return
(bRow, bCol, eRow, eCol) = selection
if bRow == eRow:
self.SingleLineDelete(bRow, bCol, eCol)
else:
self.MultipleLineDelete(bRow, bCol, eRow, eCol)
self.TouchBuffer()
self.cy = bRow
self.cx = bCol
self.SelectOff()
self.UpdateView()
def SingleLineDelete(self, Row, bCol, eCol):
ModLine = self.GetTextLine(Row)
ModLine = ModLine[:bCol] + ModLine[eCol:]
self.SetTextLine(Row,ModLine)
def MultipleLineDelete(self, bRow, bCol, eRow, eCol):
bLine = self.GetTextLine(bRow)
eLine = self.GetTextLine(eRow)
ModLine = bLine[:bCol] + eLine[eCol:]
self.lines[bRow:eRow + 1] = [ModLine]
def OnPaste(self, event):
do = wxTextDataObject()
wxTheClipboard.Open()
success = wxTheClipboard.GetData(do)
wxTheClipboard.Close()
if success:
pastedLines = LineSplitter(do.GetText())
else:
wxBell()
return
if len(pastedLines) == 0:
wxBell()
return
elif len(pastedLines) == 1:
self.SingleLineInsert(pastedLines[0])
else:
self.MultipleLinePaste(pastedLines)
def SingleLineInsert(self, newText):
ModLine = self.GetTextLine(self.cy)
ModLine = ModLine[:self.cx] + newText + ModLine[self.cx:]
self.SetTextLine(self.cy, ModLine)
self.cHoriz(len(newText))
self.TouchBuffer()
self.UpdateView()
def MultipleLinePaste(self, pastedLines):
FirstLine = LastLine = self.GetTextLine(self.cy)
FirstLine = FirstLine[:self.cx] + pastedLines[0]
LastLine = pastedLines[-1] + LastLine[self.cx:]
NewSlice = [FirstLine]
NewSlice += [l for l in pastedLines[1:-1]]
NewSlice += [LastLine]
self.lines[self.cy:self.cy + 1] = NewSlice
self.cy = self.cy + len(pastedLines)-1
self.cx = len(pastedLines[-1])
self.TouchBuffer()
self.UpdateView()
def OnCutSelection(self,event):
self.CopySelection(event)
self.OnDeleteSelection(event)
#-------------- Keyboard movement implementations
def MoveDown(self, event):
self.cVert(+1)
def MoveUp(self, event):
self.cVert(-1)
def MoveLeft(self, event):
if self.cx == 0:
if self.cy == 0:
wxBell()
else:
self.cVert(-1)
self.cx = self.CurrentLineLength()
else:
self.cx -= 1
def MoveRight(self, event):
linelen = self.CurrentLineLength()
if self.cx == linelen:
if self.cy == len(self.lines) - 1:
wxBell()
else:
self.cx = 0
self.cVert(1)
else:
self.cx += 1
def MovePageDown(self, event):
self.cVert(self.sh)
def MovePageUp(self, event):
self.cVert(-self.sh)
def MoveHome(self, event):
self.cx = 0
def MoveEnd(self, event):
self.cx = self.CurrentLineLength()
def MoveStartOfFile(self, event):
self.cy = 0
self.cx = 0
def MoveEndOfFile(self, event):
self.cy = len(self.lines) - 1
self.cx = self.CurrentLineLength()
#-------------- Key handler mapping tables
def SetMoveSpecialFuncs(self, action):
action[WXK_DOWN] = self.MoveDown
action[WXK_UP] = self.MoveUp
action[WXK_LEFT] = self.MoveLeft
action[WXK_RIGHT] = self.MoveRight
action[WXK_NEXT] = self.MovePageDown
action[WXK_PRIOR] = self.MovePageUp
action[WXK_HOME] = self.MoveHome
action[WXK_END] = self.MoveEnd
def SetMoveSpecialControlFuncs(self, action):
action[WXK_HOME] = self.MoveStartOfFile
action[WXK_END] = self.MoveEndOfFile
def SetAltFuncs(self, action):
# subclass implements
pass
def SetControlFuncs(self, action):
action['c'] = self.OnCopySelection
action['d'] = self.OnDeleteSelection
action['v'] = self.OnPaste
action['x'] = self.OnCutSelection
def SetSpecialControlFuncs(self, action):
action[WXK_INSERT] = self.OnCopySelection
def SetShiftFuncs(self, action):
action[WXK_DELETE] = self.OnCutSelection
action[WXK_INSERT] = self.OnPaste
def SetSpecialFuncs(self, action):
action[WXK_BACK] = self.BackSpace
action[WXK_DELETE] = self.Delete
action[WXK_RETURN] = self.BreakLine
action[WXK_ESCAPE] = self.Escape
action[WXK_TAB] = self.TabKey
##-------------- Logic for key handlers
def Move(self, keySettingFunction, key, event):
action = {}
keySettingFunction(action)
if not action.has_key(key):
return False
if event.ShiftDown():
if not self.Selecting:
self.Selecting = True
self.SelectBegin = (self.cy, self.cx)
action[key](event)
self.SelectEnd = (self.cy, self.cx)
else:
action[key](event)
if self.Selecting:
self.Selecting = False
self.SelectNotify(self.Selecting, self.SelectBegin, self.SelectEnd)
self.UpdateView()
return True
def MoveSpecialKey(self, event, key):
return self.Move(self.SetMoveSpecialFuncs, key, event)
def MoveSpecialControlKey(self, event, key):
if not event.ControlDown():
return False
return self.Move(self.SetMoveSpecialControlFuncs, key, event)
def Dispatch(self, keySettingFunction, key, event):
action = {}
keySettingFunction(action)
if action.has_key(key):
action[key](event)
self.UpdateView()
return True
return False
def ModifierKey(self, key, event, modifierKeyDown, MappingFunc):
if not modifierKeyDown:
return False
key = self.UnixKeyHack(key)
try:
key = chr(key)
except:
return False
if not self.Dispatch(MappingFunc, key, event):
wxBell()
return True
def ControlKey(self, event, key):
return self.ModifierKey(key, event, event.ControlDown(), self.SetControlFuncs)
def AltKey(self, event, key):
return self.ModifierKey(key, event, event.AltDown(), self.SetAltFuncs)
def SpecialControlKey(self, event, key):
if not event.ControlDown():
return False
if not self.Dispatch(self.SetSpecialControlFuncs, key, event):
wxBell()
return True
def ShiftKey(self, event, key):
if not event.ShiftDown():
return False
return self.Dispatch(self.SetShiftFuncs, key, event)
def NormalChar(self, event, key):
self.SelectOff()
# regular ascii
if not self.Dispatch(self.SetSpecialFuncs, key, event):
if (key>31) and (key<256):
self.InsertChar(chr(key))
else:
wxBell()
return
self.UpdateView()
self.AdjustScrollbars()
def OnChar(self, event):
key = event.KeyCode()
filters = [self.AltKey,
self.MoveSpecialControlKey,
self.ControlKey,
self.SpecialControlKey,
self.MoveSpecialKey,
self.ShiftKey,
self.NormalChar]
for filter in filters:
if filter(event,key):
break
return 0
#----------------------- Eliminate memory leaks
def OnDestroy(self, event):
self.mdc = None
self.odc = None
self.bgColor = None
self.fgColor = None
self.font = None
self.selectColor = None
self.scrollTimer = None
self.eofMarker = None
#-------------------- Abstract methods for subclasses
def OnClick(self):
pass
def SelectNotify(self, Selecting, SelectionBegin, SelectionEnd):
pass
__doc__ = wx.lib.editor.editor.__doc__
ForceBetween = wx.lib.editor.editor.ForceBetween
LineSplitter = wx.lib.editor.editor.LineSplitter
LineTrimmer = wx.lib.editor.editor.LineTrimmer
Scroller = wx.lib.editor.editor.Scroller
wxEditor = wx.lib.editor.editor.wxEditor

View File

@@ -1,27 +1,10 @@
## This file imports items from the wx package into the wxPython package for
## backwards compatibility. Some names will also have a 'wx' added on if
## that is how they used to be named in the old wxPython package.
# images converted with wxPython's img2py.py tool
from wxPython.wx import wxImageFromStream, wxBitmapFromImage
import cStringIO
##----------- Common Functions
def GetBitmap(ImageData):
return wxBitmapFromImage(GetImage(ImageData))
def GetImage(ImageData):
stream = cStringIO.StringIO(ImageData)
return wxImageFromStream(stream)
##----------- Image Data
EofImageData = \
'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x07\x00\x00\x00\x07\x08\x06\
\x00\x00\x00\xc4RW\xd3\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\x00\
\x00:IDATx\x9c]\x8e\xc1\r\x000\x08\x02\xc5\tn\xff)\xdd\xa0}\xd1`\xf9(\x9c\t\
\n(kf\x0e \xfbN\x90\xf3\xc1\x0c\xd2\xab\xaa\x16Huv\xa4\x00\xb5\x97\x1f\xac\
\x87\x1c\xe4\xe1\x05`2\x15\x9e\xc54\xca\xb4\x00\x00\x00\x00IEND\xaeB`\x82'
import wx.lib.editor.images
__doc__ = wx.lib.editor.images.__doc__
GetBitmap = wx.lib.editor.images.GetBitmap
GetImage = wx.lib.editor.images.GetImage

View File

@@ -1,42 +1,10 @@
True = 1
False = 0
## This file imports items from the wx package into the wxPython package for
## backwards compatibility. Some names will also have a 'wx' added on if
## that is how they used to be named in the old wxPython package.
def RestOfLine(sx, width, data, bool):
if len(data) == 0 and sx == 0:
return [('', bool)]
if sx >= len(data):
return []
return [(data[sx:sx+width], bool)]
def Selection(SelectBegin,SelectEnd, sx, width, line, data):
if SelectEnd is None or SelectBegin is None:
return RestOfLine(sx, width, data, False)
(bRow, bCol) = SelectBegin
(eRow, eCol) = SelectEnd
if (eRow < bRow):
(bRow, bCol) = SelectEnd
(eRow, eCol) = SelectBegin
if (line < bRow or eRow < line):
return RestOfLine(sx, width, data, False)
if (bRow < line and line < eRow):
return RestOfLine(sx, width, data, True)
if (bRow == eRow) and (eCol < bCol):
(bCol, eCol) = (eCol, bCol)
# selection either starts or ends on this line
end = min(sx+width, len(data))
if (bRow < line):
bCol = 0
if (line < eRow):
eCol = end
pieces = []
if (sx < bCol):
if bCol <= end:
pieces += [(data[sx:bCol], False)]
else:
return [(data[sx:end], False)]
pieces += [(data[max(bCol,sx):min(eCol,end)], True)]
if (eCol < end):
pieces += [(data[eCol:end], False)]
return pieces
import wx.lib.editor.selection
__doc__ = wx.lib.editor.selection.__doc__
RestOfLine = wx.lib.editor.selection.RestOfLine
Selection = wx.lib.editor.selection.Selection

View File

@@ -1,518 +1,13 @@
#---------------------------------------------------------------------------
# Name: wxPython.lib.evtmgr
# Purpose: An easier, more "Pythonic" and more OO method of registering
# handlers for wxWindows events using the Publish/Subscribe
# pattern.
#
# Author: Robb Shecter and Robin Dunn
#
# Created: 12-December-2002
# RCS-ID: $Id$
# Copyright: (c) 2003 by db-X Corporation
# Licence: wxWindows license
#---------------------------------------------------------------------------
## This file imports items from the wx package into the wxPython package for
## backwards compatibility. Some names will also have a 'wx' added on if
## that is how they used to be named in the old wxPython package.
"""
A module that allows multiple handlers to respond to single wxWindows
events. This allows true NxN Observer/Observable connections: One
event can be received by multiple handlers, and one handler can
receive multiple events.
import wx.lib.evtmgr
There are two ways to register event handlers. The first way is
similar to standard wxPython handler registration:
__doc__ = wx.lib.evtmgr.__doc__
from wxPython.lib.evtmgr import eventManager
eventManager.Register(handleEvents, EVT_BUTTON, win=frame, id=101)
There's also a new object-oriented way to register for events. This
invocation is equivalent to the one above, but does not require the
programmer to declare or track control ids or parent containers:
eventManager.Register(handleEvents, EVT_BUTTON, myButton)
This module is Python 2.1+ compatible.
"""
from wxPython import wx
import pubsub
#---------------------------------------------------------------------------
class EventManager:
"""
This is the main class in the module, and is the only class that
the application programmer needs to use. There is a pre-created
instance of this class called 'eventManager'. It should not be
necessary to create other instances.
"""
def __init__(self):
self.eventAdapterDict = {}
self.messageAdapterDict = {}
self.windowTopicLookup = {}
self.listenerTopicLookup = {}
self.__publisher = pubsub.Publisher()
self.EMPTY_LIST = []
def Register(self, listener, event, source=None, win=None, id=None):
"""
Registers a listener function (or any callable object) to
receive events of type event coming from the source window.
For example:
eventManager.Register(self.OnButton, EVT_BUTTON, theButton)
Alternatively, the specific window where the event is
delivered, and/or the ID of the event source can be specified.
For example:
eventManager.Register(self.OnButton, EVT_BUTTON, win=self, id=ID_BUTTON)
or
eventManager.Register(self.OnButton, EVT_BUTTON, theButton, self)
"""
# 1. Check if the 'event' is actually one of the multi-
# event macros.
if _macroInfo.isMultiEvent(event):
raise 'Cannot register the macro, '+`event`+'. Register instead the individual events.'
# Support a more OO API. This allows the GUI widget itself to
# be specified, and the id to be retrieved from the system,
# instead of kept track of explicitly by the programmer.
# (Being used to doing GUI work with Java, this seems to me to be
# the natural way of doing things.)
if source is not None:
id = source.GetId()
if win is None:
# Some widgets do not function as their own windows.
win = self._determineWindow(source)
topic = (event, win, id)
# Create an adapter from the PS system back to wxEvents, and
# possibly one from wxEvents:
if not self.__haveMessageAdapter(listener, topic):
messageAdapter = MessageAdapter(eventHandler=listener, topicPattern=topic)
try:
self.messageAdapterDict[topic][listener] = messageAdapter
except KeyError:
self.messageAdapterDict[topic] = {}
self.messageAdapterDict[topic][listener] = messageAdapter
if not self.eventAdapterDict.has_key(topic):
self.eventAdapterDict[topic] = EventAdapter(event, win, id)
else:
# Throwing away a duplicate request
pass
# For time efficiency when deregistering by window:
try:
self.windowTopicLookup[win].append(topic)
except KeyError:
self.windowTopicLookup[win] = []
self.windowTopicLookup[win].append(topic)
# For time efficiency when deregistering by listener:
try:
self.listenerTopicLookup[listener].append(topic)
except KeyError:
self.listenerTopicLookup[listener] = []
self.listenerTopicLookup[listener].append(topic)
# See if the source understands the listeningFor protocol.
# This is a bit of a test I'm working on - it allows classes
# to know when their events are being listened to. I use
# it to enable chaining events from contained windows only
# when needed.
if source is not None:
try:
# Let the source know that we're listening for this
# event.
source.listeningFor(event)
except AttributeError:
pass
# Some aliases for Register, just for kicks
Bind = Register
Subscribe = Register
def DeregisterWindow(self, win):
"""
Deregister all events coming from the given window.
"""
win = self._determineWindow(win)
topics = self.__getTopics(win)
if topics:
for aTopic in topics:
self.__deregisterTopic(aTopic)
del self.windowTopicLookup[win]
def DeregisterListener(self, listener):
"""
Deregister all event notifications for the given listener.
"""
try:
topicList = self.listenerTopicLookup[listener]
except KeyError:
return
for topic in topicList:
topicDict = self.messageAdapterDict[topic]
if topicDict.has_key(listener):
topicDict[listener].Destroy()
del topicDict[listener]
if len(topicDict) == 0:
self.eventAdapterDict[topic].Destroy()
del self.eventAdapterDict[topic]
del self.messageAdapterDict[topic]
del self.listenerTopicLookup[listener]
def GetStats(self):
"""
Return a dictionary with data about my state.
"""
stats = {}
stats['Adapters: Message'] = reduce(lambda x,y: x+y, [0] + map(len, self.messageAdapterDict.values()))
stats['Adapters: Event'] = len(self.eventAdapterDict)
stats['Topics: Total'] = len(self.__getTopics())
stats['Topics: Dead'] = len(self.GetDeadTopics())
return stats
def DeregisterDeadTopics(self):
"""
Deregister any entries relating to dead
wxPython objects. Not sure if this is an
important issue; 1) My app code always de-registers
listeners it doesn't need. 2) I don't think
that lingering references to these dead objects
is a problem.
"""
for topic in self.GetDeadTopics():
self.__deregisterTopic(topic)
def GetDeadTopics(self):
"""
Return a list of topics relating to dead wxPython
objects.
"""
return filter(self.__isDeadTopic, self.__getTopics())
def __winString(self, aWin):
"""
A string rep of a window for debugging
"""
try:
name = aWin.GetClassName()
i = id(aWin)
return '%s #%d' % (name, i)
except wx.wxPyDeadObjectError:
return '(dead wxObject)'
def __topicString(self, aTopic):
"""
A string rep of a topic for debugging
"""
return '[%-26s %s]' % (aTopic[0].__name__, self.winString(aTopic[1]))
def __listenerString(self, aListener):
"""
A string rep of a listener for debugging
"""
try:
return aListener.im_class.__name__ + '.' + aListener.__name__
except:
return 'Function ' + aListener.__name__
def __deregisterTopic(self, aTopic):
try:
messageAdapterList = self.messageAdapterDict[aTopic].values()
except KeyError:
# This topic isn't valid. Probably because it was deleted
# by listener.
return
for messageAdapter in messageAdapterList:
messageAdapter.Destroy()
self.eventAdapterDict[aTopic].Destroy()
del self.messageAdapterDict[aTopic]
del self.eventAdapterDict[aTopic]
def __getTopics(self, win=None):
if win is None:
return self.messageAdapterDict.keys()
if win is not None:
try:
return self.windowTopicLookup[win]
except KeyError:
return self.EMPTY_LIST
def __isDeadWxObject(self, anObject):
return isinstance(anObject, wx._wxPyDeadObject)
def __isDeadTopic(self, aTopic):
return self.__isDeadWxObject(aTopic[1])
def __haveMessageAdapter(self, eventHandler, topicPattern):
"""
Return True if there's already a message adapter
with these specs.
"""
try:
return self.messageAdapterDict[topicPattern].has_key(eventHandler)
except KeyError:
return 0
def _determineWindow(self, aComponent):
"""
Return the window that corresponds to this component.
A window is something that supports the Connect protocol.
Most things registered with the event manager are a window,
but there are apparently some exceptions. If more are
discovered, the implementation can be changed to a dictionary
lookup along the lines of class : function-to-get-window.
"""
if isinstance(aComponent, wx.wxMenuItem):
return aComponent.GetMenu()
else:
return aComponent
#---------------------------------------------------------------------------
# From here down is implementaion and support classes, although you may
# find some of them useful in other contexts.
#---------------------------------------------------------------------------
class EventMacroInfo:
"""
A class that provides information about event macros.
"""
def __init__(self):
self.lookupTable = {}
def getEventTypes(self, eventMacro):
"""
Return the list of event types that the given
macro corresponds to.
"""
try:
return self.lookupTable[eventMacro]
except KeyError:
win = FakeWindow()
try:
eventMacro(win, None, None)
except TypeError:
eventMacro(win, None)
self.lookupTable[eventMacro] = win.eventTypes
return win.eventTypes
def eventIsA(self, event, macroList):
"""
Return True if the event is one of the given
macros.
"""
eventType = event.GetEventType()
for macro in macroList:
if eventType in self.getEventTypes(macro):
return 1
return 0
def macroIsA(self, macro, macroList):
"""
Return True if the macro is in the macroList.
The added value of this method is that it takes
multi-events into account. The macroList parameter
will be coerced into a sequence if needed.
"""
if callable(macroList):
macroList = (macroList,)
testList = self.getEventTypes(macro)
eventList = []
for m in macroList:
eventList.extend(self.getEventTypes(m))
# Return True if every element in testList is in eventList
for element in testList:
if element not in eventList:
return 0
return 1
def isMultiEvent(self, macro):
"""
Return True if the given macro actually causes
multiple events to be registered.
"""
return len(self.getEventTypes(macro)) > 1
#---------------------------------------------------------------------------
class FakeWindow:
"""
Used internally by the EventMacroInfo class. The FakeWindow is
the most important component of the macro-info utility: it
implements the Connect() protocol of wxWindow, but instead of
registering for events, it keeps track of what parameters were
passed to it.
"""
def __init__(self):
self.eventTypes = []
def Connect(self, id1, id2, eventType, handlerFunction):
self.eventTypes.append(eventType)
#---------------------------------------------------------------------------
class EventAdapter:
"""
A class that adapts incoming wxWindows events to
Publish/Subscribe messages.
In other words, this is the object that's seen by the
wxWindows system. Only one of these registers for any
particular wxWindows event. It then relays it into the
PS system, which lets many listeners respond.
"""
def __init__(self, func, win, id):
"""
Instantiate a new adapter. Pre-compute my Publish/Subscribe
topic, which is constant, and register with wxWindows.
"""
self.publisher = pubsub.Publisher()
self.topic = ((func, win, id),)
self.id = id
self.win = win
self.eventType = _macroInfo.getEventTypes(func)[0]
# Register myself with the wxWindows event system
try:
func(win, id, self.handleEvent)
self.callStyle = 3
except TypeError:
func(win, self.handleEvent)
self.callStyle = 2
def disconnect(self):
if self.callStyle == 3:
return self.win.Disconnect(self.id, -1, self.eventType)
else:
return self.win.Disconnect(-1, -1, self.eventType)
def handleEvent(self, event):
"""
In response to a wxWindows event, send a PS message
"""
self.publisher.sendMessage(topic=self.topic, data=event)
def Destroy(self):
try:
if not self.disconnect():
print 'disconnect failed'
except wx.wxPyDeadObjectError:
print 'disconnect failed: dead object' ##????
#---------------------------------------------------------------------------
class MessageAdapter:
"""
A class that adapts incoming Publish/Subscribe messages
to wxWindows event calls.
This class works opposite the EventAdapter, and
retrieves the information an EventAdapter has sent in a message.
Strictly speaking, this class is not required: Event listeners
could pull the original wxEvent object out of the PS Message
themselves.
However, by pairing an instance of this class with each wxEvent
handler, the handlers can use the standard API: they receive an
event as a parameter.
"""
def __init__(self, eventHandler, topicPattern):
"""
Instantiate a new MessageAdapter that send wxEvents to the
given eventHandler.
"""
self.eventHandler = eventHandler
pubsub.Publisher().subscribe(listener=self.deliverEvent, topic=(topicPattern,))
def deliverEvent(self, message):
event = message.data # Extract the wxEvent
self.eventHandler(event) # Perform the call as wxWindows would
def Destroy(self):
pubsub.Publisher().unsubscribe(listener=self.deliverEvent)
#---------------------------------------------------------------------------
# Create globals
_macroInfo = EventMacroInfo()
# For now a singleton is not enforced. Should it be or can we trust
# the programmers?
eventManager = EventManager()
#---------------------------------------------------------------------------
# simple test code
if __name__ == '__main__':
from wxPython.wx import wxPySimpleApp, wxFrame, wxToggleButton, wxBoxSizer, wxHORIZONTAL, EVT_MOTION, EVT_LEFT_DOWN, EVT_TOGGLEBUTTON, wxALL
app = wxPySimpleApp()
frame = wxFrame(None, -1, 'Event Test', size=(300,300))
button = wxToggleButton(frame, -1, 'Listen for Mouse Events')
sizer = wxBoxSizer(wxHORIZONTAL)
sizer.Add(button, 0, 0 | wxALL, 10)
frame.SetAutoLayout(1)
frame.SetSizer(sizer)
#
# Demonstrate 1) register/deregister, 2) Multiple listeners receiving
# one event, and 3) Multiple events going to one listener.
#
def printEvent(event):
print 'Name:',event.GetClassName(),'Timestamp',event.GetTimestamp()
def enableFrameEvents(event):
# Turn the output of mouse events on and off
if event.IsChecked():
print '\nEnabling mouse events...'
eventManager.Register(printEvent, EVT_MOTION, frame)
eventManager.Register(printEvent, EVT_LEFT_DOWN, frame)
else:
print '\nDisabling mouse events...'
eventManager.DeregisterWindow(frame)
# Send togglebutton events to both the on/off code as well
# as the function that prints to stdout.
eventManager.Register(printEvent, EVT_TOGGLEBUTTON, button)
eventManager.Register(enableFrameEvents, EVT_TOGGLEBUTTON, button)
frame.CenterOnScreen()
frame.Show(1)
app.MainLoop()
EventAdapter = wx.lib.evtmgr.EventAdapter
EventMacroInfo = wx.lib.evtmgr.EventMacroInfo
EventManager = wx.lib.evtmgr.EventManager
FakeWindow = wx.lib.evtmgr.FakeWindow
MessageAdapter = wx.lib.evtmgr.MessageAdapter

View File

@@ -1,410 +1,24 @@
"""<font weight="bold" size="16">FancyText</font> -- <font style="italic" size="16">methods for rendering XML specified text</font>
<font family="swiss" size="12">
This module exports four main methods::
<font family="fixed" style="slant">
def GetExtent(str, dc=None, enclose=True)
def GetFullExtent(str, dc=None, enclose=True)
def RenderToBitmap(str, background=None, enclose=True)
def RenderToDC(str, dc, x, y, enclose=True)
</font>
In all cases, 'str' is an XML string. Note that start and end tags
are only required if *enclose* is set to False. In this case the
text should be wrapped in FancyText tags.
## This file imports items from the wx package into the wxPython package for
## backwards compatibility. Some names will also have a 'wx' added on if
## that is how they used to be named in the old wxPython package.
In addition, the module exports one class::
<font family="fixed" style="slant">
class StaticFancyText(self, window, id, text, background, ...)
</font>
This class works similar to StaticText except it interprets its text
as FancyText.
The text can support<sup>superscripts</sup> and <sub>subscripts</sub>, text
in different <font size="20">sizes</font>, <font color="blue">colors</font>, <font style="italic">styles</font>, <font weight="bold">weights</font> and
<font family="script">families</font>. It also supports a limited set of symbols,
currently <times/>, <infinity/>, <angle/> as well as greek letters in both
upper case (<Alpha/><Beta/>...<Omega/>) and lower case (<alpha/><beta/>...<omega/>).
We can use doctest/guitest to display this string in all its marked up glory.
<font family="fixed">
>>> frame = wx.Frame(wx.NULL, -1, "FancyText demo", wx.DefaultPosition)
>>> sft = StaticFancyText(frame, -1, __doc__, wx.Brush("light grey", wx.SOLID))
>>> frame.SetClientSize(sft.GetSize())
>>> didit = frame.Show()
>>> from guitest import PauseTests; PauseTests()
</font></font>
The End"""
# Copyright 2001-2003 Timothy Hochberg
# Use as you see fit. No warantees, I cannot be help responsible, etc.
import copy
import math
import sys
import wx
import xml.parsers.expat
__all__ = "GetExtent", "GetFullExtent", "RenderToBitmap", "RenderToDC", "StaticFancyText"
if sys.platform == "win32":
_greekEncoding = str(wx.FONTENCODING_CP1253)
else:
_greekEncoding = str(wx.FONTENCODING_ISO8859_7)
_families = {"fixed" : wx.FIXED, "default" : wx.DEFAULT, "decorative" : wx.DECORATIVE, "roman" : wx.ROMAN,
"script" : wx.SCRIPT, "swiss" : wx.SWISS, "modern" : wx.MODERN}
_styles = {"normal" : wx.NORMAL, "slant" : wx.SLANT, "italic" : wx.ITALIC}
_weights = {"normal" : wx.NORMAL, "light" : wx.LIGHT, "bold" : wx.BOLD}
# 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.
_greek_letters = ("alpha", "beta", "gamma", "delta", "epsilon", "zeta",
"eta", "theta", "iota", "kappa", "lambda", "mu", "nu",
"xi", "omnikron", "pi", "rho", "altsigma", "sigma", "tau", "upsilon",
"phi", "chi", "psi", "omega")
def iround(number):
return int(round(number))
def iceil(number):
return int(math.ceil(number))
class Renderer:
"""Class for rendering XML marked up text.
See the module docstring for a description of the markup.
This class must be subclassed and the methods the methods that do
the drawing overridden for a particular output device.
"""
defaultSize = wx.NORMAL_FONT.GetPointSize()
defaultFamily = wx.DEFAULT
defaultStyle = wx.NORMAL
defaultWeight = wx.NORMAL
defaultEncoding = wx.Font_GetDefaultEncoding()
defaultColor = "black"
def __init__(self, dc=None, x=0, y=None):
if dc == None:
dc = wx.MemoryDC()
self.dc = dc
self.offsets = [0]
self.fonts = [{}]
self.width = self.height = 0
self.x = x
self.minY = self.maxY = self._y = y
def getY(self):
if self._y is None:
self.minY = self.maxY = self._y = self.dc.GetTextExtent("M")[1]
return self._y
def setY(self, value):
self._y = y
y = property(getY, setY)
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):
methname = "end_" + name
if hasattr(self, methname):
getattr(self, methname)()
elif hasattr(self, "start_" + name):
pass
else:
raise ValueError("XML tag '%s' not supported" % methname)
def characterData(self, data):
self.dc.SetFont(self.getCurrentFont())
for i, chunk in enumerate(data.split('\n')):
if i:
self.x = 0
self.y = self.mayY = self.maxY + self.dc.GetTextExtent("M")[1]
if chunk:
width, height, descent, extl = self.dc.GetFullTextExtent(chunk)
self.renderCharacterData(data, iround(self.x), iround(self.y + self.offsets[-1] - height + descent))
else:
width = height = descent = extl = 0
self.updateDims(width, height, descent, extl)
def updateDims(self, width, height, descent, externalLeading):
self.x += width
self.width = max(self.x, self.width)
self.minY = min(self.minY, self.y+self.offsets[-1]-height+descent)
self.maxY = max(self.maxY, self.y+self.offsets[-1]+descent)
self.height = self.maxY - self.minY
def start_FancyText(self, attrs):
pass
start_wxFancyText = start_FancyText # For backward compatibility
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":
value = int(value)
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 wx.TheFontList.FindOrCreateFont(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 wx.TheColourDatabase.FindColour(font.get("color", self.defaultColor))
def getCurrentPen(self):
return wx.ThePenList.FindOrCreatePen(self.getCurrentColor(), 1, wx.SOLID)
def renderCharacterData(self, data, x, y):
raise NotImplementedError()
def _addGreek():
alpha = 0xE1
Alpha = 0xC1
def end(self):
pass
for i, name in enumerate(_greek_letters):
def start(self, attrs, code=chr(alpha+i)):
self.start_font({"encoding" : _greekEncoding})
self.characterData(code)
self.end_font()
setattr(Renderer, "start_%s" % name, start)
setattr(Renderer, "end_%s" % name, end)
if name == "altsigma":
continue # There is no capital for altsigma
def start(self, attrs, code=chr(Alpha+i)):
self.start_font({"encoding" : _greekEncoding})
self.characterData(code)
self.end_font()
setattr(Renderer, "start_%s" % name.capitalize(), start)
setattr(Renderer, "end_%s" % name.capitalize(), end)
_addGreek()
class SizeRenderer(Renderer):
"""Processes text as if rendering it, but just computes the size."""
def __init__(self, dc=None):
Renderer.__init__(self, dc, 0, 0)
def renderCharacterData(self, data, x, y):
pass
def start_angle(self, attrs):
self.characterData("M")
def start_infinity(self, attrs):
width, height = self.dc.GetTextExtent("M")
width = max(width, 10)
height = max(height, width / 2)
self.updateDims(width, height, 0, 0)
def start_times(self, attrs):
self.characterData("M")
def start_in(self, attrs):
self.characterData("M")
def start_times(self, attrs):
self.characterData("M")
class DCRenderer(Renderer):
"""Renders text to a wxPython device context DC."""
def renderCharacterData(self, data, x, y):
self.dc.SetTextForeground(self.getCurrentColor())
self.dc.DrawText(data, x, y)
def start_angle(self, attrs):
self.dc.SetFont(self.getCurrentFont())
self.dc.SetPen(self.getCurrentPen())
width, height, descent, leading = self.dc.GetFullTextExtent("M")
y = self.y + self.offsets[-1]
self.dc.DrawLine(iround(self.x), iround(y),iround( self.x+width), iround(y))
self.dc.DrawLine(iround(self.x), iround(y), iround(self.x+width), iround(y-width))
self.updateDims(width, height, descent, leading)
def start_infinity(self, attrs):
self.dc.SetFont(self.getCurrentFont())
self.dc.SetPen(self.getCurrentPen())
width, height, descent, leading = self.dc.GetFullTextExtent("M")
width = max(width, 10)
height = max(height, width / 2)
self.dc.SetPen(wx.Pen(self.getCurrentColor(), max(1, width/10)))
self.dc.SetBrush(wx.TRANSPARENT_BRUSH)
y = self.y + self.offsets[-1]
r = iround( 0.95 * width / 4)
xc = (2*self.x + width) / 2
yc = iround(y-1.5*r)
self.dc.DrawCircle(xc - r, yc, r)
self.dc.DrawCircle(xc + r, yc, r)
self.updateDims(width, height, 0, 0)
def start_times(self, attrs):
self.dc.SetFont(self.getCurrentFont())
self.dc.SetPen(self.getCurrentPen())
width, height, descent, leading = self.dc.GetFullTextExtent("M")
y = self.y + self.offsets[-1]
width *= 0.8
width = iround(width+.5)
self.dc.SetPen(wx.Pen(self.getCurrentColor(), 1))
self.dc.DrawLine(iround(self.x), iround(y-width), iround(self.x+width-1), iround(y-1))
self.dc.DrawLine(iround(self.x), iround(y-2), iround(self.x+width-1), iround(y-width-1))
self.updateDims(width, height, 0, 0)
def RenderToRenderer(str, renderer, enclose=True):
try:
if enclose:
str = '<?xml version="1.0"?><FancyText>%s</FancyText>' % 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)
except xml.parsers.expat.error, err:
raise ValueError('error parsing text text "%s": %s' % (str, err))
# Public interface
def GetExtent(str, dc=None, enclose=True):
"Return the extent of str"
renderer = SizeRenderer(dc)
RenderToRenderer(str, renderer, enclose)
return iceil(renderer.width), iceil(renderer.height) # XXX round up
def GetFullExtent(str, dc=None, enclose=True):
renderer = SizeRenderer(dc)
RenderToRenderer(str, renderer, enclose)
return iceil(renderer.width), iceil(renderer.height), -iceil(renderer.minY) # XXX round up
def RenderToBitmap(str, background=None, enclose=1):
"Return str rendered on a minumum size bitmap"
dc = wx.MemoryDC()
width, height, dy = GetFullExtent(str, dc, enclose)
bmp = wx.EmptyBitmap(width, height)
dc.SelectObject(bmp)
if background is None:
dc.SetBackground(wx.WHITE_BRUSH)
else:
dc.SetBackground(background)
dc.Clear()
renderer = DCRenderer(dc, y=dy)
dc.BeginDrawing()
RenderToRenderer(str, renderer, enclose)
dc.EndDrawing()
dc.SelectObject(wx.NullBitmap)
if background is None:
img = wx.ImageFromBitmap(bmp)
bg = dc.GetBackground().GetColour()
img.SetMaskColour(bg.Red(), bg.Green(), bg.Blue())
bmp = img.ConvertToBitmap()
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)
class StaticFancyText(wx.StaticBitmap):
def __init__(self, window, id, text, *args, **kargs):
args = list(args)
kargs.setdefault('name', 'staticFancyText')
if 'background' in kargs:
background = kargs.pop('background')
elif args:
background = args.pop(0)
else:
background = wx.Brush(window.GetBackgroundColour(), wx.SOLID)
bmp = RenderToBitmap(text, background)
wx.StaticBitmap.__init__(self, window, id, bmp, *args, **kargs)
# Old names for backward compatibiliry
getExtent = GetExtent
renderToBitmap = RenderToBitmap
renderToDC = RenderToDC
# Test Driver
def test():
app = wx.PyApp()
box = wx.BoxSizer(wx.VERTICAL)
frame = wx.Frame(wx.NULL, -1, "FancyText demo", wx.DefaultPosition)
frame.SetBackgroundColour("light grey")
sft = StaticFancyText(frame, -1, __doc__)
box.Add(sft, 1, wx.EXPAND)
frame.SetSizer(box)
frame.SetAutoLayout(True)
box.Fit(frame)
box.SetSizeHints(frame)
frame.Show()
app.MainLoop()
if __name__ == "__main__":
test()
import wx.lib.fancytext
__doc__ = wx.lib.fancytext.__doc__
DCRenderer = wx.lib.fancytext.DCRenderer
GetExtent = wx.lib.fancytext.GetExtent
GetFullExtent = wx.lib.fancytext.GetFullExtent
RenderToBitmap = wx.lib.fancytext.RenderToBitmap
RenderToDC = wx.lib.fancytext.RenderToDC
RenderToRenderer = wx.lib.fancytext.RenderToRenderer
Renderer = wx.lib.fancytext.Renderer
SizeRenderer = wx.lib.fancytext.SizeRenderer
StaticFancyText = wx.lib.fancytext.StaticFancyText
_addGreek = wx.lib.fancytext._addGreek
getExtent = wx.lib.fancytext.getExtent
iceil = wx.lib.fancytext.iceil
iround = wx.lib.fancytext.iround
renderToBitmap = wx.lib.fancytext.renderToBitmap
renderToDC = wx.lib.fancytext.renderToDC
test = wx.lib.fancytext.test

View File

@@ -1,447 +1,11 @@
#----------------------------------------------------------------------
# Name: wxPython.lib.filebrowsebutton
# Purpose: Composite controls that provide a Browse button next to
# either a wxTextCtrl or a wxComboBox. The Browse button
# launches a wxFileDialog and loads the result into the
# other control.
#
# Author: Mike Fletcher
#
# RCS-ID: $Id$
# Copyright: (c) 2000 by Total Control Software
# Licence: wxWindows license
#----------------------------------------------------------------------
from wxPython.wx import *
import os, types
#----------------------------------------------------------------------
class FileBrowseButton(wxPanel):
""" A control to allow the user to type in a filename
or browse with the standard file dialog to select file
__init__ (
parent, id, pos, size -- passed directly to wxPanel initialisation
style = wxTAB_TRAVERSAL -- passed directly to wxPanel initialisation
labelText -- Text for label to left of text field
buttonText -- Text for button which launches the file dialog
toolTip -- Help text
dialogTitle -- Title used in file dialog
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
)
GetValue() -- retrieve current value of text control
SetValue(string) -- set current value of text control
label -- pointer to internal label widget
textControl -- pointer to internal text control
browseButton -- pointer to button
"""
def __init__ (self, parent, id= -1,
pos = wxDefaultPosition, size = wxDefaultSize,
style = wxTAB_TRAVERSAL,
labelText= "File Entry:",
buttonText= "Browse",
toolTip= "Type filename or click browse to choose file",
# following are the values for a file dialog box
dialogTitle = "Choose a file",
startDirectory = ".",
initialValue = "",
fileMask = "*.*",
fileMode = wxOPEN,
# callback for when value changes (optional)
changeCallback= lambda x:x
):
# store variables
self.labelText = labelText
self.buttonText = buttonText
self.toolTip = toolTip
self.dialogTitle = dialogTitle
self.startDirectory = startDirectory
self.initialValue = initialValue
self.fileMask = fileMask
self.fileMode = fileMode
self.changeCallback = changeCallback
self.callCallback = True
# get background to match it
try:
self._bc = parent.GetBackgroundColour()
except:
pass
# create the dialog
self.createDialog(parent, id, pos, size, style )
# Setting a value causes the changeCallback to be called.
# In this case that would be before the return of the
# constructor. Not good. So a default value on
# SetValue is used to disable the callback
self.SetValue( initialValue, 0)
def createDialog( self, parent, id, pos, size, style ):
"""Setup the graphic representation of the dialog"""
wxPanel.__init__ (self, parent, id, pos, size, style)
# try to set the background colour
try:
self.SetBackgroundColour(self._bc)
except:
pass
box = wxBoxSizer(wxHORIZONTAL)
self.label = self.createLabel( )
box.Add( self.label, 0, wxCENTER )
self.textControl = self.createTextControl()
box.Add( self.textControl, 1, wxLEFT|wxCENTER, 5)
self.browseButton = self.createBrowseButton()
box.Add( self.browseButton, 0, wxLEFT|wxCENTER, 5)
# add a border around the whole thing and resize the panel to fit
outsidebox = wxBoxSizer(wxVERTICAL)
outsidebox.Add(box, 1, wxEXPAND|wxALL, 3)
outsidebox.Fit(self)
self.SetAutoLayout(True)
self.SetSizer( outsidebox )
self.Layout()
if type( size ) == types.TupleType:
size = apply( wxSize, size)
self.SetDimensions(-1, -1, size.width, size.height, wxSIZE_USE_EXISTING)
# if size.width != -1 or size.height != -1:
# self.SetSize(size)
def SetBackgroundColour(self,color):
wxPanel.SetBackgroundColour(self,color)
self.label.SetBackgroundColour(color)
def createLabel( self ):
"""Create the label/caption"""
label = wxStaticText(self, -1, self.labelText, style =wxALIGN_RIGHT )
font = label.GetFont()
w, h, d, e = self.GetFullTextExtent(self.labelText, font)
label.SetSize(wxSize(w+5, h))
return label
def createTextControl( self):
"""Create the text control"""
ID = wxNewId()
textControl = wxTextCtrl(self, ID)
textControl.SetToolTipString( self.toolTip )
if self.changeCallback:
EVT_TEXT(textControl, ID, self.OnChanged)
EVT_COMBOBOX(textControl, ID, self.OnChanged)
return textControl
def OnChanged(self, evt):
if self.callCallback and self.changeCallback:
self.changeCallback(evt)
def createBrowseButton( self):
"""Create the browse-button control"""
ID = wxNewId()
button =wxButton(self, ID, self.buttonText)
button.SetToolTipString( self.toolTip )
EVT_BUTTON(button, ID, self.OnBrowse)
return button
def OnBrowse (self, event = None):
""" Going to browse for file... """
current = self.GetValue()
directory = os.path.split(current)
if os.path.isdir( current):
directory = current
current = ''
elif directory and os.path.isdir( directory[0] ):
current = directory[1]
directory = directory [0]
else:
directory = self.startDirectory
dlg = wxFileDialog(self, self.dialogTitle, directory, current, self.fileMask, self.fileMode)
if dlg.ShowModal() == wxID_OK:
self.SetValue(dlg.GetPath())
dlg.Destroy()
def GetValue (self):
""" Convenient access to text control value """
return self.textControl.GetValue()
def SetValue (self, value, callBack=1):
""" Convenient setting of text control value """
save = self.callCallback
self.callCallback = callBack
self.textControl.SetValue(value)
self.callCallback = save
def Enable (self, value):
""" Convenient enabling/disabling of entire control """
self.label.Enable (value)
self.textControl.Enable (value)
return self.browseButton.Enable (value)
def GetLabel( self ):
""" Retrieve the label's current text """
return self.label.GetLabel()
def SetLabel( self, value ):
""" Set the label's current text """
rvalue = self.label.SetLabel( value )
self.Refresh( True )
return rvalue
class FileBrowseButtonWithHistory( FileBrowseButton ):
""" with following additions:
__init__(..., history=None)
history -- optional list of paths for initial history drop-down
(must be passed by name, not a positional argument)
If history is callable it will must return a list used
for the history drop-down
changeCallback -- as for FileBrowseButton, but with a work-around
for win32 systems which don't appear to create EVT_COMBOBOX
events properly. There is a (slight) chance that this work-around
will cause some systems to create two events for each Combobox
selection. If you discover this condition, please report it!
As for a FileBrowseButton.__init__ otherwise.
GetHistoryControl()
Return reference to the control which implements interfaces
required for manipulating the history list. See GetHistoryControl
documentation for description of what that interface is.
GetHistory()
Return current history list
SetHistory( value=(), selectionIndex = None )
Set current history list, if selectionIndex is not None, select that index
"""
def __init__( self, *arguments, **namedarguments):
self.history = namedarguments.get( "history" )
if self.history:
del namedarguments["history"]
self.historyCallBack=None
if callable(self.history):
self.historyCallBack=self.history
self.history=None
apply( FileBrowseButton.__init__, ( self,)+arguments, namedarguments)
def createTextControl( self):
"""Create the text control"""
ID = wxNewId()
textControl = wxComboBox(self, ID, style = wxCB_DROPDOWN )
textControl.SetToolTipString( self.toolTip )
EVT_SET_FOCUS(textControl, self.OnSetFocus)
if self.changeCallback:
EVT_TEXT(textControl, ID, self.changeCallback)
EVT_COMBOBOX(textControl, ID, self.changeCallback)
if self.history:
history=self.history
self.history=None
self.SetHistory( history, control=textControl)
return textControl
def GetHistoryControl( self ):
"""Return a pointer to the control which provides (at least)
the following methods for manipulating the history list.:
Append( item ) -- add item
Clear() -- clear all items
Delete( index ) -- 0-based index to delete from list
SetSelection( index ) -- 0-based index to select in list
Semantics of the methods follow those for the wxComboBox control
"""
return self.textControl
def SetHistory( self, value=(), selectionIndex = None, control=None ):
"""Set the current history list"""
if control is None:
control = self.GetHistoryControl()
if self.history == value:
return
self.history = value
# Clear history values not the selected one.
tempValue=control.GetValue()
# clear previous values
control.Clear()
control.SetValue(tempValue)
# walk through, appending new values
for path in value:
control.Append( path )
if selectionIndex is not None:
control.SetSelection( selectionIndex )
def GetHistory( self ):
"""Return the current history list"""
if self.historyCallBack != None:
return self.historyCallBack()
else:
return list( self.history )
def OnSetFocus(self, event):
"""When the history scroll is selected, update the history"""
if self.historyCallBack != None:
self.SetHistory( self.historyCallBack(), control=self.textControl)
event.Skip()
if wxPlatform == "__WXMSW__":
def SetValue (self, value, callBack=1):
""" Convenient setting of text control value, works
around limitation of wxComboBox """
save = self.callCallback
self.callCallback = callBack
self.textControl.SetValue(value)
self.callCallback = save
# Hack to call an event handler
class LocalEvent:
def __init__(self, string):
self._string=string
def GetString(self):
return self._string
if callBack==1:
# The callback wasn't being called when SetValue was used ??
# So added this explicit call to it
self.changeCallback(LocalEvent(value))
class DirBrowseButton(FileBrowseButton):
def __init__(self, parent, id = -1,
pos = wxDefaultPosition, size = wxDefaultSize,
style = wxTAB_TRAVERSAL,
labelText = 'Select a directory:',
buttonText = 'Browse',
toolTip = 'Type directory name or browse to select',
dialogTitle = '',
startDirectory = '.',
changeCallback = None,
dialogClass = wxDirDialog):
FileBrowseButton.__init__(self, parent, id, pos, size, style,
labelText, buttonText, toolTip,
dialogTitle, startDirectory,
changeCallback = changeCallback)
#
self._dirDialog = dialogClass(self,
message = dialogTitle,
defaultPath = startDirectory)
#
def OnBrowse(self, ev = None):
dialog = self._dirDialog
if dialog.ShowModal() == wxID_OK:
self.SetValue(dialog.GetPath())
#
def __del__(self):
if self.__dict__.has_key('_dirDialog'):
self._dirDialog.Destroy()
#----------------------------------------------------------------------
if __name__ == "__main__":
#from skeletonbuilder import rulesfile
class SimpleCallback:
def __init__( self, tag ):
self.tag = tag
def __call__( self, event ):
print self.tag, event.GetString()
class DemoFrame( wxFrame ):
def __init__(self, parent):
wxFrame.__init__(self, parent, 2400, "File entry with browse", size=(500,260) )
EVT_CLOSE(self, self.OnCloseWindow)
panel = wxPanel (self,-1)
innerbox = wxBoxSizer(wxVERTICAL)
control = FileBrowseButton(
panel,
initialValue = "z:\\temp",
)
innerbox.Add( control, 0, wxEXPAND )
middlecontrol = FileBrowseButtonWithHistory(
panel,
labelText = "With History",
initialValue = "d:\\temp",
history = ["c:\\temp", "c:\\tmp", "r:\\temp","z:\\temp"],
changeCallback= SimpleCallback( "With History" ),
)
innerbox.Add( middlecontrol, 0, wxEXPAND )
middlecontrol = FileBrowseButtonWithHistory(
panel,
labelText = "History callback",
initialValue = "d:\\temp",
history = self.historyCallBack,
changeCallback= SimpleCallback( "History callback" ),
)
innerbox.Add( middlecontrol, 0, wxEXPAND )
self.bottomcontrol = control = FileBrowseButton(
panel,
labelText = "With Callback",
style = wxSUNKEN_BORDER|wxCLIP_CHILDREN ,
changeCallback= SimpleCallback( "With Callback" ),
)
innerbox.Add( control, 0, wxEXPAND)
self.bottommostcontrol = control = DirBrowseButton(
panel,
labelText = "Simple dir browse button",
style = wxSUNKEN_BORDER|wxCLIP_CHILDREN)
innerbox.Add( control, 0, wxEXPAND)
ID = wxNewId()
innerbox.Add( wxButton( panel, ID,"Change Label", ), 1, wxEXPAND)
EVT_BUTTON( self, ID, self.OnChangeLabel )
ID = wxNewId()
innerbox.Add( wxButton( panel, ID,"Change Value", ), 1, wxEXPAND)
EVT_BUTTON( self, ID, self.OnChangeValue )
panel.SetAutoLayout(True)
panel.SetSizer( innerbox )
self.history={"c:\\temp":1, "c:\\tmp":1, "r:\\temp":1,"z:\\temp":1}
def historyCallBack(self):
keys=self.history.keys()
keys.sort()
return keys
def OnFileNameChangedHistory (self, event):
self.history[event.GetString ()]=1
def OnCloseMe(self, event):
self.Close(True)
def OnChangeLabel( self, event ):
self.bottomcontrol.SetLabel( "Label Updated" )
def OnChangeValue( self, event ):
self.bottomcontrol.SetValue( "r:\\somewhere\\over\\the\\rainbow.htm" )
def OnCloseWindow(self, event):
self.Destroy()
class DemoApp(wxApp):
def OnInit(self):
wxImage_AddHandler(wxJPEGHandler())
wxImage_AddHandler(wxPNGHandler())
wxImage_AddHandler(wxGIFHandler())
frame = DemoFrame(NULL)
#frame = RulesPanel(NULL )
frame.Show(True)
self.SetTopWindow(frame)
return True
def test( ):
app = DemoApp(0)
app.MainLoop()
print 'Creating dialog'
test( )
## This file imports items from the wx package into the wxPython package for
## backwards compatibility. Some names will also have a 'wx' added on if
## that is how they used to be named in the old wxPython package.
import wx.lib.filebrowsebutton
__doc__ = wx.lib.filebrowsebutton.__doc__
DirBrowseButton = wx.lib.filebrowsebutton.DirBrowseButton
FileBrowseButton = wx.lib.filebrowsebutton.FileBrowseButton
FileBrowseButtonWithHistory = wx.lib.filebrowsebutton.FileBrowseButtonWithHistory

View File

@@ -1,283 +1,9 @@
#----------------------------------------------------------------------------
# Name: floatbar.py
# Purpose: Contains floating toolbar class
#
# Author: Bryn Keller
#
# Created: 10/4/99
#----------------------------------------------------------------------------
"""
NOTE: This module is *not* supported in any way. Use it however you
wish, but be warned that dealing with any consequences is
entirly up to you.
--Robin
"""
from wxPython.wx import *
if wxPlatform == '__WXGTK__':
#
# For wxGTK all we have to do is set the wxTB_DOCKABLE flag
#
class wxFloatBar(wxToolBar):
def __init__(self, parent, ID,
pos = wxDefaultPosition,
size = wxDefaultSize,
style = 0,
name = 'toolbar'):
wxToolBar.__init__(self, parent, ID, pos, size,
style|wxTB_DOCKABLE, name)
# these other methods just become no-ops
def SetFloatable(self, float):
pass
def IsFloating(self):
return 1
def GetTitle(self):
return ""
def SetTitle(self, title):
pass
else:
_DOCKTHRESHOLD = 25
class wxFloatBar(wxToolBar):
"""
wxToolBar subclass which can be dragged off its frame and later
replaced there. Drag on the toolbar to release it, close it like
a normal window to make it return to its original
position. Programmatically, call SetFloatable(True) and then
Float(True) to float, Float(False) to dock.
"""
def __init__(self,*_args,**_kwargs):
"""
In addition to the usual arguments, wxFloatBar accepts keyword
args of: title(string): the title that should appear on the
toolbar's frame when it is floating. floatable(bool): whether
user actions (i.e., dragging) can float the toolbar or not.
"""
args = (self,) + _args
apply(wxToolBar.__init__, args, _kwargs)
if _kwargs.has_key('floatable'):
self.floatable = _kwargs['floatable']
assert type(self.floatable) == type(0)
else:
self.floatable = 0
self.floating = 0
if _kwargs.has_key('title'):
self.title = _kwargs['title']
assert type(self.title) == type("")
else:
self.title = ""
EVT_MOUSE_EVENTS(self, self.OnMouse)
self.parentframe = wxPyTypeCast(args[1], 'wxFrame')
def IsFloatable(self):
return self.floatable
def SetFloatable(self, float):
self.floatable = float
#Find the size of a title bar.
if not hasattr(self, 'titleheight'):
test = wxMiniFrame(NULL, -1, "TEST")
test.SetClientSize(wxSize(0,0))
self.titleheight = test.GetSizeTuple()[1]
test.Destroy()
def IsFloating(self):
return self.floating
def Realize(self):
wxToolBar.Realize(self)
def GetTitle(self):
return self.title
def SetTitle(self, title):
print 'SetTitle', title
self.title = title
if self.IsFloating():
self.floatframe.SetTitle(self.title)
## def GetHome(self):
## """
## Returns the frame which this toolbar will return to when
## docked, or the parent if currently docked.
## """
## if hasattr(self, 'parentframe'):
## return self.parentframe
## else:
## return wxPyTypeCast(self.GetParent(), 'wxFrame')
## def SetHome(self, frame):
## """
## Called when docked, this will remove the toolbar from its
## current frame and attach it to another. If called when
## floating, it will dock to the frame specified when the toolbar
## window is closed.
## """
## if self.IsFloating():
## self.parentframe = frame
## self.floatframe.Reparent(frame)
## else:
## parent = wxPyTypeCast(self.GetParent(), 'wxFrame')
## self.Reparent(frame)
## parent.SetToolBar(None)
## size = parent.GetSize()
## parent.SetSize(wxSize(0,0))
## parent.SetSize(size)
## frame.SetToolBar(self)
## size = frame.GetSize()
## frame.SetSize(wxSize(0,0))
## frame.SetSize(size)
def Float(self, bool):
"Floats or docks the toolbar programmatically."
if bool:
self.parentframe = wxPyTypeCast(self.GetParent(), 'wxFrame')
print self.title
if self.title:
useStyle = wxDEFAULT_FRAME_STYLE
else:
useStyle = wxTHICK_FRAME
self.floatframe = wxMiniFrame(self.parentframe, -1, self.title,
style = useStyle)
self.Reparent(self.floatframe)
self.parentframe.SetToolBar(None)
self.floating = 1
psize = self.parentframe.GetSize()
self.parentframe.SetSize(wxSize(0,0))
self.parentframe.SetSize(psize)
self.floatframe.SetToolBar(self)
self.oldcolor = self.GetBackgroundColour()
w = psize.width
h = self.GetSize().height
if self.title:
h = h + self.titleheight
self.floatframe.SetSize(wxSize(w,h))
self.floatframe.SetClientSize(self.GetSize())
newpos = self.parentframe.GetPosition()
newpos.y = newpos.y + _DOCKTHRESHOLD * 2
self.floatframe.SetPosition(newpos)
self.floatframe.Show(True)
EVT_CLOSE(self.floatframe, self.OnDock)
#EVT_MOVE(self.floatframe, self.OnMove)
else:
self.Reparent(self.parentframe)
self.parentframe.SetToolBar(self)
self.floating = 0
self.floatframe.SetToolBar(None)
self.floatframe.Destroy()
size = self.parentframe.GetSize()
self.parentframe.SetSize(wxSize(0,0))
self.parentframe.SetSize(size)
self.SetBackgroundColour(self.oldcolor)
def OnDock(self, e):
self.Float(0)
if hasattr(self, 'oldpos'):
del self.oldpos
def OnMove(self, e):
homepos = self.parentframe.ClientToScreen(wxPoint(0,0))
floatpos = self.floatframe.GetPosition()
if (abs(homepos.x - floatpos.x) < _DOCKTHRESHOLD and
abs(homepos.y - floatpos.y) < _DOCKTHRESHOLD):
self.Float(0)
#homepos = self.parentframe.GetPositionTuple()
#homepos = homepos[0], homepos[1] + self.titleheight
#floatpos = self.floatframe.GetPositionTuple()
#if abs(homepos[0] - floatpos[0]) < 35 and abs(homepos[1] - floatpos[1]) < 35:
# self._SetFauxBarVisible(True)
#else:
# self._SetFauxBarVisible(False)
def OnMouse(self, e):
if not self.IsFloatable():
e.Skip()
return
if e.ButtonDClick(1) or e.ButtonDClick(2) or e.ButtonDClick(3) or e.ButtonDown() or e.ButtonUp():
e.Skip()
if e.ButtonDown():
self.CaptureMouse()
self.oldpos = (e.GetX(), e.GetY())
if e.Entering():
self.oldpos = (e.GetX(), e.GetY())
if e.ButtonUp():
self.ReleaseMouse()
if self.IsFloating():
homepos = self.parentframe.ClientToScreen(wxPoint(0,0))
floatpos = self.floatframe.GetPosition()
if (abs(homepos.x - floatpos.x) < _DOCKTHRESHOLD and
abs(homepos.y - floatpos.y) < _DOCKTHRESHOLD):
self.Float(0)
return
if e.Dragging():
if not self.IsFloating():
self.Float(True)
self.oldpos = (e.GetX(), e.GetY())
else:
if hasattr(self, 'oldpos'):
loc = self.floatframe.GetPosition()
pt = wxPoint(loc.x - (self.oldpos[0]-e.GetX()), loc.y - (self.oldpos[1]-e.GetY()))
self.floatframe.Move(pt)
def _SetFauxBarVisible(self, vis):
return
if vis:
if self.parentframe.GetToolBar() == None:
if not hasattr(self, 'nullbar'):
self.nullbar = wxToolBar(self.parentframe, -1)
print "Adding fauxbar."
self.nullbar.Reparent(self.parentframe)
print "Reparented."
self.parentframe.SetToolBar(self.nullbar)
print "Set toolbar"
col = wxNamedColour("GREY")
self.nullbar.SetBackgroundColour(col)
print "Set color"
size = self.parentframe.GetSize()
self.parentframe.SetSize(wxSize(0,0))
self.parentframe.SetSize(size)
print "Set size"
else:
print self.parentframe.GetToolBar()
else:
if self.parentframe.GetToolBar() != None:
print "Removing fauxbar"
self.nullbar.Reparent(self.floatframe)
self.parentframe.SetToolBar(None)
size = self.parentframe.GetSize()
self.parentframe.SetSize(wxSize(0,0))
self.parentframe.SetSize(size)
## This file imports items from the wx package into the wxPython package for
## backwards compatibility. Some names will also have a 'wx' added on if
## that is how they used to be named in the old wxPython package.
import wx.lib.floatbar
__doc__ = wx.lib.floatbar.__doc__
wxFloatBar = wx.lib.floatbar.wxFloatBar

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,10 @@
## This file imports items from the wx package into the wxPython package for
## backwards compatibility. Some names will also have a 'wx' added on if
## that is how they used to be named in the old wxPython package.
import wx.lib.foldmenu
__doc__ = wx.lib.foldmenu.__doc__
FoldOutMenu = wx.lib.foldmenu.FoldOutMenu
FoldOutWindow = wx.lib.foldmenu.FoldOutWindow

View File

@@ -1,419 +1,18 @@
#----------------------------------------------------------------------------
# Name: GridColMover.py
# Purpose: Grid Column Mover Extension
#
# Author: Gerrit van Dyk (email: gerritvd@decillion.net)
#
# Version 0.1
# Date: Nov 19, 2002
# RCS-ID: $Id$
# Licence: wxWindows license
#----------------------------------------------------------------------------
## This file imports items from the wx package into the wxPython package for
## backwards compatibility. Some names will also have a 'wx' added on if
## that is how they used to be named in the old wxPython package.
from wxPython.wx import *
from wxPython.grid import wxGridPtr
import wx.lib.gridmovers
#----------------------------------------------------------------------------
# event class and macors
__doc__ = wx.lib.gridmovers.__doc__
wxEVT_COMMAND_GRID_COL_MOVE = wxNewEventType()
wxEVT_COMMAND_GRID_ROW_MOVE = wxNewEventType()
def EVT_GRID_COL_MOVE(win, id, func):
win.Connect(id, -1, wxEVT_COMMAND_GRID_COL_MOVE, func)
def EVT_GRID_ROW_MOVE(win,id,func):
win.Connect(id, -1, wxEVT_COMMAND_GRID_ROW_MOVE, func)
class wxGridColMoveEvent(wxPyCommandEvent):
def __init__(self, id, dCol, bCol):
wxPyCommandEvent.__init__(self, id = id)
self.SetEventType(wxEVT_COMMAND_GRID_COL_MOVE)
self.moveColumn = dCol
self.beforeColumn = bCol
def GetMoveColumn(self):
return self.moveColumn
def GetBeforeColumn(self):
return self.beforeColumn
class wxGridRowMoveEvent(wxPyCommandEvent):
def __init__(self, id, dRow, bRow):
wxPyCommandEvent.__init__(self,id = id)
self.SetEventType(wxEVT_COMMAND_GRID_ROW_MOVE)
self.moveRow = dRow
self.beforeRow = bRow
def GetMoveRow(self):
return self.moveRow
def GetBeforeRow(self):
return self.beforeRow
#----------------------------------------------------------------------------
# graft new methods into the wxGridPtr class
def _ColToRect(self,col):
if self.GetNumberRows() > 0:
rect = self.CellToRect(0,col)
else:
rect = wxRect()
rect.height = self.GetColLabelSize()
rect.width = self.GetColSize(col)
for cCol in range(0,col):
rect.x += self.GetColSize(cCol)
rect.y = self.GetGridColLabelWindow().GetPosition()[1]
return rect
wxGridPtr.ColToRect = _ColToRect
def _RowToRect(self,row):
if self.GetNumberCols() > 0:
rect = self.CellToRect(row,0)
else:
rect = wxRect()
rect.width = self.GetRowLabelSize()
rect.height = self.GetRowSize(row)
for cRow in range(0,row):
rect.y += self.GetRowSize(cRow)
rect.x = self.GetGridRowLabelWindow().GetPosition()[0]
return rect
wxGridPtr.RowToRect = _RowToRect
#----------------------------------------------------------------------------
class ColDragWindow(wxWindow):
def __init__(self,parent,image,dragCol):
wxWindow.__init__(self,parent,wxSIMPLE_BORDER)
self.image = image
self.SetSize((self.image.GetWidth(),self.image.GetHeight()))
self.ux = parent.GetScrollPixelsPerUnit()[0]
self.moveColumn = dragCol
EVT_PAINT(self,self.OnPaint)
def DisplayAt(self,pos,y):
x = self.GetPositionTuple()[0]
if x == pos:
self.Refresh() # Need to display insertion point
else:
self.MoveXY(pos,y)
def GetMoveColumn(self):
return self.moveColumn
def _GetInsertionInfo(self):
parent = self.GetParent()
sx = parent.GetViewStart()[0] * self.ux
sx -= parent._rlSize
x = self.GetPositionTuple()[0]
w = self.GetSizeTuple()[0]
sCol = parent.XToCol(x + sx)
eCol = parent.XToCol(x + w + sx)
iPos = xPos = xCol = 99999
centerPos = x + sx + (w / 2)
for col in range(sCol,eCol + 1):
cx = parent.ColToRect(col)[0]
if abs(cx - centerPos) < iPos:
iPos = abs(cx - centerPos)
xCol = col
xPos = cx
if xCol < 0 or xCol > parent.GetNumberCols():
xCol = parent.GetNumberCols()
return (xPos - sx - x,xCol)
def GetInsertionColumn(self):
return self._GetInsertionInfo()[1]
def GetInsertionPos(self):
return self._GetInsertionInfo()[0]
def OnPaint(self,evt):
dc = wxPaintDC(self)
w,h = self.GetSize()
dc.DrawBitmap(self.image,0,0)
dc.SetPen(wxPen(wxBLACK,1,wxSOLID))
dc.SetBrush(wxTRANSPARENT_BRUSH)
dc.DrawRectangle(0,0,w,h)
iPos = self.GetInsertionPos()
dc.DrawLine(iPos,h - 10,iPos,h)
class RowDragWindow(wxWindow):
def __init__(self,parent,image,dragRow):
wxWindow.__init__(self,parent,wxSIMPLE_BORDER)
self.image = image
self.SetSize((self.image.GetWidth(),self.image.GetHeight()))
self.uy = parent.GetScrollPixelsPerUnit()[1]
self.moveRow = dragRow
EVT_PAINT(self,self.OnPaint)
def DisplayAt(self,x,pos):
y = self.GetPositionTuple()[1]
if y == pos:
self.Refresh() # Need to display insertion point
else:
self.MoveXY(x,pos)
def GetMoveRow(self):
return self.moveRow
def _GetInsertionInfo(self):
parent = self.GetParent()
sy = parent.GetViewStart()[1] * self.uy
sy -= parent._clSize
y = self.GetPositionTuple()[1]
h = self.GetSizeTuple()[1]
sRow = parent.YToRow(y + sy)
eRow = parent.YToRow(y + h + sy)
iPos = yPos = yRow = 99999
centerPos = y + sy + (h / 2)
for row in range(sRow,eRow + 1):
cy = parent.RowToRect(row)[1]
if abs(cy - centerPos) < iPos:
iPos = abs(cy - centerPos)
yRow = row
yPos = cy
if yRow < 0 or yRow > parent.GetNumberRows():
yRow = parent.GetNumberRows()
return (yPos - sy - y,yRow)
def GetInsertionRow(self):
return self._GetInsertionInfo()[1]
def GetInsertionPos(self):
return self._GetInsertionInfo()[0]
def OnPaint(self,evt):
dc = wxPaintDC(self)
w,h = self.GetSize()
dc.DrawBitmap(self.image,0,0)
dc.SetPen(wxPen(wxBLACK,1,wxSOLID))
dc.SetBrush(wxTRANSPARENT_BRUSH)
dc.DrawRectangle(0,0,w,h)
iPos = self.GetInsertionPos()
dc.DrawLine(w - 10,iPos,w,iPos)
#----------------------------------------------------------------------------
class wxGridColMover(wxEvtHandler):
def __init__(self,grid):
wxEvtHandler.__init__(self)
self.grid = grid
self.grid._rlSize = self.grid.GetRowLabelSize()
self.lwin = grid.GetGridColLabelWindow()
self.lwin.PushEventHandler(self)
self.colWin = None
self.ux = self.grid.GetScrollPixelsPerUnit()[0]
self.startX = -10
self.cellX = 0
self.didMove = False
self.isDragging = False
EVT_MOTION(self,self.OnMouseMove)
EVT_LEFT_DOWN(self,self.OnPress)
EVT_LEFT_UP(self,self.OnRelease)
def OnMouseMove(self,evt):
if self.isDragging:
if abs(self.startX - evt.m_x) >= 3:
self.didMove = True
sx,y = self.grid.GetViewStart()
w,h = self.lwin.GetClientSizeTuple()
x = sx * self.ux
if (evt.m_x + x) < x:
x = evt.m_x + x
elif evt.m_x > w:
x += evt.m_x - w
if x < 1: x = 0
else: x /= self.ux
if x != sx:
if wxPlatform == '__WXMSW__':
self.colWin.Show(False)
self.grid.Scroll(x,y)
x,y = self.lwin.ClientToScreenXY(evt.m_x,0)
x,y = self.grid.ScreenToClientXY(x,y)
if not self.colWin.IsShown():
self.colWin.Show(True)
px = x - self.cellX
if px < 0 + self.grid._rlSize: px = 0 + self.grid._rlSize
if px > w - self.colWin.GetSizeTuple()[0] + self.grid._rlSize:
px = w - self.colWin.GetSizeTuple()[0] + self.grid._rlSize
self.colWin.DisplayAt(px,y)
return
evt.Skip()
def OnPress(self,evt):
self.startX = evt.m_x
sx = self.grid.GetViewStart()[0] * self.ux
sx -= self.grid._rlSize
px,py = self.lwin.ClientToScreenXY(evt.m_x,evt.m_y)
px,py = self.grid.ScreenToClientXY(px,py)
if self.grid.XToEdgeOfCol(px + sx) != wxNOT_FOUND:
evt.Skip()
return
self.isDragging = True
self.didMove = False
col = self.grid.XToCol(px + sx)
rect = self.grid.ColToRect(col)
self.cellX = px + sx - rect.x
size = self.lwin.GetSizeTuple()
rect.y = 0
rect.x -= sx + self.grid._rlSize
rect.height = size[1]
colImg = self._CaptureImage(rect)
self.colWin = ColDragWindow(self.grid,colImg,col)
self.colWin.Show(False)
self.lwin.CaptureMouse()
def OnRelease(self,evt):
if self.isDragging:
self.lwin.ReleaseMouse()
self.colWin.Show(False)
self.isDragging = False
if not self.didMove:
px = self.lwin.ClientToScreenXY(self.startX,0)[0]
px = self.grid.ScreenToClientXY(px,0)[0]
sx = self.grid.GetViewStart()[0] * self.ux
sx -= self.grid._rlSize
col = self.grid.XToCol(px+sx)
if col != wxNOT_FOUND:
self.grid.SelectCol(col,evt.m_controlDown)
return
else:
bCol = self.colWin.GetInsertionColumn()
dCol = self.colWin.GetMoveColumn()
wxPostEvent(self,wxGridColMoveEvent(self.grid.GetId(),
dCol,bCol))
self.colWin.Destroy()
evt.Skip()
def _CaptureImage(self,rect):
bmp = wxEmptyBitmap(rect.width,rect.height)
memdc = wxMemoryDC()
memdc.SelectObject(bmp)
dc = wxWindowDC(self.lwin)
memdc.Blit(0,0,rect.width,rect.height,dc,rect.x,rect.y)
memdc.SelectObject(wxNullBitmap)
return bmp
class wxGridRowMover(wxEvtHandler):
def __init__(self,grid):
wxEvtHandler.__init__(self)
self.grid = grid
self.grid._clSize = self.grid.GetColLabelSize()
self.lwin = grid.GetGridRowLabelWindow()
self.lwin.PushEventHandler(self)
self.rowWin = None
self.uy = self.grid.GetScrollPixelsPerUnit()[1]
self.startY = -10
self.cellY = 0
self.didMove = False
self.isDragging = False
EVT_MOTION(self,self.OnMouseMove)
EVT_LEFT_DOWN(self,self.OnPress)
EVT_LEFT_UP(self,self.OnRelease)
def OnMouseMove(self,evt):
if self.isDragging:
if abs(self.startY - evt.m_y) >= 3:
self.didMove = True
x,sy = self.grid.GetViewStart()
w,h = self.lwin.GetClientSizeTuple()
y = sy * self.uy
if (evt.m_y + y) < y:
y = evt.m_y + y
elif evt.m_y > h:
y += evt.m_y - h
if y < 1: y = 0
else: y /= self.uy
if y != sy:
if wxPlatform == '__WXMSW__':
self.rowWin.Show(False)
self.grid.Scroll(x,y)
x,y = self.lwin.ClientToScreenXY(0,evt.m_y)
x,y = self.grid.ScreenToClientXY(x,y)
if not self.rowWin.IsShown():
self.rowWin.Show(True)
py = y - self.cellY
if py < 0 + self.grid._clSize: py = 0 + self.grid._clSize
if py > h - self.rowWin.GetSizeTuple()[1] + self.grid._clSize:
py = h - self.rowWin.GetSizeTuple()[1] + self.grid._clSize
self.rowWin.DisplayAt(x,py)
return
evt.Skip()
def OnPress(self,evt):
self.startY = evt.m_y
sy = self.grid.GetViewStart()[1] * self.uy
sy -= self.grid._clSize
px,py = self.lwin.ClientToScreenXY(evt.m_x,evt.m_y)
px,py = self.grid.ScreenToClientXY(px,py)
if self.grid.YToEdgeOfRow(py + sy) != wxNOT_FOUND:
evt.Skip()
return
self.isDragging = True
self.didMove = False
row = self.grid.YToRow(py + sy)
rect = self.grid.RowToRect(row)
self.cellY = py + sy - rect.y
size = self.lwin.GetSizeTuple()
rect.x = 0
rect.y -= sy + self.grid._clSize
rect.width = size[0]
rowImg = self._CaptureImage(rect)
self.rowWin = RowDragWindow(self.grid,rowImg,row)
self.rowWin.Show(False)
self.lwin.CaptureMouse()
def OnRelease(self,evt):
if self.isDragging:
self.lwin.ReleaseMouse()
self.rowWin.Show(False)
self.isDragging = False
if not self.didMove:
py = self.lwin.ClientToScreenXY(0,self.startY)[1]
py = self.grid.ScreenToClientXY(0,py)[1]
sy = self.grid.GetViewStart()[1] * self.uy
sy -= self.grid._clSize
row = self.grid.YToRow(py + sy)
if row != wxNOT_FOUND:
self.grid.SelectRow(row,evt.m_controlDown)
return
else:
bRow = self.rowWin.GetInsertionRow()
dRow = self.rowWin.GetMoveRow()
wxPostEvent(self,wxGridRowMoveEvent(self.grid.GetId(),
dRow,bRow))
self.rowWin.Destroy()
evt.Skip()
def _CaptureImage(self,rect):
bmp = wxEmptyBitmap(rect.width,rect.height)
memdc = wxMemoryDC()
memdc.SelectObject(bmp)
dc = wxWindowDC(self.lwin)
memdc.Blit(0,0,rect.width,rect.height,dc,rect.x,rect.y)
memdc.SelectObject(wxNullBitmap)
return bmp
#----------------------------------------------------------------------------
ColDragWindow = wx.lib.gridmovers.ColDragWindow
EVT_GRID_COL_MOVE = wx.lib.gridmovers.EVT_GRID_COL_MOVE
EVT_GRID_ROW_MOVE = wx.lib.gridmovers.EVT_GRID_ROW_MOVE
RowDragWindow = wx.lib.gridmovers.RowDragWindow
_ColToRect = wx.lib.gridmovers._ColToRect
_RowToRect = wx.lib.gridmovers._RowToRect
wxGridColMoveEvent = wx.lib.gridmovers.wxGridColMoveEvent
wxGridColMover = wx.lib.gridmovers.wxGridColMover
wxGridRowMoveEvent = wx.lib.gridmovers.wxGridRowMoveEvent
wxGridRowMover = wx.lib.gridmovers.wxGridRowMover

View File

@@ -1,267 +1,10 @@
#----------------------------------------------------------------------
# Name: wxPython.lib.grids
# Purpose: An example sizer derived from the C++ wxPySizer that
# sizes items in a fixed or flexible grid.
#
# Author: Robin Dunn
#
# Created: 21-Sept-1999
# RCS-ID: $Id$
# Copyright: (c) 1999 by Total Control Software
# Licence: wxWindows license
#----------------------------------------------------------------------
"""
In this module you will find wxGridSizer and wxFlexGridSizer. Please
note that these sizers have since been ported to C++ and those
versions are now exposed in the regular wxPython wrappers. However I
am also leaving them here in the library so they can serve as an
example of how to implement sizers in Python.
wxGridSizer: Sizes and positions items such that all rows are the same
height and all columns are the same width. You can specify a gap in
pixels to be used between the rows and/or the columns. When you
create the sizer you specify the number of rows or the number of
columns and then as you add items it figures out the other dimension
automatically. Like other sizers, items can be set to fill their
available space, or to be aligned on a side, in a corner, or in the
center of the space. When the sizer is resized, all the items are
resized the same amount so all rows and all columns remain the same
size.
wxFlexGridSizer: Derives from wxGridSizer and adds the ability for
particular rows and/or columns to be marked as growable. This means
that when the sizer changes size, the growable rows and colums are the
ones that stretch. The others remain at their initial size.
See the demo for a couple examples for how to use them.
"""
from wxPython.wx import *
import operator
#----------------------------------------------------------------------
class wxGridSizer(wxPySizer):
def __init__(self, rows=0, cols=0, hgap=0, vgap=0):
wxPySizer.__init__(self)
if rows == 0 and cols == 0:
raise ValueError, "rows and cols cannot both be zero"
self.rows = rows
self.cols = cols
self.hgap = hgap
self.vgap = vgap
def SetRows(self, rows):
if rows == 0 and self.cols == 0:
raise ValueError, "rows and cols cannot both be zero"
self.rows = rows
def SetColumns(self, cols):
if self.rows == 0 and cols == 0:
raise ValueError, "rows and cols cannot both be zero"
self.cols = cols
def GetRows(self):
return self.rows
def GetColumns(self):
return self.cols
def SetHgap(self, hgap):
self.hgap = hgap
def SetVgap(self, vgap):
self.vgap = vgap
def GetHgap(self, hgap):
return self.hgap
def GetVgap(self, vgap):
return self.vgap
#--------------------------------------------------
def CalcMin(self):
items = self.GetChildren()
nitems = len(items)
nrows = self.rows
ncols = self.cols
if ncols > 0:
nrows = (nitems + ncols-1) / ncols
else:
ncols = (nitems + nrows-1) / nrows
# Find the max width and height for any component.
w = 0
h = 0
for item in items:
size = item.CalcMin()
w = max(w, size.width)
h = max(h, size.height)
return wxSize(ncols * w + (ncols-1) * self.hgap,
nrows * h + (nrows-1) * self.vgap)
#--------------------------------------------------
def RecalcSizes(self):
items = self.GetChildren()
if not items:
return
nitems = len(items)
nrows = self.rows
ncols = self.cols
if ncols > 0:
nrows = (nitems + ncols-1) / ncols
else:
ncols = (nitems + nrows-1) / nrows
sz = self.GetSize()
pt = self.GetPosition()
w = (sz.width - (ncols - 1) * self.hgap) / ncols;
h = (sz.height - (nrows - 1) * self.vgap) / nrows;
x = pt.x
for c in range(ncols):
y = pt.y
for r in range(nrows):
i = r * ncols + c
if i < nitems:
self.SetItemBounds(items[i], x, y, w, h)
y = y + h + self.vgap
x = x + w + self.hgap
#--------------------------------------------------
def SetItemBounds(self, item, x, y, w, h):
# calculate the item's size and position within
# its grid cell
ipt = wxPoint(x, y)
isz = item.CalcMin()
flag = item.GetFlag()
if flag & wxEXPAND or flag & wxSHAPED:
isz = wxSize(w, h)
else:
if flag & wxALIGN_CENTER_HORIZONTAL:
ipt.x = x + (w - isz.width) / 2
elif flag & wxALIGN_RIGHT:
ipt.x = x + (w - isz.width)
if flag & wxALIGN_CENTER_VERTICAL:
ipt.y = y + (h - isz.height) / 2
elif flag & wxALIGN_BOTTOM:
ipt.y = y + (h - isz.height)
item.SetDimension(ipt, isz)
#----------------------------------------------------------------------
class wxFlexGridSizer(wxGridSizer):
def __init__(self, rows=0, cols=0, hgap=0, vgap=0):
wxGridSizer.__init__(self, rows, cols, hgap, vgap)
self.rowHeights = []
self.colWidths = []
self.growableRows = []
self.growableCols = []
def AddGrowableRow(self, idx):
self.growableRows.append(idx)
def AddGrowableCol(self, idx):
self.growableCols.append(idx)
#--------------------------------------------------
def CalcMin(self):
items = self.GetChildren()
nitems = len(items)
nrows = self.rows
ncols = self.cols
if ncols > 0:
nrows = (nitems + ncols-1) / ncols
else:
ncols = (nitems + nrows-1) / nrows
# Find the max width and height for any component.
self.rowHeights = [0] * nrows
self.colWidths = [0] * ncols
for i in range(len(items)):
size = items[i].CalcMin()
row = i / ncols
col = i % ncols
self.rowHeights[row] = max(size.height, self.rowHeights[row])
self.colWidths[col] = max(size.width, self.colWidths[col])
# Add up all the widths and heights
cellsWidth = reduce(operator.__add__, self.colWidths)
cellHeight = reduce(operator.__add__, self.rowHeights)
return wxSize(cellsWidth + (ncols-1) * self.hgap,
cellHeight + (nrows-1) * self.vgap)
#--------------------------------------------------
def RecalcSizes(self):
items = self.GetChildren()
if not items:
return
nitems = len(items)
nrows = self.rows
ncols = self.cols
if ncols > 0:
nrows = (nitems + ncols-1) / ncols
else:
ncols = (nitems + nrows-1) / nrows
minsz = self.CalcMin()
sz = self.GetSize()
pt = self.GetPosition()
# Check for growables
if self.growableRows and sz.height > minsz.height:
delta = (sz.height - minsz.height) / len(self.growableRows)
for idx in self.growableRows:
self.rowHeights[idx] = self.rowHeights[idx] + delta
if self.growableCols and sz.width > minsz.width:
delta = (sz.width - minsz.width) / len(self.growableCols)
for idx in self.growableCols:
self.colWidths[idx] = self.colWidths[idx] + delta
# bottom right corner
sz = wxSize(pt.x + sz.width, pt.y + sz.height)
# Layout each cell
x = pt.x
for c in range(ncols):
y = pt.y
for r in range(nrows):
i = r * ncols + c
if i < nitems:
w = max(0, min(self.colWidths[c], sz.width - x))
h = max(0, min(self.rowHeights[r], sz.height - y))
self.SetItemBounds(items[i], x, y, w, h)
y = y + self.rowHeights[r] + self.vgap
x = x + self.colWidths[c] + self.hgap
#----------------------------------------------------------------------
## This file imports items from the wx package into the wxPython package for
## backwards compatibility. Some names will also have a 'wx' added on if
## that is how they used to be named in the old wxPython package.
import wx.lib.grids
__doc__ = wx.lib.grids.__doc__
wxFlexGridSizer = wx.lib.grids.wxFlexGridSizer
wxGridSizer = wx.lib.grids.wxGridSizer

View File

@@ -1,315 +1,14 @@
#----------------------------------------------------------------------------
# Name: BrowseImage.py
# Purpose: Display and Select Image Files
#
# Author: Lorne White
#
# Version: 1.0
# Date: January 29, 2002
# Licence: wxWindows license
#----------------------------------------------------------------------------
## This file imports items from the wx package into the wxPython package for
## backwards compatibility. Some names will also have a 'wx' added on if
## that is how they used to be named in the old wxPython package.
# 1.0 Release
# Create list of all available image file types
# View "All Image" File Types as default filter
# Sort the file list
# Use newer "re" function for patterns
import wx.lib.imagebrowser
#---------------------------------------------------------------------------
__doc__ = wx.lib.imagebrowser.__doc__
import os, sys
from wxPython.wx import *
dir_path = os.getcwd()
#---------------------------------------------------------------------------
def ConvertBMP(file_nm):
if file_nm is None:
return None
fl_fld = os.path.splitext(file_nm)
ext = fl_fld[1]
ext = ext[1:].lower()
if ext == 'bmp':
image = wxImage(file_nm, wxBITMAP_TYPE_BMP)
elif ext == 'gif':
image = wxImage(file_nm, wxBITMAP_TYPE_GIF)
elif ext == 'png':
image = wxImage(file_nm, wxBITMAP_TYPE_PNG)
elif ext == 'jpg':
image = wxImage(file_nm, wxBITMAP_TYPE_JPEG)
elif ext == 'pcx':
image = wxImage(file_nm, wxBITMAP_TYPE_PCX)
elif ext == 'tif':
image = wxImage(file_nm, wxBITMAP_TYPE_TIF)
elif ext == 'pnm':
image = wxImage(file_nm, wxBITMAP_TYPE_PNM)
else:
image = wxImage(file_nm, wxBITMAP_TYPE_ANY)
return image
def GetSize(file_nm): # for scaling image values
image = ConvertBMP(file_nm)
bmp = image.ConvertToBitmap()
size = bmp.GetWidth(), bmp.GetHeight()
return size
class ImageView(wxWindow):
def __init__(self, parent, id=-1, pos=wxDefaultPosition, size=wxDefaultSize):
wxWindow.__init__(self, parent, id, pos, size)
self.win = parent
self.image = None
self.back_color = 'WHITE'
self.border_color = 'BLACK'
self.image_sizex = size.width
self.image_sizey = size.height
self.image_posx = pos.x
self.image_posy = pos.y
EVT_PAINT(self, self.OnPaint)
wxInitAllImageHandlers()
def OnPaint(self, event):
dc = wxPaintDC(self)
self.DrawImage(dc)
def DrawImage(self, dc):
dc.BeginDrawing()
self.DrawImage(dc)
dc.EndDrawing()
def SetValue(self, file_nm): # display the selected file in the panel
image = ConvertBMP(file_nm)
self.image = image
self.Refresh()
def DrawBorder(self, dc):
brush = wxBrush(wxNamedColour(self.back_color), wxSOLID)
dc.SetBrush(brush)
dc.SetPen(wxPen(wxNamedColour(self.border_color), 1))
dc.DrawRectangle(0, 0, self.image_sizex, self.image_sizey)
def DrawImage(self, dc):
try:
image = self.image
except:
return
self.DrawBorder(dc)
if image is None:
return
bmp = image.ConvertToBitmap()
iwidth = bmp.GetWidth() # dimensions of image file
iheight = bmp.GetHeight()
diffx = (self.image_sizex - iwidth)/2 # center calc
if iwidth >= self.image_sizex -10: # if image width fits in window adjust
diffx = 5
iwidth = self.image_sizex - 10
diffy = (self.image_sizey - iheight)/2 # center calc
if iheight >= self.image_sizey - 10: # if image height fits in window adjust
diffy = 5
iheight = self.image_sizey - 10
image.Rescale(iwidth, iheight) # rescale to fit the window
image.ConvertToBitmap()
bmp = image.ConvertToBitmap()
dc.DrawBitmap(bmp, diffx, diffy) # draw the image to window
class ImageDialog(wxDialog):
def __init__(self, parent, set_dir = None):
wxDialog.__init__(self, parent, -1, "Image Browser", wxPyDefaultPosition, wxSize(400, 400))
self.x_pos = 30 # initial display positions
self.y_pos = 20
self.delta = 20
size = wxSize(80, 25)
self.set_dir = os.getcwd()
self.set_file = None
if set_dir != None:
if os.path.exists(set_dir): # set to working directory if nothing set
self.set_dir = set_dir
self.dir_x = self.x_pos
self.dir_y = self.y_pos
self.DisplayDir() # display the directory value
self.y_pos = self.y_pos + self.delta
mID = wxNewId()
wxButton(self, mID, ' Set Directory ', wxPoint(self.x_pos, self.y_pos), size).SetDefault()
EVT_BUTTON(self, mID, self.SetDirect)
self.type_posy = self.y_pos # save the y position for the image type combo
self.fl_ext = '*.bmp' # initial setting for file filtering
self.GetFiles() # get the file list
self.y_pos = self.y_pos + self.delta + 10
self.list_height = 150
# List of Labels
mID = wxNewId()
self.tb = tb = wxListBox(self, mID, wxPoint(self.x_pos, self.y_pos), wxSize(160, self.list_height), self.fl_list, wxLB_SINGLE)
EVT_LISTBOX(self, mID, self.OnListClick)
EVT_LISTBOX_DCLICK(self, mID, self.OnListDClick)
width, height = self.tb.GetSizeTuple()
image_posx = self.x_pos + width + 20 # positions for setting the image window
image_posy = self.y_pos
image_sizex = 150
image_sizey = self.list_height
self.fl_types = ["All Images", "Bmp", "Gif", "Png", "Jpg", "Ico", "Pnm", "Pcx", "Tif", "All Files"]
self.fl_ext_types = { "All Images": "All", "Bmp": "*.bmp", "Gif": "*.gif", "Png": "*.png", "Jpg": "*.jpg",
"Ico": "*.ico", "Pnm": "*.pnm", "Pcx": "*.pcx", "Tif": "*.tif", "All Files": "*.*" }
self.set_type = self.fl_types[0] # initial file filter setting
self.fl_ext = self.fl_ext_types[self.set_type]
mID = wxNewId()
self.sel_type = wxComboBox(self, mID, self.set_type, wxPoint(image_posx , self.type_posy), wxSize(150, -1), self.fl_types, wxCB_DROPDOWN)
EVT_COMBOBOX(self, mID, self.OnSetType)
self.image_view = ImageView(self, pos=wxPoint(image_posx, image_posy), size=wxSize(image_sizex, image_sizey))
self.y_pos = self.y_pos + height + 20
mID = wxNewId()
wxButton(self, mID, ' Select ', wxPoint(100, self.y_pos), size).SetDefault()
EVT_BUTTON(self, mID, self.OnOk)
wxButton(self, wxID_CANCEL, 'Cancel', wxPoint(250, self.y_pos), size)
self.y_pos = self.y_pos + self.delta
fsize = wxSize(400, self.y_pos + 50) # resize dialog for final vertical position
self.SetSize(fsize)
self.ResetFiles()
def GetFiles(self): # get the file list using directory and extension values
if self.fl_ext == "All":
all_files = []
for ftypes in self.fl_types[1:-1]: # get list of all available image types
filter = self.fl_ext_types[ftypes]
print "filter = ", filter
self.fl_val = FindFiles(self, self.set_dir, filter)
all_files = all_files + self.fl_val.files # add to list of files
self.fl_list = all_files
else:
self.fl_val = FindFiles(self, self.set_dir, self.fl_ext)
self.fl_list = self.fl_val.files
self.fl_list.sort() # sort the file list
def DisplayDir(self): # display the working directory
wxStaticText(self, -1, self.set_dir, wxPoint(self.dir_x, self.dir_y), wxSize(250, -1))
def OnSetType(self, event):
val = event.GetString() # get file type value
self.fl_ext = self.fl_ext_types[val]
self.ResetFiles()
def OnListDClick(self, event):
self.OnOk(0)
def OnListClick(self, event):
val = event.GetSelection()
self.SetListValue(val)
def SetListValue(self, val):
file_nm = self.fl_list[val]
self.set_file = file_val = os.path.join(self.set_dir, file_nm)
self.image_view.SetValue(file_val)
def SetDirect(self, event): # set the new directory
dlg = wxDirDialog(self)
dlg.SetPath(self.set_dir)
if dlg.ShowModal() == wxID_OK:
self.set_dir = dlg.GetPath()
self.ResetFiles()
dlg.Destroy()
def ResetFiles(self): # refresh the display with files and initial image
self.DisplayDir()
self.GetFiles()
self.tb.Set(self.fl_list)
try:
self.tb.SetSelection(0)
self.SetListValue(0)
except:
self.image_view.SetValue(None)
def GetFile(self):
return self.set_file
def GetDirectory(self):
return self.set_dir
def OnCancel(self, event):
self.result = None
self.EndModal(wxID_CANCEL)
def OnOk(self, event):
self.result = self.set_file
self.EndModal(wxID_OK)
def OnFileDlg(self):
dlg = wxFileDialog(self, "Choose an Image File", ".", "", "Bmp (*.bmp)|*.bmp|JPEG (*.jpg)|*.jpg", wxOPEN)
if dlg.ShowModal() == wxID_OK:
path = dlg.GetPath()
else:
path = None
dlg.Destroy()
return path
class FindFiles:
def __init__(self, parent, dir, mask):
filelist = []
dirlist = [".."]
self.dir = dir
self.file = ""
mask = mask.upper()
pattern = self.MakeRegex(mask)
for i in os.listdir(dir):
if i == "." or i == "..":
continue
path = os.path.join(dir, i)
path = path.upper()
value = i.upper()
if pattern.match(value) != None:
filelist.append(i)
self.files = filelist
def MakeRegex(self, pattern):
import re
f = "" # Set up a regex for file names
for ch in pattern:
if ch == "*":
f = f + ".*"
elif ch == ".":
f = f + "\."
elif ch == "?":
f = f + "."
else:
f = f + ch
return re.compile(f+'$')
def StripExt(self, file_nm):
fl_fld = os.path.splitext(file_nm)
fl_name = fl_fld[0]
ext = fl_fld[1]
return ext[1:]
ConvertBMP = wx.lib.imagebrowser.ConvertBMP
FindFiles = wx.lib.imagebrowser.FindFiles
GetSize = wx.lib.imagebrowser.GetSize
ImageDialog = wx.lib.imagebrowser.ImageDialog
ImageView = wx.lib.imagebrowser.ImageView
OnFileDlg = wx.lib.imagebrowser.OnFileDlg

View File

@@ -1,45 +1,10 @@
#----------------------------------------------------------------------
# Name: wxPython.lib.imageutils
# Purpose: A collection of functions for simple image manipulations
#
# Author: Robb Shecter
#
# Created: 7-Nov-2002
# RCS-ID: $Id$
# Copyright: (c) 2002 by
# Licence: wxWindows license
#----------------------------------------------------------------------
## This file imports items from the wx package into the wxPython package for
## backwards compatibility. Some names will also have a 'wx' added on if
## that is how they used to be named in the old wxPython package.
from __future__ import nested_scopes
import wx.lib.imageutils
__doc__ = wx.lib.imageutils.__doc__
def grayOut(anImage):
"""
Convert the given image (in place) to a grayed-out
version, appropriate for a 'disabled' appearance.
"""
factor = 0.7 # 0 < f < 1. Higher is grayer.
if anImage.HasMask():
maskColor = (anImage.GetMaskRed(), anImage.GetMaskGreen(), anImage.GetMaskBlue())
else:
maskColor = None
data = map(ord, list(anImage.GetData()))
for i in range(0, len(data), 3):
pixel = (data[i], data[i+1], data[i+2])
pixel = makeGray(pixel, factor, maskColor)
for x in range(3):
data[i+x] = pixel[x]
anImage.SetData(''.join(map(chr, data)))
def makeGray((r,g,b), factor, maskColor):
"""
Make a pixel grayed-out. If the pixel
matches the maskColor, it won't be
changed.
"""
if (r,g,b) != maskColor:
return map(lambda x: int((230 - x) * factor) + x, (r,g,b))
else:
return (r,g,b)
grayOut = wx.lib.imageutils.grayOut
makeGray = wx.lib.imageutils.makeGray

View File

@@ -1,471 +1,11 @@
"""
infoframe.py
Released under wxWindows license etc.
## This file imports items from the wx package into the wxPython package for
## backwards compatibility. Some names will also have a 'wx' added on if
## that is how they used to be named in the old wxPython package.
This is a fairly rudimentary, but slightly fancier tha
wxPyOnDemandOutputWindow (on which it's based; thanks Robin), version
of the same sort of thing: a file-like class called
wxInformationalMessagesFrame. This window also has a status bar with a
couple of buttons for controlling the echoing of all output to a file
with a randomly-chosen filename...
import wx.lib.infoframe
The class behaves similarly to wxPyOnDemandOutputWindow in that (at
least by default) the frame does not appear until written to, but is
somewhat different in that, either under programmatic (the
DisableOutput method) or user (the frame's close button, it's status
bar's "Dismiss" button, or a "Disable output" item of some menu,
perhaps of some other frame), the frame will be destroyed, an
associated file closed, and writing to it will then do nothing. This
can be reversed: either under programmatic (the EnableOutput method)
or user (an "Enable output" item of some menu), a new frame will be
opened,And an associated file (with a "randomly"selected filename)
opened for writing [to which all subsequent displayed messages will be
echoed].
Please note that, like wxPyOnDemandOutputWindow, the instance is not
itself a subclass of wxWindow: when the window is open (and ONLY
then), it's "frame" attribute is the actual instance of wFrame...
Typical usage:
from wxPython.lib.infoframe import *
... # ... modify your wxApp as follows:
class myApp(wxApp):
outputWindowClass = wxPyInformationalMessagesFrame
...
If you're running on Linux, you'll also have to supply an argument 1 to your
constructor of myApp to redirect stdout/stderr to this window (it's done
automatically for you on Windows).
If you don't want to redirect stdout/stderr, but use the class directly: do
it this way:
InformationalMessagesFrame = wxPyInformationalMessagesFrame\
([options from progname (default ""),
txt (default "informational
messages"])
#^^^^ early in the program
...
InformationalMessagesFrame([comma-separated list of items to
display. Note that these will never
be separated by spaces as they may
be when used in the Python 'print'
command])
The latter statement, of course, may be repeated arbitrarily often.
The window will not appear until it is written to, and it may be
manually closed by the user, after which it will reappear again until
written to... Also note that all output is echoed to a file with a
randomly-generated name [see the mktemp module in the standard
library], in the directory given as the 'dir' keyword argument to the
InformationalMessagesFrame constructor [which has a default value of
'.'), or set via the method SetOutputDirectory... This file will be
closed with the window--a new one will be created [by default] upon
each subsequent reopening.
Please also note the methods EnableOutput and DisableOutput, and the
possible arguments for the constructor in the code below... (* TO DO:
explain this here...*) Neither of these methods need be used at all,
and in this case the frame will only be displayed once it has been
written to, like wxPyOnDemandOutputWindow.
The former, EnableOutput, displays the frame with an introductory
message, opens a random file to which future displayed output also
goes (unless the nofile attribute is present), and sets the __debug__
variable of each module to 1 (unless the no __debug__ attribute is
present]. This is so that you can say, in any module whatsoever,
if __debug__:
InformationalMessagesFrame("... with lots of %<Character> constructs"
% TUPLE)
without worrying about the overhead of evaluating the arguments, and
calling the wxInformationalMessagesFrame instance, in the case where
debugging is not turned on. (This won't happen if the instance has an
attribute no__debug__; you can arrange this by sub-classing...)
"Debug mode" can also be turned on by selecting the item-"Enable
output" from the "Debug" menu [the default--see the optional arguments
to the SetOtherMenuBar method] of a frame which has been either passed
appropriately to the constructor of the wxInformationalMessagesFrame
(see the code), or set via the SetOtherMenuBar method thereof. This
also writes an empty string to the instance, meaning that the frame
will open (unless DisablOutput has been called) with an appropriate
introductory message (which will vary according to whether the
instance/class has the "no __debug__" attribute)^ I have found this to
be an extremely useful tool, in lieu of a full wxPython debugger...
Following this, the menu item is also disabled, and an item "Disable
output" (again, by default) is enabled. Note that these need not be
done: e.g., you don't NEED to have a menu with appropriate items; in
this case simply do not call the SetOtherMenuBar method or use the
othermenubar keyword argument of the class instance constructor.
The DisableOutput method does the reverse of this; it closes the
window (and associated file), and sets the __debug__ variable of each
module whose name begins with a capital letter {this happens to be the
author's personal practice; all my python module start with capital
letters} to 0. It also enables/disabled the appropriate menu items,
if this was done previously (or SetOtherMenuBar has been called...).
Note too that after a call to DisableOutput, nothing further will be
done upon subsequent write()'s, until the EnableOutput method is
called, either explicitly or by the menu selection above...
Finally, note that the file-like method close() destroys the window
(and closes any associated file) and there is a file-like method
write() which displays it's argument.
All (well, most) of this is made clear by the example code at the end
of this file, which is run if the file is run by itself; otherwise,
see the appropriate "stub" file in the wxPython demo.
"""
from wxPython.wx import *
import sys, tempfile, os
class _MyStatusBar(wxStatusBar):
def __init__(self, parent,callbacks=None,useopenbutton=0):
wxStatusBar.__init__(self, parent, -1, style=wxTAB_TRAVERSAL)
self.SetFieldsCount(3)
self.SetStatusText("",0)
ID = wxNewId()
self.button1 = wxButton(self,ID,"Dismiss",
style=wxTAB_TRAVERSAL)
EVT_BUTTON(self,ID,self.OnButton1)
ID = wxNewId()
if not useopenbutton:
self.button2 = wxButton(self,ID,"Close File",
style=wxTAB_TRAVERSAL)
else:
self.button2 = wxButton(self,ID,"Open New File",
style=wxTAB_TRAVERSAL)
EVT_BUTTON(self,ID,self.OnButton2)
self.useopenbutton = useopenbutton
self.callbacks = callbacks
# figure out how tall to make the status bar
dc = wxClientDC(self)
dc.SetFont(self.GetFont())
(w,h) = dc.GetTextExtent('X')
h = int(h * 1.8)
self.SetSize(wxSize(100, h))
self.OnSize("dummy")
EVT_SIZE(self,self.OnSize)
# reposition things...
def OnSize(self, event):
self.CalculateSizes()
rect = self.GetFieldRect(1)
self.button1.SetPosition(wxPoint(rect.x+5, rect.y+2))
self.button1.SetSize(wxSize(rect.width-10, rect.height-4))
rect = self.GetFieldRect(2)
self.button2.SetPosition(wxPoint(rect.x+5, rect.y+2))
self.button2.SetSize(wxSize(rect.width-10, rect.height-4))
# widths........
def CalculateSizes(self):
dc = wxClientDC(self.button1)
dc.SetFont(self.button1.GetFont())
(w1,h) = dc.GetTextExtent(self.button1.GetLabel())
dc = wxClientDC(self.button2)
dc.SetFont(self.button2.GetFont())
(w2,h) = dc.GetTextExtent(self.button2.GetLabel())
self.SetStatusWidths([-1,w1+15,w2+15])
def OnButton1(self,event):
self.callbacks[0] ()
def OnButton2(self,event):
if self.useopenbutton and self.callbacks[2] ():
self.button2.SetLabel ("Close File")
elif self.callbacks[1] ():
self.button2.SetLabel ("Open New File")
self.useopenbutton = 1 - self.useopenbutton
self.OnSize("")
self.button2.Refresh(True)
self.Refresh()
class wxPyInformationalMessagesFrame:
def __init__(self,
progname="",
text="informational messages",
dir='.',
menuname="Debug",
enableitem="Enable output",
disableitem="Disable output",
othermenubar=None):
self.SetOtherMenuBar(othermenubar,
menuname=menuname,
enableitem=enableitem,
disableitem=disableitem)
if hasattr(self,"othermenu") and self.othermenu is not None:
i = self.othermenu.FindMenuItem(self.menuname,self.disableitem)
self.othermenu.Enable(i,0)
i = self.othermenu.FindMenuItem(self.menuname,self.enableitem)
self.othermenu.Enable(i,1)
self.frame = None
self.title = "%s %s" % (progname,text)
self.parent = None # use the SetParent method if desired...
self.softspace = 1 # of rather limited use
if dir:
self.SetOutputDirectory(dir)
def SetParent(self, parent):
self.parent = parent
def SetOtherMenuBar(self,
othermenu,
menuname="Debug",
enableitem="Enable output",
disableitem="Disable output"):
self.othermenu = othermenu
self.menuname = menuname
self.enableitem = enableitem
self.disableitem = disableitem
f = None
def write(self,string):
if not wxThread_IsMain():
# Aquire the GUI mutex before making GUI calls. Mutex is released
# when locker is deleted at the end of this function.
locker = wxMutexGuiLocker()
if self.Enabled:
if self.f:
self.f.write(string)
self.f.flush()
move = 1
if (hasattr(self,"text")
and self.text is not None
and self.text.GetInsertionPoint() != self.text.GetLastPosition()):
move = 0
if not self.frame:
self.frame = wxFrame(self.parent, -1, self.title, size=(450, 300),
style=wxDEFAULT_FRAME_STYLE|wxNO_FULL_REPAINT_ON_RESIZE)
self.text = wxTextCtrl(self.frame, -1, "",
style = wxTE_MULTILINE|wxTE_READONLY|wxTE_RICH)
self.frame.sb = _MyStatusBar(self.frame,
callbacks=[self.DisableOutput,
self.CloseFile,
self.OpenNewFile],
useopenbutton=hasattr(self,
"nofile"))
self.frame.SetStatusBar(self.frame.sb)
self.frame.Show(True)
EVT_CLOSE(self.frame, self.OnCloseWindow)
if hasattr(self,"nofile"):
self.text.AppendText(
"Please close this window (or select the "
"'Dismiss' button below) when desired. By "
"default all messages written to this window "
"will NOT be written to a file--you "
"may change this by selecting 'Open New File' "
"below, allowing you to select a "
"new file...\n\n")
else:
tempfile.tempdir = self.dir
filename = os.path.abspath(tempfile.mktemp ())
self.text.AppendText(
"Please close this window (or select the "
"'Dismiss' button below) when desired. By "
"default all messages written to this window "
"will also be written to the file '%s'--you "
"may close this file by selecting 'Close "
"File' below, whereupon this button will be "
"replaced with one allowing you to select a "
"new file...\n\n" % filename)
try:
self.f = open(filename, 'w')
self.frame.sb.SetStatusText("File '%s' opened..."
% filename,
0)
except EnvironmentError:
self.frame.sb.SetStatusText("File creation failed "
"(filename '%s')..."
% filename,
0)
self.text.AppendText(string)
if move:
self.text.ShowPosition(self.text.GetLastPosition())
if not hasattr(self,"no__debug__"):
for m in sys.modules.values():
if m is not None:# and m.__dict__.has_key("__debug__"):
m.__dict__["__debug__"] = 1
if hasattr(self,"othermenu") and self.othermenu is not None:
i = self.othermenu.FindMenuItem(self.menuname,self.disableitem)
self.othermenu.Enable(i,1)
i = self.othermenu.FindMenuItem(self.menuname,self.enableitem)
self.othermenu.Enable(i,0)
Enabled = 1
def OnCloseWindow(self, event, exiting=0):
if self.f:
self.f.close()
self.f = None
if (hasattr(self,"othermenu") and self.othermenu is not None
and self.frame is not None
and not exiting):
i = self.othermenu.FindMenuItem(self.menuname,self.disableitem)
self.othermenu.Enable(i,0)
i = self.othermenu.FindMenuItem(self.menuname,self.enableitem)
self.othermenu.Enable(i,1)
if not hasattr(self,"no__debug__"):
for m in sys.modules.values():
if m is not None:# and m.__dict__.has_key("__debug__"):
m.__dict__["__debug__"] = 0
if self.frame is not None: # typically True, but, e.g., allows
# DisableOutput method (which calls this
# one) to be called when the frame is not
# actually open, so that it is always safe
# to call this method...
frame = self.frame
self.frame = self.text = None
frame.Destroy()
self.Enabled = 1
def EnableOutput(self,
event=None,# event must be the first optional argument...
othermenubar=None,
menuname="Debug",
enableitem="Enable output",
disableitem="Disable output"):
if othermenubar is not None:
self.SetOtherMenuBar(othermenubar,
menuname=menuname,
enableitem=enableitem,
disableitem=disableitem)
self.Enabled = 1
if self.f:
self.f.close()
self.f = None
self.write("")
def CloseFile(self):
if self.f:
if self.frame:
self.frame.sb.SetStatusText("File '%s' closed..."
% os.path.abspath(self.f.name),
0)
self.f.close ()
self.f = None
else:
if self.frame:
self.frame.sb.SetStatusText("")
if self.frame:
self.frame.sb.Refresh()
return 1
def OpenNewFile(self):
self.CloseFile()
dlg = wxFileDialog(self.frame,
"Choose a new log file", self.dir,"","*",
wxSAVE | wxHIDE_READONLY | wxOVERWRITE_PROMPT)
if dlg.ShowModal() == wxID_CANCEL:
dlg.Destroy()
return 0
else:
try:
self.f = open(os.path.abspath(dlg.GetPath()),'w')
except EnvironmentError:
dlg.Destroy()
return 0
dlg.Destroy()
if self.frame:
self.frame.sb.SetStatusText("File '%s' opened..."
% os.path.abspath(self.f.name),
0)
if hasattr(self,"nofile"):
self.frame.sb = _MyStatusBar(self.frame,
callbacks=[self.DisableOutput,
self.CloseFile,
self.OpenNewFile])
self.frame.SetStatusBar(self.frame.sb)
if hasattr(self,"nofile"):
delattr(self,"nofile")
return 1
def DisableOutput(self,
event=None,# event must be the first optional argument...
exiting=0):
self.write("<InformationalMessagesFrame>.DisableOutput()\n")
if hasattr(self,"frame") \
and self.frame is not None:
self.OnCloseWindow("Dummy",exiting=exiting)
self.Enabled = 0
def close(self):
self.DisableOutput()
def flush(self):
if self.text:
self.text.SetInsertionPointEnd()
wxYield()
def __call__(self,* args):
for s in args:
self.write (str (s))
def SetOutputDirectory(self,dir):
self.dir = os.path.abspath(dir)
## sys.__stderr__.write("Directory: os.path.abspath(%s) = %s\n"
## % (dir,self.dir))
class Dummy_wxPyInformationalMessagesFrame:
def __init__(self,progname=""):
self.softspace = 1
def __call__(self,*args):
pass
def write(self,s):
pass
def flush(self):
pass
def close(self):
pass
def EnableOutput(self):
pass
def __call__(self,* args):
pass
def DisableOutput(self,exiting=0):
pass
def SetParent(self,wX):
pass
__doc__ = wx.lib.infoframe.__doc__
Dummy_wxPyInformationalMessagesFrame = wx.lib.infoframe.Dummy_wxPyInformationalMessagesFrame
_MyStatusBar = wx.lib.infoframe._MyStatusBar
wxPyInformationalMessagesFrame = wx.lib.infoframe.wxPyInformationalMessagesFrame

View File

@@ -1,894 +1,12 @@
#----------------------------------------------------------------------------
# Name: wxPython.lib.intctrl.py
# Author: Will Sadkin
# Created: 01/16/2003
# Copyright: (c) 2003 by Will Sadkin
# RCS-ID: $Id$
# License: wxWindows license
#----------------------------------------------------------------------------
# NOTE:
# This was written to provide a standard integer edit control for wxPython.
#
# wxIntCtrl permits integer (long) values to be retrieved or set via
# .GetValue() and .SetValue(), and provides an EVT_INT() event function
# for trapping changes to the control.
#
# It supports negative integers as well as the naturals, and does not
# permit leading zeros or an empty control; attempting to delete the
# contents of the control will result in a (selected) value of zero,
# thus preserving a legitimate integer value, or an empty control
# (if a value of None is allowed for the control.) Similarly, replacing the
# contents of the control with '-' will result in a selected (absolute)
# value of -1.
#
# wxIntCtrl also supports range limits, with the option of either
# enforcing them or simply coloring the text of the control if the limits
# are exceeded.
## This file imports items from the wx package into the wxPython package for
## backwards compatibility. Some names will also have a 'wx' added on if
## that is how they used to be named in the old wxPython package.
from wxPython.wx import *
import types, string
from sys import maxint
MAXINT = maxint # (constants should be in upper case)
MININT = -maxint-1
import wx.lib.intctrl
#----------------------------------------------------------------------------
__doc__ = wx.lib.intctrl.__doc__
wxEVT_COMMAND_INT_UPDATED = wxNewEventType()
# wxWindows' wxTextCtrl translates Composite "control key"
# events into single events before returning them to its OnChar
# routine. The doc says that this results in 1 for Ctrl-A, 2 for
# Ctrl-B, etc. However, there are no wxPython or wxWindows
# symbols for them, so I'm defining codes for Ctrl-X (cut) and
# Ctrl-V (paste) here for readability:
WXK_CTRL_X = (ord('X')+1) - ord('A')
WXK_CTRL_V = (ord('V')+1) - ord('A')
def EVT_INT(win, id, func):
"""Used to trap events indicating that the current
integer value of the control has been changed."""
win.Connect(id, -1, wxEVT_COMMAND_INT_UPDATED, func)
class wxIntUpdatedEvent(wxPyCommandEvent):
def __init__(self, id, value = 0, object=None):
wxPyCommandEvent.__init__(self, wxEVT_COMMAND_INT_UPDATED, id)
self.__value = value
self.SetEventObject(object)
def GetValue(self):
"""Retrieve the value of the control at the time
this event was generated."""
return self.__value
#----------------------------------------------------------------------------
class wxIntValidator( wxPyValidator ):
"""
Validator class used with wxIntCtrl; handles all validation of input
prior to changing the value of the underlying wxTextCtrl.
"""
def __init__(self):
wxPyValidator.__init__(self)
EVT_CHAR(self, self.OnChar)
def Clone (self):
return self.__class__()
def Validate(self, window): # window here is the *parent* of the ctrl
"""
Because each operation on the control is vetted as it's made,
the value of the control is always valid.
"""
return 1
def OnChar(self, event):
"""
Validates keystrokes to make sure the resulting value will a legal
value. Erasing the value causes it to be set to 0, with the value
selected, so it can be replaced. Similarly, replacing the value
with a '-' sign causes the value to become -1, with the value
selected. Leading zeros are removed if introduced by selection,
and are prevented from being inserted.
"""
key = event.KeyCode()
ctrl = event.GetEventObject()
value = ctrl.GetValue()
textval = wxTextCtrl.GetValue(ctrl)
allow_none = ctrl.IsNoneAllowed()
pos = ctrl.GetInsertionPoint()
sel_start, sel_to = ctrl.GetSelection()
select_len = sel_to - sel_start
# (Uncomment for debugging:)
## print 'keycode:', key
## print 'pos:', pos
## print 'sel_start, sel_to:', sel_start, sel_to
## print 'select_len:', select_len
## print 'textval:', textval
# set defaults for processing:
allow_event = 1
set_to_none = 0
set_to_zero = 0
set_to_minus_one = 0
paste = 0
internally_set = 0
new_value = value
new_text = textval
new_pos = pos
# Validate action, and predict resulting value, so we can
# range check the result and validate that too.
if key in (WXK_DELETE, WXK_BACK, WXK_CTRL_X):
if select_len:
new_text = textval[:sel_start] + textval[sel_to:]
elif key == WXK_DELETE and pos < len(textval):
new_text = textval[:pos] + textval[pos+1:]
elif key == WXK_BACK and pos > 0:
new_text = textval[:pos-1] + textval[pos:]
# (else value shouldn't change)
if new_text in ('', '-'):
# Deletion of last significant digit:
if allow_none and new_text == '':
new_value = None
set_to_none = 1
else:
new_value = 0
set_to_zero = 1
else:
try:
new_value = ctrl._fromGUI(new_text)
except ValueError:
allow_event = 0
elif key == WXK_CTRL_V: # (see comments at top of file)
# Only allow paste if number:
paste_text = ctrl._getClipboardContents()
new_text = textval[:sel_start] + paste_text + textval[sel_to:]
if new_text == '' and allow_none:
new_value = None
set_to_none = 1
else:
try:
# Convert the resulting strings, verifying they
# are legal integers and will fit in proper
# size if ctrl limited to int. (if not,
# disallow event.)
new_value = ctrl._fromGUI(new_text)
if paste_text:
paste_value = ctrl._fromGUI(paste_text)
else:
paste_value = 0
new_pos = sel_start + len(str(paste_value))
# if resulting value is 0, truncate and highlight value:
if new_value == 0 and len(new_text) > 1:
set_to_zero = 1
elif paste_value == 0:
# Disallow pasting a leading zero with nothing selected:
if( select_len == 0
and value is not None
and ( (value >= 0 and pos == 0)
or (value < 0 and pos in [0,1]) ) ):
allow_event = 0
paste = 1
except ValueError:
allow_event = 0
elif key < WXK_SPACE or key > 255:
pass # event ok
elif chr(key) == '-':
# Allow '-' to result in -1 if replacing entire contents:
if( value is None
or (value == 0 and pos == 0)
or (select_len >= len(str(abs(value)))) ):
new_value = -1
set_to_minus_one = 1
# else allow negative sign only at start, and only if
# number isn't already zero or negative:
elif pos != 0 or (value is not None and value < 0):
allow_event = 0
else:
new_text = '-' + textval
new_pos = 1
try:
new_value = ctrl._fromGUI(new_text)
except ValueError:
allow_event = 0
elif chr(key) in string.digits:
# disallow inserting a leading zero with nothing selected
if( chr(key) == '0'
and select_len == 0
and value is not None
and ( (value >= 0 and pos == 0)
or (value < 0 and pos in [0,1]) ) ):
allow_event = 0
# disallow inserting digits before the minus sign:
elif value is not None and value < 0 and pos == 0:
allow_event = 0
else:
new_text = textval[:sel_start] + chr(key) + textval[sel_to:]
try:
new_value = ctrl._fromGUI(new_text)
except ValueError:
allow_event = 0
else:
# not a legal char
allow_event = 0
if allow_event:
# Do range checking for new candidate value:
if ctrl.IsLimited() and not ctrl.IsInBounds(new_value):
allow_event = 0
elif new_value is not None:
# ensure resulting text doesn't result in a leading 0:
if not set_to_zero and not set_to_minus_one:
if( (new_value > 0 and new_text[0] == '0')
or (new_value < 0 and new_text[1] == '0')
or (new_value == 0 and select_len > 1 ) ):
# Allow replacement of leading chars with
# zero, but remove the leading zero, effectively
# making this like "remove leading digits"
# Account for leading zero when positioning cursor:
if( key == WXK_BACK
or (paste and paste_value == 0 and new_pos > 0) ):
new_pos = new_pos - 1
wxCallAfter(ctrl.SetValue, new_value)
wxCallAfter(ctrl.SetInsertionPoint, new_pos)
internally_set = 1
elif paste:
# Always do paste numerically, to remove
# leading/trailing spaces
wxCallAfter(ctrl.SetValue, new_value)
wxCallAfter(ctrl.SetInsertionPoint, new_pos)
internally_set = 1
elif (new_value == 0 and len(new_text) > 1 ):
allow_event = 0
if allow_event:
ctrl._colorValue(new_value) # (one way or t'other)
# (Uncomment for debugging:)
## if allow_event:
## print 'new value:', new_value
## if paste: print 'paste'
## if set_to_none: print 'set_to_none'
## if set_to_zero: print 'set_to_zero'
## if set_to_minus_one: print 'set_to_minus_one'
## if internally_set: print 'internally_set'
## else:
## print 'new text:', new_text
## print 'disallowed'
## print
if allow_event:
if set_to_none:
wxCallAfter(ctrl.SetValue, new_value)
elif set_to_zero:
# select to "empty" numeric value
wxCallAfter(ctrl.SetValue, new_value)
wxCallAfter(ctrl.SetInsertionPoint, 0)
wxCallAfter(ctrl.SetSelection, 0, 1)
elif set_to_minus_one:
wxCallAfter(ctrl.SetValue, new_value)
wxCallAfter(ctrl.SetInsertionPoint, 1)
wxCallAfter(ctrl.SetSelection, 1, 2)
elif not internally_set:
event.Skip() # allow base wxTextCtrl to finish processing
elif not wxValidator_IsSilent():
wxBell()
def TransferToWindow(self):
""" Transfer data from validator to window.
The default implementation returns False, indicating that an error
occurred. We simply return True, as we don't do any data transfer.
"""
return True # Prevent wxDialog from complaining.
def TransferFromWindow(self):
""" Transfer data from window to validator.
The default implementation returns False, indicating that an error
occurred. We simply return True, as we don't do any data transfer.
"""
return True # Prevent wxDialog from complaining.
#----------------------------------------------------------------------------
class wxIntCtrl(wxTextCtrl):
"""
This class provides a control that takes and returns integers as
value, and provides bounds support and optional value limiting.
wxIntCtrl(
parent, id = -1,
value = 0,
pos = wxDefaultPosition,
size = wxDefaultSize,
style = 0,
validator = wxDefaultValidator,
name = "integer",
min = None,
max = None,
limited = False,
allow_none = False,
allow_long = False,
default_color = wxBLACK,
oob_color = wxRED )
value
If no initial value is set, the default will be zero, or
the minimum value, if specified. If an illegal string is specified,
a ValueError will result. (You can always later set the initial
value with SetValue() after instantiation of the control.)
min
The minimum value that the control should allow. This can be
adjusted with SetMin(). If the control is not limited, any value
below this bound will be colored with the current out-of-bounds color.
If min < -sys.maxint-1 and the control is configured to not allow long
values, the minimum bound will still be set to the long value, but
the implicit bound will be -sys.maxint-1.
max
The maximum value that the control should allow. This can be
adjusted with SetMax(). If the control is not limited, any value
above this bound will be colored with the current out-of-bounds color.
if max > sys.maxint and the control is configured to not allow long
values, the maximum bound will still be set to the long value, but
the implicit bound will be sys.maxint.
limited
Boolean indicating whether the control prevents values from
exceeding the currently set minimum and maximum values (bounds).
If False and bounds are set, out-of-bounds values will
be colored with the current out-of-bounds color.
allow_none
Boolean indicating whether or not the control is allowed to be
empty, representing a value of None for the control.
allow_long
Boolean indicating whether or not the control is allowed to hold
and return a long as well as an int.
default_color
Color value used for in-bounds values of the control.
oob_color
Color value used for out-of-bounds values of the control
when the bounds are set but the control is not limited.
validator
Normally None, wxIntCtrl uses its own validator to do value
validation and input control. However, a validator derived
from wxIntValidator can be supplied to override the data
transfer methods for the wxIntValidator class.
"""
def __init__ (
self, parent, id=-1, value = 0,
pos = wxDefaultPosition, size = wxDefaultSize,
style = 0, validator = wxDefaultValidator,
name = "integer",
min=None, max=None,
limited = 0, allow_none = 0, allow_long = 0,
default_color = wxBLACK, oob_color = wxRED,
):
# Establish attrs required for any operation on value:
self.__min = None
self.__max = None
self.__limited = 0
self.__default_color = wxBLACK
self.__oob_color = wxRED
self.__allow_none = 0
self.__allow_long = 0
self.__oldvalue = None
if validator == wxDefaultValidator:
validator = wxIntValidator()
wxTextCtrl.__init__(
self, parent, id, self._toGUI(0),
pos, size, style, validator, name )
# The following lets us set out our "integer update" events:
EVT_TEXT( self, self.GetId(), self.OnText )
# Establish parameters, with appropriate error checking
self.SetBounds(min, max)
self.SetLimited(limited)
self.SetColors(default_color, oob_color)
self.SetNoneAllowed(allow_none)
self.SetLongAllowed(allow_long)
self.SetValue(value)
self.__oldvalue = 0
def OnText( self, event ):
"""
Handles an event indicating that the text control's value
has changed, and issue EVT_INT event.
NOTE: using wxTextCtrl.SetValue() to change the control's
contents from within a EVT_CHAR handler can cause double
text events. So we check for actual changes to the text
before passing the events on.
"""
value = self.GetValue()
if value != self.__oldvalue:
try:
self.GetEventHandler().ProcessEvent(
wxIntUpdatedEvent( self.GetId(), self.GetValue(), self ) )
except ValueError:
return
# let normal processing of the text continue
event.Skip()
self.__oldvalue = value # record for next event
def GetValue(self):
"""
Returns the current integer (long) value of the control.
"""
return self._fromGUI( wxTextCtrl.GetValue(self) )
def SetValue(self, value):
"""
Sets the value of the control to the integer value specified.
The resulting actual value of the control may be altered to
conform with the bounds set on the control if limited,
or colored if not limited but the value is out-of-bounds.
A ValueError exception will be raised if an invalid value
is specified.
"""
wxTextCtrl.SetValue( self, self._toGUI(value) )
self._colorValue()
def SetMin(self, min=None):
"""
Sets the minimum value of the control. If a value of None
is provided, then the control will have no explicit minimum value.
If the value specified is greater than the current maximum value,
then the function returns 0 and the minimum will not change from
its current setting. On success, the function returns 1.
If successful and the current value is lower than the new lower
bound, if the control is limited, the value will be automatically
adjusted to the new minimum value; if not limited, the value in the
control will be colored with the current out-of-bounds color.
If min > -sys.maxint-1 and the control is configured to not allow longs,
the function will return 0, and the min will not be set.
"""
if( self.__max is None
or min is None
or (self.__max is not None and self.__max >= min) ):
self.__min = min
if self.IsLimited() and min is not None and self.GetValue() < min:
self.SetValue(min)
else:
self._colorValue()
return 1
else:
return 0
def GetMin(self):
"""
Gets the minimum value of the control. It will return the current
minimum integer, or None if not specified.
"""
return self.__min
def SetMax(self, max=None):
"""
Sets the maximum value of the control. If a value of None
is provided, then the control will have no explicit maximum value.
If the value specified is less than the current minimum value, then
the function returns 0 and the maximum will not change from its
current setting. On success, the function returns 1.
If successful and the current value is greater than the new upper
bound, if the control is limited the value will be automatically
adjusted to this maximum value; if not limited, the value in the
control will be colored with the current out-of-bounds color.
If max > sys.maxint and the control is configured to not allow longs,
the function will return 0, and the max will not be set.
"""
if( self.__min is None
or max is None
or (self.__min is not None and self.__min <= max) ):
self.__max = max
if self.IsLimited() and max is not None and self.GetValue() > max:
self.SetValue(max)
else:
self._colorValue()
return 1
else:
return 0
def GetMax(self):
"""
Gets the maximum value of the control. It will return the current
maximum integer, or None if not specified.
"""
return self.__max
def SetBounds(self, min=None, max=None):
"""
This function is a convenience function for setting the min and max
values at the same time. The function only applies the maximum bound
if setting the minimum bound is successful, and returns True
only if both operations succeed.
NOTE: leaving out an argument will remove the corresponding bound.
"""
ret = self.SetMin(min)
return ret and self.SetMax(max)
def GetBounds(self):
"""
This function returns a two-tuple (min,max), indicating the
current bounds of the control. Each value can be None if
that bound is not set.
"""
return (self.__min, self.__max)
def SetLimited(self, limited):
"""
If called with a value of True, this function will cause the control
to limit the value to fall within the bounds currently specified.
If the control's value currently exceeds the bounds, it will then
be limited accordingly.
If called with a value of 0, this function will disable value
limiting, but coloring of out-of-bounds values will still take
place if bounds have been set for the control.
"""
self.__limited = limited
if limited:
min = self.GetMin()
max = self.GetMax()
if not min is None and self.GetValue() < min:
self.SetValue(min)
elif not max is None and self.GetValue() > max:
self.SetValue(max)
else:
self._colorValue()
def IsLimited(self):
"""
Returns True if the control is currently limiting the
value to fall within the current bounds.
"""
return self.__limited
def IsInBounds(self, value=None):
"""
Returns True if no value is specified and the current value
of the control falls within the current bounds. This function can
also be called with a value to see if that value would fall within
the current bounds of the given control.
"""
if value is None:
value = self.GetValue()
if( not (value is None and self.IsNoneAllowed())
and type(value) not in (types.IntType, types.LongType) ):
raise ValueError (
'wxIntCtrl requires integer values, passed %s'% repr(value) )
min = self.GetMin()
max = self.GetMax()
if min is None: min = value
if max is None: max = value
# if bounds set, and value is None, return False
if value == None and (min is not None or max is not None):
return 0
else:
return min <= value <= max
def SetNoneAllowed(self, allow_none):
"""
Change the behavior of the validation code, allowing control
to have a value of None or not, as appropriate. If the value
of the control is currently None, and allow_none is 0, the
value of the control will be set to the minimum value of the
control, or 0 if no lower bound is set.
"""
self.__allow_none = allow_none
if not allow_none and self.GetValue() is None:
min = self.GetMin()
if min is not None: self.SetValue(min)
else: self.SetValue(0)
def IsNoneAllowed(self):
return self.__allow_none
def SetLongAllowed(self, allow_long):
"""
Change the behavior of the validation code, allowing control
to have a long value or not, as appropriate. If the value
of the control is currently long, and allow_long is 0, the
value of the control will be adjusted to fall within the
size of an integer type, at either the sys.maxint or -sys.maxint-1,
for positive and negative values, respectively.
"""
current_value = self.GetValue()
if not allow_long and type(current_value) is types.LongType:
if current_value > 0:
self.SetValue(MAXINT)
else:
self.SetValue(MININT)
self.__allow_long = allow_long
def IsLongAllowed(self):
return self.__allow_long
def SetColors(self, default_color=wxBLACK, oob_color=wxRED):
"""
Tells the control what colors to use for normal and out-of-bounds
values. If the value currently exceeds the bounds, it will be
recolored accordingly.
"""
self.__default_color = default_color
self.__oob_color = oob_color
self._colorValue()
def GetColors(self):
"""
Returns a tuple of (default_color, oob_color), indicating
the current color settings for the control.
"""
return self.__default_color, self.__oob_color
def _colorValue(self, value=None):
"""
Colors text with oob_color if current value exceeds bounds
set for control.
"""
if not self.IsInBounds(value):
self.SetForegroundColour(self.__oob_color)
else:
self.SetForegroundColour(self.__default_color)
self.Refresh()
def _toGUI( self, value ):
"""
Conversion function used to set the value of the control; does
type and bounds checking and raises ValueError if argument is
not a valid value.
"""
if value is None and self.IsNoneAllowed():
return ''
elif type(value) == types.LongType and not self.IsLongAllowed():
raise ValueError (
'wxIntCtrl requires integer value, passed long' )
elif type(value) not in (types.IntType, types.LongType):
raise ValueError (
'wxIntCtrl requires integer value, passed %s'% repr(value) )
elif self.IsLimited():
min = self.GetMin()
max = self.GetMax()
if not min is None and value < min:
raise ValueError (
'value is below minimum value of control %d'% value )
if not max is None and value > max:
raise ValueError (
'value exceeds value of control %d'% value )
return str(value)
def _fromGUI( self, value ):
"""
Conversion function used in getting the value of the control.
"""
# One or more of the underlying text control implementations
# issue an intermediate EVT_TEXT when replacing the control's
# value, where the intermediate value is an empty string.
# So, to ensure consistency and to prevent spurious ValueErrors,
# we make the following test, and react accordingly:
#
if value == '':
if not self.IsNoneAllowed():
return 0
else:
return None
else:
try:
return int( value )
except ValueError:
if self.IsLongAllowed():
return long( value )
else:
raise
def Cut( self ):
"""
Override the wxTextCtrl's .Cut function, with our own
that does validation. Will result in a value of 0
if entire contents of control are removed.
"""
sel_start, sel_to = self.GetSelection()
select_len = sel_to - sel_start
textval = wxTextCtrl.GetValue(self)
do = wxTextDataObject()
do.SetText(textval[sel_start:sel_to])
wxTheClipboard.Open()
wxTheClipboard.SetData(do)
wxTheClipboard.Close()
if select_len == len(wxTextCtrl.GetValue(self)):
if not self.IsNoneAllowed():
self.SetValue(0)
self.SetInsertionPoint(0)
self.SetSelection(0,1)
else:
self.SetValue(None)
else:
new_value = self._fromGUI(textval[:sel_start] + textval[sel_to:])
self.SetValue(new_value)
def _getClipboardContents( self ):
"""
Subroutine for getting the current contents of the clipboard.
"""
do = wxTextDataObject()
wxTheClipboard.Open()
success = wxTheClipboard.GetData(do)
wxTheClipboard.Close()
if not success:
return None
else:
# Remove leading and trailing spaces before evaluating contents
return do.GetText().strip()
def Paste( self ):
"""
Override the wxTextCtrl's .Paste function, with our own
that does validation. Will raise ValueError if not a
valid integerizable value.
"""
paste_text = self._getClipboardContents()
if paste_text:
# (conversion will raise ValueError if paste isn't legal)
sel_start, sel_to = self.GetSelection()
text = wxTextCtrl.GetValue( self )
new_text = text[:sel_start] + paste_text + text[sel_to:]
if new_text == '' and self.IsNoneAllowed():
self.SetValue(None)
else:
value = self._fromGUI(new_text)
self.SetValue(value)
new_pos = sel_start + len(paste_text)
wxCallAfter(self.SetInsertionPoint, new_pos)
#===========================================================================
if __name__ == '__main__':
import traceback
class myDialog(wxDialog):
def __init__(self, parent, id, title,
pos = wxPyDefaultPosition, size = wxPyDefaultSize,
style = wxDEFAULT_DIALOG_STYLE ):
wxDialog.__init__(self, parent, id, title, pos, size, style)
self.int_ctrl = wxIntCtrl(self, wxNewId(), size=(55,20))
self.OK = wxButton( self, wxID_OK, "OK")
self.Cancel = wxButton( self, wxID_CANCEL, "Cancel")
vs = wxBoxSizer( wxVERTICAL )
vs.AddWindow( self.int_ctrl, 0, wxALIGN_CENTRE|wxALL, 5 )
hs = wxBoxSizer( wxHORIZONTAL )
hs.AddWindow( self.OK, 0, wxALIGN_CENTRE|wxALL, 5 )
hs.AddWindow( self.Cancel, 0, wxALIGN_CENTRE|wxALL, 5 )
vs.AddSizer(hs, 0, wxALIGN_CENTRE|wxALL, 5 )
self.SetAutoLayout( True )
self.SetSizer( vs )
vs.Fit( self )
vs.SetSizeHints( self )
EVT_INT(self, self.int_ctrl.GetId(), self.OnInt)
def OnInt(self, event):
print 'int now', event.GetValue()
class TestApp(wxApp):
def OnInit(self):
try:
self.frame = wxFrame(NULL, -1, "Test",
wxPoint(20,20), wxSize(120,100) )
self.panel = wxPanel(self.frame, -1)
button = wxButton(self.panel, 10, "Push Me",
wxPoint(20, 20))
EVT_BUTTON(self, 10, self.OnClick)
except:
traceback.print_exc()
return False
return True
def OnClick(self, event):
dlg = myDialog(self.panel, -1, "test wxIntCtrl")
dlg.int_ctrl.SetValue(501)
dlg.int_ctrl.SetInsertionPoint(1)
dlg.int_ctrl.SetSelection(1,2)
rc = dlg.ShowModal()
print 'final value', dlg.int_ctrl.GetValue()
del dlg
self.frame.Destroy()
def Show(self):
self.frame.Show(True)
try:
app = TestApp(0)
app.Show()
app.MainLoop()
except:
traceback.print_exc()
EVT_INT = wx.lib.intctrl.EVT_INT
wxIntCtrl = wx.lib.intctrl.wxIntCtrl
wxIntUpdatedEvent = wx.lib.intctrl.wxIntUpdatedEvent
wxIntValidator = wx.lib.intctrl.wxIntValidator

View File

@@ -1,263 +1,9 @@
from wxPython.wx import wxLayoutConstraints,\
wxTop, wxLeft, wxBottom, wxRight, \
wxHeight, wxWidth, wxCentreX, wxCentreY
import re
class Layoutf(wxLayoutConstraints):
"""
The class Layoutf(wxLayoutConstraints) presents a simplification
of the wxLayoutConstraints syntax. The name Layoutf is choosen
because of the similarity with C's printf function.
Quick Example:
lc = Layoutf('t=t#1;l=r10#2;r!100;h%h50#1', (self, self.panel))
is equivalent to
lc = wxLayoutContraints()
lc.top.SameAs(self, wxTop)
lc.left.SameAs(self.panel, wxRight, 10)
lc.right.Absolute(100)
lc.height.PercentOf(self, wxHeight, 50)
Usage:
You can give a constraint string to the Layoutf constructor,
or use the 'pack' method. The following are equivalent:
lc = Layoutf('t=t#1;l=r#2;r!100;h%h50#1', (self, self.panel))
and
lc = Layoutf()
lc.pack('t=t#1;l=r#2;r!100;h%h50#1', (self, self.panel))
Besides 'pack' there's also 'debug_pack' which does not set
constraints, but prints traditional wxLayoutConstraint calls to
stdout.
The calls to the Layoutf constructor and pack methods have
the following argument list:
(constraint_string, objects_tuple)
Constraint String syntax:
Constraint directives are separated by semi-colons. You
generally (always?) need four directives to completely describe a
subwindow's location.
A single directive has either of the following forms:
1. <own attribute><compare operation>[numerical argument]
for example r!100 -> lc.right.Absolute(100) )
and w* -> lc.width.AsIs()
2. <own attribute><compare operation>[numerical argument]
#<compare object nr.>
for example t_10#2 (lc.top.Below(<second obj>, 10)
3. <own attribute><compare operation><compare attribute>
[numerical argument]#<compare object nr.>
for example w%h50#2 ( lc.width.PercentOf(<second obj>,
wxHeight, 50) and t=b#1 ( lc.top.SameAs(<first obj>,
wxBottom) )
Which one you need is defined by the <compare operation>
type. The following take type 1 (no object to compare with):
'!': 'Absolute', '?': 'Unconstrained', '*': 'AsIs'
These take type 2 (need to be compared with another object)
'<': 'LeftOf', '>': 'RightOf', '^': 'Above', '_': 'Below'
These take type 3 (need to be compared to another object
attribute)
'=': 'SameAs', '%': 'PercentOf'
For all types, the <own attribute> letter can be any of
't': 'top', 'l': 'left', 'b': 'bottom',
'r': 'right', 'h': 'height', 'w': 'width',
'x': 'centreX', 'y': 'centreY'
If the operation takes an (optional) numerical argument, place it
in [numerical argument]. For type 3 directives, the <compare
attribute> letter can be any of
't': 'wxTop', 'l': 'wxLeft', 'b': 'wxBottom'
'r': 'wxRight', 'h': 'wxHeight', 'w': 'wxWidth',
'x': 'wxCentreX', 'y': 'wxCentreY'
Note that these are the same letters as used for <own attribute>,
so you'll only need to remember one set. Finally, the object
whose attribute is refered to, is specified by #<compare object
nr>, where <compare object nr> is the 1-based (stupid, I know,
but I've gotten used to it) index of the object in the
objects_tuple argument.
Bugs:
Not entirely happy about the logic in the order of arguments
after the <compare operation> character.
Not all wxLayoutConstraint methods are included in the
syntax. However, the type 3 directives are generally the most
used. Further excuse: wxWindows layout constraints are at the
time of this writing not documented.
"""
attr_d = { 't': 'top', 'l': 'left', 'b': 'bottom',
'r': 'right', 'h': 'height', 'w': 'width',
'x': 'centreX', 'y': 'centreY' }
op_d = { '=': 'SameAs', '%': 'PercentOf', '<': 'LeftOf',
'>': 'RightOf', '^': 'Above', '_': 'Below',
'!': 'Absolute', '?': 'Unconstrained', '*': 'AsIs' }
cmp_d = { 't': 'wxTop', 'l': 'wxLeft', 'b': 'wxBottom',
'r': 'wxRight', 'h': 'wxHeight', 'w': 'wxWidth',
'x': 'wxCentreX', 'y': 'wxCentreY' }
rexp1 = re.compile('^\s*([tlrbhwxy])\s*([!\?\*])\s*(\d*)\s*$')
rexp2 = re.compile('^\s*([tlrbhwxy])\s*([=%<>^_])\s*([tlrbhwxy]?)\s*(\d*)\s*#(\d+)\s*$')
def __init__(self,pstr=None,winlist=None):
wxLayoutConstraints.__init__(self)
if pstr:
self.pack(pstr,winlist)
def pack(self, pstr, winlist):
pstr = pstr.lower()
for item in pstr.split(';'):
m = self.rexp1.match(item)
if m:
g = list(m.groups())
attr = getattr(self, self.attr_d[g[0]])
func = getattr(attr, self.op_d[g[1]])
if g[1] == '!':
func(int(g[2]))
else:
func()
continue
m = self.rexp2.match(item)
if not m: raise ValueError
g = list(m.groups())
attr = getattr(self, self.attr_d[g[0]])
func = getattr(attr, self.op_d[g[1]])
if g[3]: g[3] = int(g[3])
else: g[3] = None;
g[4] = int(g[4]) - 1
if g[1] in '<>^_':
if g[3]: func(winlist[g[4]], g[3])
else: func(winlist[g[4]])
else:
cmp = eval(self.cmp_d[g[2]])
if g[3]: func(winlist[g[4]], cmp, g[3])
else: func(winlist[g[4]], cmp)
def debug_pack(self, pstr, winlist):
pstr = pstr.lower()
for item in pstr.split(';'):
m = self.rexp1.match(item)
if m:
g = list(m.groups())
attr = getattr(self, self.attr_d[g[0]])
func = getattr(attr, self.op_d[g[1]])
if g[1] == '!':
print "%s.%s.%s(%s)" % \
('self',self.attr_d[g[0]],self.op_d[g[1]],g[2])
else:
print "%s.%s.%s()" % \
('self',self.attr_d[g[0]],self.op_d[g[1]])
continue
m = self.rexp2.match(item)
if not m: raise ValueError
g = list(m.groups())
if g[3]: g[3] = int(g[3])
else: g[3] = 0;
g[4] = int(g[4]) - 1
if g[1] in '<>^_':
if g[3]: print "%s.%s.%s(%s,%d)" % \
('self',self.attr_d[g[0]],self.op_d[g[1]],winlist[g[4]],
g[3])
else: print "%s.%s.%s(%s)" % \
('self',self.attr_d[g[0]],self.op_d[g[1]],winlist[g[4]])
else:
if g[3]: print "%s.%s.%s(%s,%s,%d)" % \
('self',self.attr_d[g[0]],self.op_d[g[1]],winlist[g[4]],
self.cmp_d[g[2]],g[3])
else: print "%s.%s.%s(%s,%s)" % \
('self',self.attr_d[g[0]],self.op_d[g[1]],winlist[g[4]],
self.cmp_d[g[2]])
if __name__=='__main__':
from wxPython.wx import *
class TestLayoutf(wxFrame):
def __init__(self, parent):
wxFrame.__init__(self, parent, -1, 'Test Layout Constraints',
wxPyDefaultPosition, wxSize(500, 300))
EVT_CLOSE(self, self.OnCloseWindow)
self.SetAutoLayout(True)
EVT_BUTTON(self, 100, self.OnButton)
EVT_BUTTON(self, 101, self.OnAbout)
self.panelA = wxWindow(self, -1, wxPyDefaultPosition, wxPyDefaultSize, wxSIMPLE_BORDER)
self.panelA.SetBackgroundColour(wxBLUE)
self.panelA.SetConstraints(Layoutf('t=t10#1;l=l10#1;b=b10#1;r%r50#1',(self,)))
self.panelB = wxWindow(self, -1, wxPyDefaultPosition, wxPyDefaultSize, wxSIMPLE_BORDER)
self.panelB.SetBackgroundColour(wxRED)
self.panelB.SetConstraints(Layoutf('t=t10#1;r=r10#1;b%b30#1;l>10#2', (self,self.panelA)))
self.panelC = wxWindow(self, -1, wxPyDefaultPosition, wxPyDefaultSize, wxSIMPLE_BORDER)
self.panelC.SetBackgroundColour(wxWHITE)
self.panelC.SetConstraints(Layoutf('t_10#3;r=r10#1;b=b10#1;l>10#2', (self,self.panelA,self.panelB)))
b = wxButton(self.panelA, 101, ' About: ')
b.SetConstraints(Layoutf('X=X#1;Y=Y#1;h*;w%w50#1', (self.panelA,)))
b = wxButton(self.panelB, 100, ' Panel B ')
b.SetConstraints(Layoutf('t=t2#1;r=r4#1;h*;w*', (self.panelB,)))
self.panelD = wxWindow(self.panelC, -1, wxPyDefaultPosition, wxPyDefaultSize, wxSIMPLE_BORDER)
self.panelD.SetBackgroundColour(wxGREEN)
self.panelD.SetConstraints(Layoutf('b%h50#1;r%w50#1;h=h#2;w=w#2', (self.panelC, b)))
b = wxButton(self.panelC, 100, ' Panel C ')
b.SetConstraints(Layoutf('t_#1;l>#1;h*;w*', (self.panelD,)))
wxStaticText(self.panelD, -1, "Panel D", wxPoint(4, 4)).SetBackgroundColour(wxGREEN)
def OnButton(self, event):
self.Close(True)
def OnAbout(self, event):
try:
from dialogs import wxScrolledMessageDialog
msg = wxScrolledMessageDialog(self, Layoutf.__doc__, "about")
msg.ShowModal()
except:
print msg
def OnCloseWindow(self, event):
self.Destroy()
class TestApp(wxApp):
def OnInit(self):
frame = TestLayoutf(NULL)
frame.Show(1)
self.SetTopWindow(frame)
return 1
app = TestApp(0)
app.MainLoop()
## This file imports items from the wx package into the wxPython package for
## backwards compatibility. Some names will also have a 'wx' added on if
## that is how they used to be named in the old wxPython package.
import wx.lib.layoutf
__doc__ = wx.lib.layoutf.__doc__
Layoutf = wx.lib.layoutf.Layoutf

View File

@@ -1,101 +1,10 @@
#----------------------------------------------------------------------------
# Name: wxPython.lib.maskedctrl.py
# Author: Will Sadkin
# Created: 09/24/2003
# Copyright: (c) 2003 by Will Sadkin
# RCS-ID: $Id$
# License: wxWindows license
#----------------------------------------------------------------------------
## This file imports items from the wx package into the wxPython package for
## backwards compatibility. Some names will also have a 'wx' added on if
## that is how they used to be named in the old wxPython package.
"""<html><body>
<P>
<B>wxMaskedCtrl</B> is actually a factory function for several types of
masked edit controls:
<P>
<UL>
<LI><b>wxMaskedTextCtrl</b> - standard masked edit text box</LI>
<LI><b>wxMaskedComboBox</b> - adds combobox capabilities</LI>
<LI><b>wxIpAddrCtrl</b> - adds logical input semantics for IP address entry</LI>
<LI><b>wxTimeCtrl</b> - special subclass handling lots of time formats as values</LI>
<LI><b>wxMaskedNumCtrl</b> - special subclass handling numeric values</LI>
</UL>
<P>
<B>wxMaskedCtrl</B> works by looking for a special <b><i>controlType</i></b>
parameter in the variable arguments of the control, to determine
what kind of instance to return.
controlType can be one of:
<PRE><FONT SIZE=-1>
controlTypes.MASKEDTEXT
controlTypes.MASKEDCOMBO
controlTypes.IPADDR
controlTypes.TIME
controlTypes.NUMBER
</FONT></PRE>
These constants are also available individually, ie, you can
use either of the following:
<PRE><FONT SIZE=-1>
from wxPython.wx.lib.maskedctrl import wxMaskedCtrl, MASKEDCOMBO, MASKEDTEXT, NUMBER
from wxPython.wx.lib.maskedctrl import wxMaskedCtrl, controlTypes
</FONT></PRE>
If not specified as a keyword argument, the default controlType is
controlTypes.MASKEDTEXT.
<P>
Each of the above classes has its own unique arguments, but wxMaskedCtrl
provides a single "unified" interface for masked controls. wxMaskedTextCtrl,
wxMaskedComboBox and wxIpAddrCtrl are all documented below; the others have
their own demo pages and interface descriptions.
</body></html>
"""
from wxPython.lib.maskededit import wxMaskedTextCtrl, wxMaskedComboBox, wxIpAddrCtrl
from wxPython.lib.maskednumctrl import wxMaskedNumCtrl
from wxPython.lib.timectrl import wxTimeCtrl
# "type" enumeration for class instance factory function
MASKEDTEXT = 0
MASKEDCOMBO = 1
IPADDR = 2
TIME = 3
NUMBER = 4
# for ease of import
class controlTypes:
MASKEDTEXT = MASKEDTEXT
MASKEDCOMBO = MASKEDCOMBO
IPADDR = IPADDR
TIME = TIME
NUMBER = NUMBER
def wxMaskedCtrl( *args, **kwargs):
"""
Actually a factory function providing a unifying
interface for generating masked controls.
"""
if not kwargs.has_key('controlType'):
controlType = MASKEDTEXT
else:
controlType = kwargs['controlType']
del kwargs['controlType']
if controlType == MASKEDTEXT:
return wxMaskedTextCtrl(*args, **kwargs)
elif controlType == MASKEDCOMBO:
return wxMaskedComboBox(*args, **kwargs)
elif controlType == IPADDR:
return wxIpAddrCtrl(*args, **kwargs)
elif controlType == TIME:
return wxTimeCtrl(*args, **kwargs)
elif controlType == NUMBER:
return wxMaskedNumCtrl(*args, **kwargs)
else:
raise AttributeError(
"invalid controlType specified: %s" % repr(controlType))
import wx.lib.maskedctrl
__doc__ = wx.lib.maskedctrl.__doc__
controlTypes = wx.lib.maskedctrl.controlTypes
wxMaskedCtrl = wx.lib.maskedctrl.wxMaskedCtrl

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,14 +1 @@
#----------------------------------------------------------------------
# Name: wxPython.lib.mixins
# Purpose: A package for helpful wxPython mix-in classes
#
# Author: Robin Dunn
#
# Created: 15-May-2001
# RCS-ID: $Id$
# Copyright: (c) 2001 by Total Control Software
# Licence: wxWindows license
#----------------------------------------------------------------------

View File

@@ -1,43 +1,9 @@
#----------------------------------------------------------------------------
# Name: wxPython.lib.mixins.grid
# Purpose: Helpful mix-in classes for wxGrid
#
# Author: Robin Dunn
#
# Created: 5-June-2001
# RCS-ID: $Id$
# Copyright: (c) 2001 by Total Control Software
# Licence: wxWindows license
#----------------------------------------------------------------------------
## This file imports items from the wx package into the wxPython package for
## backwards compatibility. Some names will also have a 'wx' added on if
## that is how they used to be named in the old wxPython package.
from wxPython import wx, grid
import wx.lib.mixins.grid
#----------------------------------------------------------------------------
class wxGridAutoEditMixin:
"""A mix-in class that automatically enables the grid edit control when
a cell is selected.
If your class hooks EVT_GRID_SELECT_CELL be sure to call event.Skip so
this handler will be called too.
"""
def __init__(self):
self.__enableEdit = 0
wx.EVT_IDLE(self, self.__OnIdle)
grid.EVT_GRID_SELECT_CELL(self, self.__OnSelectCell)
def __OnIdle(self, evt):
if self.__enableEdit:
if self.CanEnableCellControl():
self.EnableCellEditControl()
self.__enableEdit = 0
evt.Skip()
def __OnSelectCell(self, evt):
self.__enableEdit = 1
evt.Skip()
__doc__ = wx.lib.mixins.grid.__doc__
wxGridAutoEditMixin = wx.lib.mixins.grid.wxGridAutoEditMixin

View File

@@ -1,73 +1,9 @@
#----------------------------------------------------------------------------
# Name: wxPython.lib.mixins.listctrl
# Purpose: Helpful mix-in classes for using a wxImageList
#
# Author: Robin Dunn
#
# Created: 15-May-2001
# RCS-ID: $Id$
# Copyright: (c) 2001 by Total Control Software
# Licence: wxWindows license
#----------------------------------------------------------------------------
from wxPython.wx import *
#----------------------------------------------------------------------------
class MagicImageList:
'''
Mix-in to provide "magic" growing image lists
By Mike Fletcher
'''
### LAZYTREE and LISTCONTROL Methods
DEFAULTICONSIZE = 16
def SetupIcons(self, images=(), size=None):
self.__size = size or self.DEFAULTICONSIZE
self.__magicImageList = wxImageList (self.__size,self.__size)
self.__magicImageListMapping = {}
self.SetImageList (
self.__magicImageList, {
16:wxIMAGE_LIST_SMALL,
32:wxIMAGE_LIST_NORMAL,
}[self.__size]
)
for image in images:
self.AddIcon (image)
def GetIcons (self, node):
'''Get icon indexes for a given node, or None if no associated icon'''
icon = self.GetIcon( node )
if icon:
index = self.AddIcon (icon)
return index, index
return None
### Local methods...
def AddIcon(self, icon, mask = wxNullBitmap):
'''Add an icon to the image list, or get the index if already there'''
index = self.__magicImageListMapping.get (id (icon))
if index is None:
if isinstance( icon, wxIconPtr ):
index = self.__magicImageList.AddIcon( icon )
elif isinstance( icon, wxBitmapPtr ):
if isinstance( mask, wxColour ):
index = self.__magicImageList.AddWithColourMask( icon, mask )
else:
index = self.__magicImageList.Add( icon, mask )
else:
raise ValueError("Unexpected icon object %s, "
"expected wxIcon or wxBitmap" % (icon))
self.__magicImageListMapping [id (icon)] = index
return index
### Customisation point...
def GetIcon( self, node ):
'''Get the actual icon object for a node'''
if hasattr (node,"DIAGRAMICON"):
return node.DIAGRAMICON
## This file imports items from the wx package into the wxPython package for
## backwards compatibility. Some names will also have a 'wx' added on if
## that is how they used to be named in the old wxPython package.
import wx.lib.mixins.imagelist
__doc__ = wx.lib.mixins.imagelist.__doc__
MagicImageList = wx.lib.mixins.imagelist.MagicImageList

View File

@@ -1,322 +1,14 @@
#----------------------------------------------------------------------------
# Name: wxPython.lib.mixins.listctrl
# Purpose: Helpful mix-in classes for wxListCtrl
#
# Author: Robin Dunn
#
# Created: 15-May-2001
# RCS-ID: $Id$
# Copyright: (c) 2001 by Total Control Software
# Licence: wxWindows license
#----------------------------------------------------------------------------
## This file imports items from the wx package into the wxPython package for
## backwards compatibility. Some names will also have a 'wx' added on if
## that is how they used to be named in the old wxPython package.
from wxPython.wx import *
import locale
import wx.lib.mixins.listctrl
#----------------------------------------------------------------------------
__doc__ = wx.lib.mixins.listctrl.__doc__
class wxColumnSorterMixin:
"""
A mixin class that handles sorting of a wxListCtrl in REPORT mode when
the column header is clicked on.
ListCtrlSelectionManagerMix = wx.lib.mixins.listctrl.ListCtrlSelectionManagerMix
getListCtrlSelection = wx.lib.mixins.listctrl.getListCtrlSelection
selectBeforePopup = wx.lib.mixins.listctrl.selectBeforePopup
wxColumnSorterMixin = wx.lib.mixins.listctrl.wxColumnSorterMixin
wxListCtrlAutoWidthMixin = wx.lib.mixins.listctrl.wxListCtrlAutoWidthMixin
There are a few requirments needed in order for this to work genericly:
1. The combined class must have a GetListCtrl method that
returns the wxListCtrl to be sorted, and the list control
must exist at the time the wxColumnSorterMixin.__init__
method is called because it uses GetListCtrl.
2. Items in the list control must have a unique data value set
with list.SetItemData.
3. The combined class must have an attribute named itemDataMap
that is a dictionary mapping the data values to a sequence of
objects representing the values in each column. These values
are compared in the column sorter to determine sort order.
Interesting methods to override are GetColumnSorter,
GetSecondarySortValues, and GetSortImages. See below for details.
"""
def __init__(self, numColumns):
self.SetColumnCount(numColumns)
list = self.GetListCtrl()
if not list:
raise ValueError, "No wxListCtrl available"
EVT_LIST_COL_CLICK(list, list.GetId(), self.__OnColClick)
def SetColumnCount(self, newNumColumns):
self._colSortFlag = [0] * newNumColumns
self._col = -1
def SortListItems(self, col=-1, ascending=1):
"""Sort the list on demand. Can also be used to set the sort column and order."""
oldCol = self._col
if col != -1:
self._col = col
self._colSortFlag[col] = ascending
self.GetListCtrl().SortItems(self.GetColumnSorter())
self.__updateImages(oldCol)
def GetColumnWidths(self):
"""
Returns a list of column widths. Can be used to help restore the current
view later.
"""
list = self.GetListCtrl()
rv = []
for x in range(len(self._colSortFlag)):
rv.append(list.GetColumnWidth(x))
return rv
def GetSortImages(self):
"""
Returns a tuple of image list indexesthe indexes in the image list for an image to be put on the column
header when sorting in descending order.
"""
return (-1, -1) # (decending, ascending) image IDs
def GetColumnSorter(self):
"""Returns a callable object to be used for comparing column values when sorting."""
return self.__ColumnSorter
def GetSecondarySortValues(self, col, key1, key2):
"""Returns a tuple of 2 values to use for secondary sort values when the
items in the selected column match equal. The default just returns the
item data values."""
return (key1, key2)
def __OnColClick(self, evt):
oldCol = self._col
self._col = col = evt.GetColumn()
self._colSortFlag[col] = not self._colSortFlag[col]
self.GetListCtrl().SortItems(self.GetColumnSorter())
self.__updateImages(oldCol)
evt.Skip()
def __ColumnSorter(self, key1, key2):
col = self._col
ascending = self._colSortFlag[col]
item1 = self.itemDataMap[key1][col]
item2 = self.itemDataMap[key2][col]
#--- Internationalization of string sorting with locale module
if type(item1) == type('') or type(item2) == type(''):
cmpVal = locale.strcoll(str(item1), str(item2))
else:
cmpVal = cmp(item1, item2)
#---
# If the items are equal then pick something else to make the sort value unique
if cmpVal == 0:
cmpVal = apply(cmp, self.GetSecondarySortValues(col, key1, key2))
if ascending:
return cmpVal
else:
return -cmpVal
def __updateImages(self, oldCol):
sortImages = self.GetSortImages()
if self._col != -1 and sortImages[0] != -1:
img = sortImages[self._colSortFlag[self._col]]
list = self.GetListCtrl()
if oldCol != -1:
list.ClearColumnImage(oldCol)
list.SetColumnImage(self._col, img)
#----------------------------------------------------------------------------
#----------------------------------------------------------------------------
class wxListCtrlAutoWidthMixin:
""" A mix-in class that automatically resizes the last column to take up
the remaining width of the wxListCtrl.
This causes the wxListCtrl to automatically take up the full width of
the list, without either a horizontal scroll bar (unless absolutely
necessary) or empty space to the right of the last column.
NOTE: This only works for report-style lists.
WARNING: If you override the EVT_SIZE event in your wxListCtrl, make
sure you call event.Skip() to ensure that the mixin's
_OnResize method is called.
This mix-in class was written by Erik Westra <ewestra@wave.co.nz>
"""
def __init__(self):
""" Standard initialiser.
"""
self._lastColMinWidth = None
EVT_SIZE(self, self._onResize)
EVT_LIST_COL_END_DRAG(self, self.GetId(), self._onResize)
def resizeLastColumn(self, minWidth):
""" Resize the last column appropriately.
If the list's columns are too wide to fit within the window, we use
a horizontal scrollbar. Otherwise, we expand the right-most column
to take up the remaining free space in the list.
This method is called automatically when the wxListCtrl is resized;
you can also call it yourself whenever you want the last column to
be resized appropriately (eg, when adding, removing or resizing
columns).
'minWidth' is the preferred minimum width for the last column.
"""
self._lastColMinWidth = minWidth
self._doResize()
# =====================
# == Private Methods ==
# =====================
def _onResize(self, event):
""" Respond to the wxListCtrl being resized.
We automatically resize the last column in the list.
"""
wxCallAfter(self._doResize)
event.Skip()
def _doResize(self):
""" Resize the last column as appropriate.
If the list's columns are too wide to fit within the window, we use
a horizontal scrollbar. Otherwise, we expand the right-most column
to take up the remaining free space in the list.
We remember the current size of the last column, before resizing,
as the preferred minimum width if we haven't previously been given
or calculated a minimum width. This ensure that repeated calls to
_doResize() don't cause the last column to size itself too large.
"""
numCols = self.GetColumnCount()
if numCols == 0: return # Nothing to resize.
if self._lastColMinWidth == None:
self._lastColMinWidth = self.GetColumnWidth(numCols - 1)
# We're showing the vertical scrollbar -> allow for scrollbar width
# NOTE: on GTK, the scrollbar is included in the client size, but on
# Windows it is not included
listWidth = self.GetClientSize().width
if wxPlatform != '__WXMSW__':
if self.GetItemCount() > self.GetCountPerPage():
scrollWidth = wxSystemSettings_GetSystemMetric(wxSYS_VSCROLL_X)
listWidth = listWidth - scrollWidth
totColWidth = 0 # Width of all columns except last one.
for col in range(numCols-1):
totColWidth = totColWidth + self.GetColumnWidth(col)
lastColWidth = self.GetColumnWidth(numCols - 1)
if totColWidth + self._lastColMinWidth > listWidth:
# We haven't got the width to show the last column at its minimum
# width -> set it to its minimum width and allow the horizontal
# scrollbar to show.
self.SetColumnWidth(numCols-1, self._lastColMinWidth)
return
# Resize the last column to take up the remaining available space.
self.SetColumnWidth(numCols-1, listWidth - totColWidth)
#----------------------------------------------------------------------------
SEL_FOC = wxLIST_STATE_SELECTED | wxLIST_STATE_FOCUSED
def selectBeforePopup(event):
"""Ensures the item the mouse is pointing at is selected before a popup.
Works with both single-select and multi-select lists."""
ctrl = event.GetEventObject()
if isinstance(ctrl, wxListCtrl):
n, flags = ctrl.HitTest(event.GetPosition())
if n >= 0:
if not ctrl.GetItemState(n, wxLIST_STATE_SELECTED):
for i in range(ctrl.GetItemCount()):
ctrl.SetItemState(i, 0, SEL_FOC)
#for i in getListCtrlSelection(ctrl, SEL_FOC):
# ctrl.SetItemState(i, 0, SEL_FOC)
ctrl.SetItemState(n, SEL_FOC, SEL_FOC)
def getListCtrlSelection(listctrl, state=wxLIST_STATE_SELECTED):
""" Returns list of item indexes of given state (selected by defaults) """
res = []
idx = -1
while 1:
idx = listctrl.GetNextItem(idx, wxLIST_NEXT_ALL, state)
if idx == -1:
break
res.append(idx)
return res
class ListCtrlSelectionManagerMix:
"""Mixin that defines a platform independent selection policy
As selection single and multi-select list return the item index or a
list of item indexes respectively.
"""
wxEVT_DOPOPUPMENU = wxNewId()
_menu = None
def __init__(self):
EVT_RIGHT_DOWN(self, self.OnLCSMRightDown)
self.Connect(-1, -1, self.wxEVT_DOPOPUPMENU, self.OnLCSMDoPopup)
def getPopupMenu(self):
""" Override to implement dynamic menus (create) """
return self._menu
def setPopupMenu(self, menu):
""" Must be set for default behaviour """
self._menu = menu
def afterPopupMenu(self, menu):
""" Override to implement dynamic menus (destroy) """
pass
def getSelection(self):
res = getListCtrlSelection(self)
if self.GetWindowStyleFlag() & wxLC_SINGLE_SEL:
if res:
return res[0]
else:
return -1
else:
return res
def OnLCSMRightDown(self, event):
selectBeforePopup(event)
event.Skip()
menu = self.getPopupMenu()
if menu:
evt = wxPyEvent()
evt.SetEventType(self.wxEVT_DOPOPUPMENU)
evt.menu = menu
evt.pos = event.GetPosition()
wxPostEvent(self, evt)
def OnLCSMDoPopup(self, event):
self.PopupMenu(event.menu, event.pos)
self.afterPopupMenu(event.menu)
#----------------------------------------------------------------------

View File

@@ -1,396 +1,15 @@
#---------------------------------------------------------------------------
# Name: wxPython.lib.mixins.rubberband
# Purpose: A mixin class for doing "RubberBand"-ing on a window.
#
# Author: Robb Shecter and members of wxPython-users
#
# Created: 11-September-2002
# RCS-ID: $Id$
# Copyright: (c) 2002 by db-X Corporation
# Licence: wxWindows license
#---------------------------------------------------------------------------
## This file imports items from the wx package into the wxPython package for
## backwards compatibility. Some names will also have a 'wx' added on if
## that is how they used to be named in the old wxPython package.
"""
A mixin class for doing "RubberBand"-ing on a window.
"""
import wx.lib.mixins.rubberband
from wxPython.wx import *
__doc__ = wx.lib.mixins.rubberband.__doc__
#
# 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()
RubberBand = wx.lib.mixins.rubberband.RubberBand
boxToExtent = wx.lib.mixins.rubberband.boxToExtent
getCursorPosition = wx.lib.mixins.rubberband.getCursorPosition
isNegative = wx.lib.mixins.rubberband.isNegative
normalizeBox = wx.lib.mixins.rubberband.normalizeBox
pointInBox = wx.lib.mixins.rubberband.pointInBox
pointOnBox = wx.lib.mixins.rubberband.pointOnBox

View File

@@ -1,726 +1,16 @@
#----------------------------------------------------------------------
# Name: multisash
# Purpose: Multi Sash control
#
# Author: Gerrit van Dyk
#
# Created: 2002/11/20
# Version: 0.1
# RCS-ID: $Id$
# License: wxWindows licensie
#----------------------------------------------------------------------
from wxPython.wx import *
MV_HOR = 0
MV_VER = not MV_HOR
SH_SIZE = 5
CR_SIZE = SH_SIZE * 3
#----------------------------------------------------------------------
class wxMultiSash(wxWindow):
def __init__(self, *_args,**_kwargs):
apply(wxWindow.__init__,(self,) + _args,_kwargs)
self._defChild = EmptyChild
self.child = wxMultiSplit(self,self,wxPoint(0,0),self.GetSize())
EVT_SIZE(self,self.OnMultiSize)
def SetDefaultChildClass(self,childCls):
self._defChild = childCls
self.child.DefaultChildChanged()
def OnMultiSize(self,evt):
self.child.SetSize(self.GetSize())
def UnSelect(self):
self.child.UnSelect()
def Clear(self):
old = self.child
self.child = wxMultiSplit(self,self,wxPoint(0,0),self.GetSize())
old.Destroy()
self.child.OnSize(None)
def GetSaveData(self):
saveData = {}
saveData['_defChild'] = str(self._defChild)
saveData['child'] = self.child.GetSaveData()
return saveData
def SetSaveData(self,data):
dChild = data['_defChild']
mod = dChild.split('.')[0]
exec 'import %s' % mod
self._defChild = eval(dChild)
old = self.child
self.child = wxMultiSplit(self,self,wxPoint(0,0),self.GetSize())
self.child.SetSaveData(data['child'])
old.Destroy()
self.OnMultiSize(None)
self.child.OnSize(None)
#----------------------------------------------------------------------
class wxMultiSplit(wxWindow):
def __init__(self,multiView,parent,pos,size,view1 = None):
wxWindow.__init__(self,id = -1,parent = parent,pos = pos,size = size,
style = wxCLIP_CHILDREN)
self.multiView = multiView
self.view2 = None
if view1:
self.view1 = view1
self.view1.Reparent(self)
self.view1.MoveXY(0,0)
else:
self.view1 = wxMultiViewLeaf(self.multiView,self,
wxPoint(0,0),self.GetSize())
self.direction = None
EVT_SIZE(self,self.OnSize)
def GetSaveData(self):
saveData = {}
if self.view1:
saveData['view1'] = self.view1.GetSaveData()
if isinstance(self.view1,wxMultiSplit):
saveData['view1IsSplit'] = 1
if self.view2:
saveData['view2'] = self.view2.GetSaveData()
if isinstance(self.view2,wxMultiSplit):
saveData['view2IsSplit'] = 1
saveData['direction'] = self.direction
v1,v2 = self.GetPositionTuple()
saveData['x'] = v1
saveData['y'] = v2
v1,v2 = self.GetSizeTuple()
saveData['w'] = v1
saveData['h'] = v2
return saveData
def SetSaveData(self,data):
self.direction = data['direction']
self.SetDimensions(data['x'],data['y'],data['w'],data['h'])
v1Data = data.get('view1',None)
if v1Data:
isSplit = data.get('view1IsSplit',None)
old = self.view1
if isSplit:
self.view1 = wxMultiSplit(self.multiView,self,
wxPoint(0,0),self.GetSize())
else:
self.view1 = wxMultiViewLeaf(self.multiView,self,
wxPoint(0,0),self.GetSize())
self.view1.SetSaveData(v1Data)
if old:
old.Destroy()
v2Data = data.get('view2',None)
if v2Data:
isSplit = data.get('view2IsSplit',None)
old = self.view2
if isSplit:
self.view2 = wxMultiSplit(self.multiView,self,
wxPoint(0,0),self.GetSize())
else:
self.view2 = wxMultiViewLeaf(self.multiView,self,
wxPoint(0,0),self.GetSize())
self.view2.SetSaveData(v2Data)
if old:
old.Destroy()
if self.view1:
self.view1.OnSize(None)
if self.view2:
self.view2.OnSize(None)
def UnSelect(self):
if self.view1:
self.view1.UnSelect()
if self.view2:
self.view2.UnSelect()
def DefaultChildChanged(self):
if not self.view2:
self.view1.DefaultChildChanged()
def AddLeaf(self,direction,caller,pos):
if self.view2:
if caller == self.view1:
self.view1 = wxMultiSplit(self.multiView,self,
caller.GetPosition(),
caller.GetSize(),
caller)
self.view1.AddLeaf(direction,caller,pos)
else:
self.view2 = wxMultiSplit(self.multiView,self,
caller.GetPosition(),
caller.GetSize(),
caller)
self.view2.AddLeaf(direction,caller,pos)
else:
self.direction = direction
w,h = self.GetSizeTuple()
if direction == MV_HOR:
x,y = (pos,0)
w1,h1 = (w-pos,h)
w2,h2 = (pos,h)
else:
x,y = (0,pos)
w1,h1 = (w,h-pos)
w2,h2 = (w,pos)
self.view2 = wxMultiViewLeaf(self.multiView,self,
wxPoint(x,y),wxSize(w1,h1))
self.view1.SetSize(wxSize(w2,h2))
self.view2.OnSize(None)
def DestroyLeaf(self,caller):
if not self.view2: # We will only have 2 windows if
return # we need to destroy any
parent = self.GetParent() # Another splitview
if parent == self.multiView: # We'r at the root
if caller == self.view1:
old = self.view1
self.view1 = self.view2
self.view2 = None
old.Destroy()
else:
self.view2.Destroy()
self.view2 = None
self.view1.SetSize(self.GetSize())
self.view1.Move(self.GetPosition())
else:
w,h = self.GetSizeTuple()
x,y = self.GetPositionTuple()
if caller == self.view1:
if self == parent.view1:
parent.view1 = self.view2
else:
parent.view2 = self.view2
self.view2.Reparent(parent)
self.view2.SetDimensions(x,y,w,h)
else:
if self == parent.view1:
parent.view1 = self.view1
else:
parent.view2 = self.view1
self.view1.Reparent(parent)
self.view1.SetDimensions(x,y,w,h)
self.view1 = None
self.view2 = None
self.Destroy()
def CanSize(self,side,view):
if self.SizeTarget(side,view):
return True
return False
def SizeTarget(self,side,view):
if self.direction == side and self.view2 and view == self.view1:
return self
parent = self.GetParent()
if parent != self.multiView:
return parent.SizeTarget(side,self)
return None
def SizeLeaf(self,leaf,pos,side):
if self.direction != side:
return
if not (self.view1 and self.view2):
return
if pos < 10: return
w,h = self.GetSizeTuple()
if side == MV_HOR:
if pos > w - 10: return
else:
if pos > h - 10: return
if side == MV_HOR:
self.view1.SetDimensions(0,0,pos,h)
self.view2.SetDimensions(pos,0,w-pos,h)
else:
self.view1.SetDimensions(0,0,w,pos)
self.view2.SetDimensions(0,pos,w,h-pos)
def OnSize(self,evt):
if not self.view2:
self.view1.SetSize(self.GetSize())
self.view1.OnSize(None)
return
v1w,v1h = self.view1.GetSizeTuple()
v2w,v2h = self.view2.GetSizeTuple()
v1x,v1y = self.view1.GetPositionTuple()
v2x,v2y = self.view2.GetPositionTuple()
w,h = self.GetSizeTuple()
if v1x != v2x:
ratio = float(w) / float((v1w + v2w))
v1w *= ratio
v2w = w - v1w
v2x = v1w
else:
v1w = v2w = w
if v1y != v2y:
ratio = float(h) / float((v1h + v2h))
v1h *= ratio
v2h = h - v1h
v2y = v1h
else:
v1h = v2h = h
self.view1.SetDimensions(v1x,v1y,v1w,v1h)
self.view2.SetDimensions(v2x,v2y,v2w,v2h)
self.view1.OnSize(None)
self.view2.OnSize(None)
#----------------------------------------------------------------------
class wxMultiViewLeaf(wxWindow):
def __init__(self,multiView,parent,pos,size):
wxWindow.__init__(self,id = -1,parent = parent,pos = pos,size = size,
style = wxCLIP_CHILDREN)
self.multiView = multiView
self.sizerHor = MultiSizer(self,MV_HOR)
self.sizerVer = MultiSizer(self,MV_VER)
self.creatorHor = MultiCreator(self,MV_HOR)
self.creatorVer = MultiCreator(self,MV_VER)
self.detail = MultiClient(self,multiView._defChild)
self.closer = MultiCloser(self)
EVT_SIZE(self,self.OnSize)
def GetSaveData(self):
saveData = {}
saveData['detailClass'] = str(self.detail.child.__class__)
if hasattr(self.detail.child,'GetSaveData'):
attr = getattr(self.detail.child,'GetSaveData')
if callable(attr):
dData = attr()
if dData:
saveData['detail'] = dData
v1,v2 = self.GetPositionTuple()
saveData['x'] = v1
saveData['y'] = v2
v1,v2 = self.GetSizeTuple()
saveData['w'] = v1
saveData['h'] = v2
return saveData
def SetSaveData(self,data):
dChild = data['detailClass']
mod = dChild.split('.')[0]
exec 'import %s' % mod
detClass = eval(dChild)
self.SetDimensions(data['x'],data['y'],data['w'],data['h'])
old = self.detail
self.detail = MultiClient(self,detClass)
dData = data.get('detail',None)
if dData:
if hasattr(self.detail.child,'SetSaveData'):
attr = getattr(self.detail.child,'SetSaveData')
if callable(attr):
attr(dData)
old.Destroy()
self.detail.OnSize(None)
def UnSelect(self):
self.detail.UnSelect()
def DefaultChildChanged(self):
self.detail.SetNewChildCls(self.multiView._defChild)
def AddLeaf(self,direction,pos):
if pos < 10: return
w,h = self.GetSizeTuple()
if direction == MV_VER:
if pos > h - 10: return
else:
if pos > w - 10: return
self.GetParent().AddLeaf(direction,self,pos)
def DestroyLeaf(self):
self.GetParent().DestroyLeaf(self)
def SizeTarget(self,side):
return self.GetParent().SizeTarget(side,self)
def CanSize(self,side):
return self.GetParent().CanSize(side,self)
def OnSize(self,evt):
self.sizerHor.OnSize(evt)
self.sizerVer.OnSize(evt)
self.creatorHor.OnSize(evt)
self.creatorVer.OnSize(evt)
self.detail.OnSize(evt)
self.closer.OnSize(evt)
#----------------------------------------------------------------------
class MultiClient(wxWindow):
def __init__(self,parent,childCls):
w,h = self.CalcSize(parent)
wxWindow.__init__(self,id = -1,parent = parent,
pos = wxPoint(0,0),
size = wxSize(w,h),
style = wxCLIP_CHILDREN | wxSUNKEN_BORDER)
self.child = childCls(self)
self.child.MoveXY(2,2)
self.normalColour = self.GetBackgroundColour()
self.selected = False
EVT_SET_FOCUS(self,self.OnSetFocus)
EVT_CHILD_FOCUS(self,self.OnChildFocus)
def UnSelect(self):
if self.selected:
self.selected = False
self.SetBackgroundColour(self.normalColour)
self.Refresh()
def Select(self):
self.GetParent().multiView.UnSelect()
self.selected = True
self.SetBackgroundColour(wxColour(255,255,0)) # Yellow
self.Refresh()
def CalcSize(self,parent):
w,h = parent.GetSizeTuple()
w -= SH_SIZE
h -= SH_SIZE
return (w,h)
def OnSize(self,evt):
w,h = self.CalcSize(self.GetParent())
self.SetDimensions(0,0,w,h)
w,h = self.GetClientSizeTuple()
self.child.SetSize(wxSize(w-4,h-4))
def SetNewChildCls(self,childCls):
if self.child:
self.child.Destroy()
self.child = None
self.child = childCls(self)
self.child.MoveXY(2,2)
def OnSetFocus(self,evt):
self.Select()
def OnChildFocus(self,evt):
self.OnSetFocus(evt)
## from Funcs import FindFocusedChild
## child = FindFocusedChild(self)
## EVT_KILL_FOCUS(child,self.OnChildKillFocus)
#----------------------------------------------------------------------
class MultiSizer(wxWindow):
def __init__(self,parent,side):
self.side = side
x,y,w,h = self.CalcSizePos(parent)
wxWindow.__init__(self,id = -1,parent = parent,
pos = wxPoint(x,y),
size = wxSize(w,h),
style = wxCLIP_CHILDREN)
self.px = None # Previous X
self.py = None # Previous Y
self.isDrag = False # In Dragging
self.dragTarget = None # View being sized
EVT_LEAVE_WINDOW(self,self.OnLeave)
EVT_ENTER_WINDOW(self,self.OnEnter)
EVT_MOTION(self,self.OnMouseMove)
EVT_LEFT_DOWN(self,self.OnPress)
EVT_LEFT_UP(self,self.OnRelease)
def CalcSizePos(self,parent):
pw,ph = parent.GetSizeTuple()
if self.side == MV_HOR:
x = CR_SIZE + 2
y = ph - SH_SIZE
w = pw - CR_SIZE - SH_SIZE - 2
h = SH_SIZE
else:
x = pw - SH_SIZE
y = CR_SIZE + 2 + SH_SIZE
w = SH_SIZE
h = ph - CR_SIZE - SH_SIZE - 4 - SH_SIZE # For Closer
return (x,y,w,h)
def OnSize(self,evt):
x,y,w,h = self.CalcSizePos(self.GetParent())
self.SetDimensions(x,y,w,h)
def OnLeave(self,evt):
self.SetCursor(wxStockCursor(wxCURSOR_ARROW))
def OnEnter(self,evt):
if not self.GetParent().CanSize(not self.side):
return
if self.side == MV_HOR:
self.SetCursor(wxStockCursor(wxCURSOR_SIZENS))
else:
self.SetCursor(wxStockCursor(wxCURSOR_SIZEWE))
def OnMouseMove(self,evt):
if self.isDrag:
DrawSash(self.dragTarget,self.px,self.py,self.side)
self.px,self.py = self.ClientToScreenXY(evt.m_x,evt.m_y)
self.px,self.py = self.dragTarget.ScreenToClientXY(self.px,self.py)
DrawSash(self.dragTarget,self.px,self.py,self.side)
else:
evt.Skip()
def OnPress(self,evt):
self.dragTarget = self.GetParent().SizeTarget(not self.side)
if self.dragTarget:
self.isDrag = True
self.px,self.py = self.ClientToScreenXY(evt.m_x,evt.m_y)
self.px,self.py = self.dragTarget.ScreenToClientXY(self.px,self.py)
DrawSash(self.dragTarget,self.px,self.py,self.side)
self.CaptureMouse()
else:
evt.Skip()
def OnRelease(self,evt):
if self.isDrag:
DrawSash(self.dragTarget,self.px,self.py,self.side)
self.ReleaseMouse()
self.isDrag = False
if self.side == MV_HOR:
self.dragTarget.SizeLeaf(self.GetParent(),
self.py,not self.side)
else:
self.dragTarget.SizeLeaf(self.GetParent(),
self.px,not self.side)
self.dragTarget = None
else:
evt.Skip()
#----------------------------------------------------------------------
class MultiCreator(wxWindow):
def __init__(self,parent,side):
self.side = side
x,y,w,h = self.CalcSizePos(parent)
wxWindow.__init__(self,id = -1,parent = parent,
pos = wxPoint(x,y),
size = wxSize(w,h),
style = wxCLIP_CHILDREN)
self.px = None # Previous X
self.py = None # Previous Y
self.isDrag = False # In Dragging
EVT_LEAVE_WINDOW(self,self.OnLeave)
EVT_ENTER_WINDOW(self,self.OnEnter)
EVT_MOTION(self,self.OnMouseMove)
EVT_LEFT_DOWN(self,self.OnPress)
EVT_LEFT_UP(self,self.OnRelease)
EVT_PAINT(self,self.OnPaint)
def CalcSizePos(self,parent):
pw,ph = parent.GetSizeTuple()
if self.side == MV_HOR:
x = 2
y = ph - SH_SIZE
w = CR_SIZE
h = SH_SIZE
else:
x = pw - SH_SIZE
y = 4 + SH_SIZE # Make provision for closer
w = SH_SIZE
h = CR_SIZE
return (x,y,w,h)
def OnSize(self,evt):
x,y,w,h = self.CalcSizePos(self.GetParent())
self.SetDimensions(x,y,w,h)
def OnLeave(self,evt):
self.SetCursor(wxStockCursor(wxCURSOR_ARROW))
def OnEnter(self,evt):
if self.side == MV_HOR:
self.SetCursor(wxStockCursor(wxCURSOR_HAND))
else:
self.SetCursor(wxStockCursor(wxCURSOR_POINT_LEFT))
def OnMouseMove(self,evt):
if self.isDrag:
parent = self.GetParent()
DrawSash(parent,self.px,self.py,self.side)
self.px,self.py = self.ClientToScreenXY(evt.m_x,evt.m_y)
self.px,self.py = parent.ScreenToClientXY(self.px,self.py)
DrawSash(parent,self.px,self.py,self.side)
else:
evt.Skip()
def OnPress(self,evt):
self.isDrag = True
parent = self.GetParent()
self.px,self.py = self.ClientToScreenXY(evt.m_x,evt.m_y)
self.px,self.py = parent.ScreenToClientXY(self.px,self.py)
DrawSash(parent,self.px,self.py,self.side)
self.CaptureMouse()
def OnRelease(self,evt):
if self.isDrag:
parent = self.GetParent()
DrawSash(parent,self.px,self.py,self.side)
self.ReleaseMouse()
self.isDrag = False
if self.side == MV_HOR:
parent.AddLeaf(MV_VER,self.py)
else:
parent.AddLeaf(MV_HOR,self.px)
else:
evt.Skip()
def OnPaint(self,evt):
dc = wxPaintDC(self)
dc.SetBackground(wxBrush(self.GetBackgroundColour(),wxSOLID))
dc.Clear()
highlight = wxPen(wxSystemSettings_GetSystemColour(
wxSYS_COLOUR_BTNHIGHLIGHT),1,wxSOLID)
shadow = wxPen(wxSystemSettings_GetSystemColour(
wxSYS_COLOUR_BTNSHADOW),1,wxSOLID)
black = wxPen(wxBLACK,1,wxSOLID)
w,h = self.GetSizeTuple()
w -= 1
h -= 1
# Draw outline
dc.SetPen(highlight)
dc.DrawLine(0,0,0,h)
dc.DrawLine(0,0,w,0)
dc.SetPen(black)
dc.DrawLine(0,h,w+1,h)
dc.DrawLine(w,0,w,h)
dc.SetPen(shadow)
dc.DrawLine(w-1,2,w-1,h)
#----------------------------------------------------------------------
class MultiCloser(wxWindow):
def __init__(self,parent):
x,y,w,h = self.CalcSizePos(parent)
wxWindow.__init__(self,id = -1,parent = parent,
pos = wxPoint(x,y),
size = wxSize(w,h),
style = wxCLIP_CHILDREN)
self.down = False
self.entered = False
EVT_LEFT_DOWN(self,self.OnPress)
EVT_LEFT_UP(self,self.OnRelease)
EVT_PAINT(self,self.OnPaint)
EVT_LEAVE_WINDOW(self,self.OnLeave)
EVT_ENTER_WINDOW(self,self.OnEnter)
def OnLeave(self,evt):
self.SetCursor(wxStockCursor(wxCURSOR_ARROW))
self.entered = False
def OnEnter(self,evt):
self.SetCursor(wxStockCursor(wxCURSOR_BULLSEYE))
self.entered = True
def OnPress(self,evt):
self.down = True
evt.Skip()
def OnRelease(self,evt):
if self.down and self.entered:
self.GetParent().DestroyLeaf()
else:
evt.Skip()
self.down = False
def OnPaint(self,evt):
dc = wxPaintDC(self)
dc.SetBackground(wxBrush(wxRED,wxSOLID))
dc.Clear()
def CalcSizePos(self,parent):
pw,ph = parent.GetSizeTuple()
x = pw - SH_SIZE
w = SH_SIZE
h = SH_SIZE + 2
y = 1
return (x,y,w,h)
def OnSize(self,evt):
x,y,w,h = self.CalcSizePos(self.GetParent())
self.SetDimensions(x,y,w,h)
#----------------------------------------------------------------------
class EmptyChild(wxWindow):
def __init__(self,parent):
wxWindow.__init__(self,parent,-1, style = wxCLIP_CHILDREN)
#----------------------------------------------------------------------
def DrawSash(win,x,y,direction):
dc = wxScreenDC()
dc.StartDrawingOnTopWin(win)
bmp = wxEmptyBitmap(8,8)
bdc = wxMemoryDC()
bdc.SelectObject(bmp)
bdc.DrawRectangle(-1,-1,10,10)
for i in range(8):
for j in range(8):
if ((i + j) & 1):
bdc.DrawPoint(i,j)
brush = wxBrush(wxColour(0,0,0))
brush.SetStipple(bmp)
dc.SetBrush(brush)
dc.SetLogicalFunction(wxXOR)
body_w,body_h = win.GetClientSizeTuple()
if y < 0:
y = 0
if y > body_h:
y = body_h
if x < 0:
x = 0
if x > body_w:
x = body_w
if direction == MV_HOR:
x = 0
else:
y = 0
x,y = win.ClientToScreenXY(x,y)
w = body_w
h = body_h
if direction == MV_HOR:
dc.DrawRectangle(x,y-2,w,4)
else:
dc.DrawRectangle(x-2,y,4,h)
dc.EndDrawingOnTop()
## This file imports items from the wx package into the wxPython package for
## backwards compatibility. Some names will also have a 'wx' added on if
## that is how they used to be named in the old wxPython package.
import wx.lib.multisash
__doc__ = wx.lib.multisash.__doc__
EmptyChild = wx.lib.multisash.EmptyChild
MultiClient = wx.lib.multisash.MultiClient
MultiCloser = wx.lib.multisash.MultiCloser
MultiCreator = wx.lib.multisash.MultiCreator
MultiSizer = wx.lib.multisash.MultiSizer
wxMultiSash = wx.lib.multisash.wxMultiSash
wxMultiSplit = wx.lib.multisash.wxMultiSplit
wxMultiViewLeaf = wx.lib.multisash.wxMultiViewLeaf

File diff suppressed because it is too large Load Diff

View File

@@ -1,122 +1,11 @@
#!/usr/bin/env python
"""Easy generation of new events classes and binder functions"""
## This file imports items from the wx package into the wxPython package for
## backwards compatibility. Some names will also have a 'wx' added on if
## that is how they used to be named in the old wxPython package.
__author__ = "Miki Tebeka <tebeka@cs.bgu.ac.il>"
import wx.lib.newevent
import wx
__doc__ = wx.lib.newevent.__doc__
#---------------------------------------------------------------------------
def NewEvent():
"""Generate new (Event, Binder) tuple
e.g. MooEvent, EVT_MOO = NewEvent()
"""
evttype = wx.NewEventType()
class _Event(wx.PyEvent):
def __init__(self, **kw):
wx.PyEvent.__init__(self)
self.SetEventType(evttype)
self.__dict__.update(kw)
def Binder(win, func):
win.Connect(-1, -1, evttype, func)
return _Event, Binder
def NewCommandEvent():
"""Generate new (CmdEvent, Binder) tuple
e.g. MooCmdEvent, EVT_MOO = NewCommandEvent()
"""
evttype = wx.NewEventType()
class _Event(wx.PyCommandEvent):
def __init__(self, id, **kw):
wx.PyCommandEvent.__init__(self, evttype, id)
self.__dict__.update(kw)
def Binder(win, id, func):
win.Connect(id, -1, evttype, func)
return _Event, Binder
#---------------------------------------------------------------------------
def _test():
"""A little smoke test"""
from threading import Thread
from time import sleep
MooEvent, EVT_MOO = NewEvent()
GooEvent, EVT_GOO = NewCommandEvent()
DELAY = 0.7
def evt_thr(win):
sleep(DELAY)
wx.PostEvent(win, MooEvent(moo=1))
def cmd_thr(win, id):
sleep(DELAY)
wx.PostEvent(win, GooEvent(id, goo=id))
ID_CMD1 = wx.NewId()
ID_CMD2 = wx.NewId()
class Frame(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, None, -1, "MOO")
sizer = wx.BoxSizer(wx.VERTICAL)
EVT_MOO(self, self.on_moo)
b = wx.Button(self, -1, "Generate MOO")
sizer.Add(b, 1, wx.EXPAND)
wx.EVT_BUTTON(self, b.GetId(), self.on_evt_click)
b = wx.Button(self, ID_CMD1, "Generate GOO with %d" % ID_CMD1)
sizer.Add(b, 1, wx.EXPAND)
wx.EVT_BUTTON(self, ID_CMD1, self.on_cmd_click)
b = wx.Button(self, ID_CMD2, "Generate GOO with %d" % ID_CMD2)
sizer.Add(b, 1, wx.EXPAND)
wx.EVT_BUTTON(self, ID_CMD2, self.on_cmd_click)
EVT_GOO(self, ID_CMD1, self.on_cmd1)
EVT_GOO(self, ID_CMD2, self.on_cmd2)
self.SetSizer(sizer)
self.SetAutoLayout(True)
sizer.Fit(self)
def on_evt_click(self, e):
t = Thread(target=evt_thr, args=(self, ))
t.setDaemon(True)
t.start()
def on_cmd_click(self, e):
t = Thread(target=cmd_thr, args=(self, e.GetId()))
t.setDaemon(True)
t.start()
def show(self, msg, title):
dlg = wx.MessageDialog(self, msg, title, wx.OK)
dlg.ShowModal()
dlg.Destroy()
def on_moo(self, e):
self.show("MOO = %s" % e.moo, "Got Moo")
def on_cmd1(self, e):
self.show("goo = %s" % e.goo, "Got Goo (cmd1)")
def on_cmd2(self, e):
self.show("goo = %s" % e.goo, "Got Goo (cmd2)")
app = wx.PySimpleApp()
f = Frame()
f.Show(True)
app.MainLoop()
if __name__ == "__main__":
_test()
NewCommandEvent = wx.lib.newevent.NewCommandEvent
NewEvent = wx.lib.newevent.NewEvent
_test = wx.lib.newevent._test

View File

@@ -1,249 +1,12 @@
#----------------------------------------------------------------------
# Name: popup
# Purpose: Generic popup control
#
# Author: Gerrit van Dyk
#
# Created: 2002/11/20
# Version: 0.1
# RCS-ID: $Id$
# License: wxWindows license
#----------------------------------------------------------------------
## This file imports items from the wx package into the wxPython package for
## backwards compatibility. Some names will also have a 'wx' added on if
## that is how they used to be named in the old wxPython package.
from wxPython.wx import *
from wxPython.lib.buttons import wxGenButtonEvent
import wx.lib.popupctl
__doc__ = wx.lib.popupctl.__doc__
class PopButton(wxPyControl):
def __init__(self,*_args,**_kwargs):
apply(wxPyControl.__init__,(self,) + _args,_kwargs)
self.up = True
self.didDown = False
self.InitColours()
EVT_LEFT_DOWN(self, self.OnLeftDown)
EVT_LEFT_UP(self, self.OnLeftUp)
EVT_MOTION(self, self.OnMotion)
EVT_PAINT(self, self.OnPaint)
def InitColours(self):
faceClr = wxSystemSettings_GetSystemColour(wxSYS_COLOUR_BTNFACE)
self.faceDnClr = faceClr
self.SetBackgroundColour(faceClr)
shadowClr = wxSystemSettings_GetSystemColour(wxSYS_COLOUR_BTNSHADOW)
highlightClr = wxSystemSettings_GetSystemColour(wxSYS_COLOUR_BTNHIGHLIGHT)
self.shadowPen = wxPen(shadowClr, 1, wxSOLID)
self.highlightPen = wxPen(highlightClr, 1, wxSOLID)
self.blackPen = wxPen(wxBLACK, 1, wxSOLID)
def Notify(self):
evt = wxGenButtonEvent(wxEVT_COMMAND_BUTTON_CLICKED, self.GetId())
evt.SetIsDown(not self.up)
evt.SetButtonObj(self)
evt.SetEventObject(self)
self.GetEventHandler().ProcessEvent(evt)
def OnEraseBackground(self, event):
pass
def OnLeftDown(self, event):
if not self.IsEnabled():
return
self.didDown = True
self.up = False
self.CaptureMouse()
self.GetParent().textCtrl.SetFocus()
self.Refresh()
event.Skip()
def OnLeftUp(self, event):
if not self.IsEnabled():
return
if self.didDown:
self.ReleaseMouse()
if not self.up:
self.Notify()
self.up = True
self.Refresh()
self.didDown = False
event.Skip()
def OnMotion(self, event):
if not self.IsEnabled():
return
if event.LeftIsDown():
if self.didDown:
x,y = event.GetPositionTuple()
w,h = self.GetClientSizeTuple()
if self.up and x<w and x>=0 and y<h and y>=0:
self.up = False
self.Refresh()
return
if not self.up and (x<0 or y<0 or x>=w or y>=h):
self.up = True
self.Refresh()
return
event.Skip()
def DrawBezel(self, dc, x1, y1, x2, y2):
# draw the upper left sides
if self.up:
dc.SetPen(self.highlightPen)
else:
dc.SetPen(self.shadowPen)
for i in range(2):
dc.DrawLine(x1+i, y1, x1+i, y2-i)
dc.DrawLine(x1, y1+i, x2-i, y1+i)
# draw the lower right sides
if self.up:
dc.SetPen(self.shadowPen)
else:
dc.SetPen(self.highlightPen)
for i in range(2):
dc.DrawLine(x1+i, y2-i, x2+1, y2-i)
dc.DrawLine(x2-i, y1+i, x2-i, y2)
def DrawArrow(self,dc):
size = self.GetSize()
mx = size.x / 2
my = size.y / 2
dc.SetPen(self.highlightPen)
dc.DrawLine(mx-5,my-5,mx+5,my-5)
dc.DrawLine(mx-5,my-5,mx,my+5)
dc.SetPen(self.shadowPen)
dc.DrawLine(mx+4,my-5,mx,my+5)
dc.SetPen(self.blackPen)
dc.DrawLine(mx+5,my-5,mx,my+5)
def OnPaint(self, event):
width, height = self.GetClientSizeTuple()
x1 = y1 = 0
x2 = width - 1
y2 = height - 1
dc = wxBufferedPaintDC(self)
if self.up:
dc.SetBackground(wxBrush(self.GetBackgroundColour(), wxSOLID))
else:
dc.SetBackground(wxBrush(self.faceDnClr, wxSOLID))
dc.Clear()
self.DrawBezel(dc, x1, y1, x2, y2)
self.DrawArrow(dc)
#---------------------------------------------------------------------------
# Tried to use wxPopupWindow but the control misbehaves on MSW
class wxPopupDialog(wxDialog):
def __init__(self,parent,content = None):
wxDialog.__init__(self,parent,-1,'', style = wxBORDER_SIMPLE|wxSTAY_ON_TOP)
self.ctrl = parent
self.win = wxWindow(self,-1,pos = wxPoint(0,0),style = 0)
if content:
self.SetContent(content)
def SetContent(self,content):
self.content = content
self.content.Reparent(self.win)
self.content.Show(True)
self.win.SetClientSize(self.content.GetSize())
self.SetSize(self.win.GetSize())
def Display(self):
pos = self.ctrl.ClientToScreen( (0,0) )
dSize = wxGetDisplaySize()
selfSize = self.GetSize()
tcSize = self.ctrl.GetSize()
pos.x -= (selfSize.x - tcSize.x) / 2
if pos.x + selfSize.x > dSize.x:
pos.x = dSize.x - selfSize.x
if pos.x < 0:
pos.x = 0
pos.y += tcSize.height
if pos.y + selfSize.y > dSize.y:
pos.y = dSize.y - selfSize.y
if pos.y < 0:
pos.y = 0
self.MoveXY(pos.x,pos.y)
self.ctrl.FormatContent()
self.ShowModal()
#---------------------------------------------------------------------------
class wxPopupControl(wxPyControl):
def __init__(self,*_args,**_kwargs):
if _kwargs.has_key('value'):
del _kwargs['value']
apply(wxPyControl.__init__,(self,) + _args,_kwargs)
self.textCtrl = wxTextCtrl(self,-1,'',pos = wxPoint(0,0))
self.bCtrl = PopButton(self,-1)
self.pop = None
self.content = None
self.OnSize(None)
EVT_SIZE(self,self.OnSize)
EVT_BUTTON(self.bCtrl,self.bCtrl.GetId(),self.OnButton)
# embedded control should get focus on TAB keypress
EVT_SET_FOCUS(self,self.OnFocus)
def OnFocus(self,evt):
self.textCtrl.SetFocus()
evt.Skip()
def OnSize(self,evt):
w,h = self.GetClientSizeTuple()
self.textCtrl.SetDimensions(0,0,w-17,h)
self.bCtrl.SetDimensions(w-17,0,17,h)
def OnButton(self,evt):
if not self.pop:
if self.content:
self.pop = wxPopupDialog(self,self.content)
del self.content
else:
print 'No Content to pop'
if self.pop:
self.pop.Display()
def Enable(self,flag):
wxPyControl.Enable(self,flag)
self.textCtrl.Enable(flag)
self.bCtrl.Enable(flag)
def SetPopupContent(self,content):
if not self.pop:
self.content = content
self.content.Show(False)
else:
self.pop.SetContent(content)
def FormatContent(self):
pass
def PopDown(self):
if self.pop:
self.pop.EndModal(1)
def SetValue(self,value):
self.textCtrl.SetValue(value)
def GetValue(self):
return self.textCtrl.GetValue()
# an alias
wxPopupCtrl = wxPopupControl
PopButton = wx.lib.popupctl.PopButton
wxPopupControl = wx.lib.popupctl.wxPopupControl
wxPopupCtrl = wx.lib.popupctl.wxPopupCtrl
wxPopupDialog = wx.lib.popupctl.wxPopupDialog

File diff suppressed because it is too large Load Diff

View File

@@ -1,382 +1,10 @@
#---------------------------------------------------------------------------
# Name: wxPython.lib.pubsub
# Purpose: The Publish/Subscribe framework used by evtmgr.EventManager
#
# Author: Robb Shecter and Robin Dunn
#
# Created: 12-December-2002
# RCS-ID: $Id$
# Copyright: (c) 2002 by db-X Corporation
# Licence: wxWindows license
#---------------------------------------------------------------------------
"""
This module has classes for implementing the Publish/Subscribe design
pattern.
## This file imports items from the wx package into the wxPython package for
## backwards compatibility. Some names will also have a 'wx' added on if
## that is how they used to be named in the old wxPython package.
It's a very flexible PS implementation: The message topics are tuples
of any length, containing any objects (that can be used as hash keys).
A subscriber's topic matches any message topic for which it's a
sublist.
import wx.lib.pubsub
It also has many optimizations to favor time efficiency (ie., run-time
speed). I did this because I use it to support extreme uses. For
example, piping every wxWindows mouse event through to multiple
listeners, and expecting the app to have no noticeable slowdown. This
has made the code somewhat obfuscated, but I've done my best to
document it.
__doc__ = wx.lib.pubsub.__doc__
The Server and Message classes are the two that clients interact
with..
This module is compatible with Python 2.1.
Author: Robb Shecter
"""
#---------------------------------------------------------------------------
class Publisher:
"""
The publish/subscribe server. This class is a Singleton.
"""
def __init__(self):
self.topicDict = {}
self.functionDict = {}
self.subscribeAllList = []
self.messageCount = 0
self.deliveryCount = 0
#
# Public API
#
def subscribe(self, topic, listener):
"""
Add the given subscription to the list. This will
add an entry recording the fact that the listener wants
to get messages for (at least) the given topic. This
method may be called multiple times for one listener,
registering it with many topics. It can also be invoked
many times for a particular topic, each time with a
different listener.
listener: expected to be either a method or function that
takes zero or one parameters. (Not counting 'self' in the
case of methods. If it accepts a parameter, it will be given
a reference to a Message object.
topic: will be converted to a tuple if it isn't one.
It's a pattern matches any topic that it's a sublist
of. For example, this pattern:
('sports',)
would match these:
('sports',)
('sports', 'baseball')
('sports', 'baseball', 'highscores')
but not these:
()
('news')
(12345)
"""
if not callable(listener):
raise TypeError('The P/S listener, '+`listener`+', is not callable.')
aTopic = Topic(topic)
# Determine now (at registration time) how many parameters
# the listener expects, and get a reference to a function which
# calls it correctly at message-send time.
callableVersion = self.__makeCallable(listener)
# Add this tuple to a list which is in a dict keyed by
# the topic's first element.
self.__addTopicToCorrectList(aTopic, listener, callableVersion)
# Add to a dict in order to speed-up unsubscribing.
self.__addFunctionLookup(listener, aTopic)
def unsubscribe(self, listener):
"""
Remove the given listener from the registry,
for all topics that it's associated with.
"""
if not callable(listener):
raise TypeError('The P/S listener, '+`listener`+', is not callable.')
topicList = self.getAssociatedTopics(listener)
for aTopic in topicList:
subscriberList = self.__getTopicList(aTopic)
listToKeep = []
for subscriber in subscriberList:
if subscriber[0] != listener:
listToKeep.append(subscriber)
self.__setTopicList(aTopic, listToKeep)
self.__delFunctionLookup(listener)
def getAssociatedTopics(self, listener):
"""
Return a list of topics the given listener is
registered with.
"""
return self.functionDict.get(listener, [])
def sendMessage(self, topic, data=None):
"""
Relay a message to registered listeners.
"""
aTopic = Topic(topic)
message = Message(aTopic.items, data)
topicList = self.__getTopicList(aTopic)
# Send to the matching topics
for subscriber in topicList:
if subscriber[1].matches(aTopic):
subscriber[2](message)
# Send to any listeners registered for ALL
for subscriber in self.subscribeAllList:
subscriber[2](message)
#
# Private methods
#
def __makeCallable(self, function):
"""
Return a function that is what the server
will actually call.
This is a time optimization: this removes a test
for the number of parameters from the inner loop
of sendMessage().
"""
parameters = self.__parameterCount(function)
if parameters == 0:
# Return a function that calls the listener
# with no arguments.
return lambda m, f=function: f()
elif parameters == 1:
# Return a function that calls the listener
# with one argument (which will be the message).
return lambda m, f=function: f(m)
else:
raise TypeError('The publish/subscribe listener, '+`function`+', has wrong parameter count')
def __parameterCount(self, callableObject):
"""
Return the effective number of parameters required
by the callable object. In other words, the 'self'
parameter of methods is not counted.
"""
try:
# Try to handle this like a method
return callableObject.im_func.func_code.co_argcount - 1
except AttributeError:
pass
try:
# Try to handle this like a function
return callableObject.func_code.co_argcount
except AttributeError:
raise 'Cannot determine if this is a method or function: '+str(callableObject)
def __addFunctionLookup(self, aFunction, aTopic):
try:
aList = self.functionDict[aFunction]
except KeyError:
aList = []
self.functionDict[aFunction] = aList
aList.append(aTopic)
def __delFunctionLookup(self, aFunction):
try:
del self.functionDict[aFunction]
except KeyError:
print 'Warning: listener not found. Logic error in PublishSubscribe?', aFunction
def __addTopicToCorrectList(self, topic, listener, callableVersion):
if len(topic.items) == 0:
self.subscribeAllList.append((listener, topic, callableVersion))
else:
self.__getTopicList(topic).append((listener, topic, callableVersion))
def __getTopicList(self, aTopic):
"""
Return the correct sublist of subscribers based on the
given topic.
"""
try:
elementZero = aTopic.items[0]
except IndexError:
return self.subscribeAllList
try:
subList = self.topicDict[elementZero]
except KeyError:
subList = []
self.topicDict[elementZero] = subList
return subList
def __setTopicList(self, aTopic, aSubscriberList):
try:
self.topicDict[aTopic.items[0]] = aSubscriberList
except IndexError:
self.subscribeAllList = aSubscriberList
def __call__(self):
return self
# Create an instance with the same name as the class, effectivly
# hiding the class object so it can't be instantiated any more. From
# this point forward any calls to Publisher() will invoke the __call__
# of this instance which just returns itself.
#
# The only flaw with this approach is that you can't derive a new
# class from Publisher without jumping through hoops. If this ever
# becomes an issue then a new Singleton implementaion will need to be
# employed.
Publisher = Publisher()
#---------------------------------------------------------------------------
class Message:
"""
A simple container object for the two components of
a message; the topic and the data.
"""
def __init__(self, topic, data):
self.topic = topic
self.data = data
def __str__(self):
return '[Topic: '+`self.topic`+', Data: '+`self.data`+']'
#---------------------------------------------------------------------------
class Topic:
"""
A class that represents a publish/subscribe topic.
Currently, it's only used internally in the framework; the
API expects and returns plain old tuples.
It currently exists mostly as a place to keep the matches()
function. This function, though, could also correctly be
seen as an attribute of the P/S server. Getting rid of this
class would also mean one fewer object instantiation per
message send.
"""
listType = type([])
tupleType = type(())
def __init__(self, items):
# Make sure we have a tuple.
if type(items) == self.__class__.listType:
items = tuple(items)
elif type(items) != self.__class__.tupleType:
items = (items,)
self.items = items
self.length = len(items)
def matches(self, aTopic):
"""
Consider myself to be a topic pattern,
and return True if I match the given specific
topic. For example,
a = ('sports')
b = ('sports','baseball')
a.matches(b) --> 1
b.matches(a) --> 0
"""
# The question this method answers is equivalent to;
# is my list a sublist of aTopic's? So, my algorithm
# is: 1) make a copy of the aTopic list which is
# truncated to the pattern's length. 2) Test for
# equality.
#
# This algorithm may be somewhat memory-intensive,
# because it creates a temporary list on each
# call to match. A possible to-do would be to
# re-write this with a hand-coded loop.
return (self.items == aTopic.items[:self.length])
def __repr__(self):
import string
return '<Topic>' + string.join(map(repr, self.items), ', ') + '</Topic>'
def __eq__(self, aTopic):
"""
Return True if I equal the given topic. We're considered
equal if our tuples are equal.
"""
if type(self) != type(aTopic):
return 0
else:
return self.items == aTopic.items
def __ne__(self, aTopic):
"""
Return False if I equal the given topic.
"""
return not self == aTopic
#---------------------------------------------------------------------------
#
# Code for a simple command-line test
#
if __name__ == '__main__':
class SimpleListener:
def __init__(self, number):
self.number = number
def notify(self, message):
print '#'+str(self.number)+' got the message:', message
# Build a list of ten listeners.
lList = []
for x in range(10):
lList.append(SimpleListener(x))
server = Publisher()
# Everyone's interested in politics...
for x in lList:
Publisher().subscribe(topic='politics', listener=x.notify) # also tests singleton
# But only the first four are interested in trivia.
for x in lList[:4]:
server.subscribe(topic='trivia', listener=x.notify)
# This one subscribes to everything.
everythingListener = SimpleListener(999)
server.subscribe(topic=(), listener=everythingListener.notify)
# Now send out two messages, testing topic matching.
server.sendMessage(topic='trivia', data='What is the capitol of Oregon?')
server.sendMessage(topic=('politics','germany'), data='The Greens have picked up another seat in the Bundestag.')
#---------------------------------------------------------------------------
Message = wx.lib.pubsub.Message
Topic = wx.lib.pubsub.Topic

View File

@@ -1,329 +1,10 @@
#----------------------------------------------------------------------
# Name: wxPython.lib.pyshell
# Purpose: A Python Interactive Interpreter running in a wxStyledTextCtrl
# window.
#
# Author: Robin Dunn
#
# Created: 7-July-2000
# RCS-ID: $Id$
# Copyright: (c) 2000 by Total Control Software
# Licence: wxWindows license
#----------------------------------------------------------------------
## This file imports items from the wx package into the wxPython package for
## backwards compatibility. Some names will also have a 'wx' added on if
## that is how they used to be named in the old wxPython package.
"""
PyShellWindow is a class that provides an Interactive Interpreter running
inside a wxStyledTextCtrl, similar to the Python shell windows found in
IDLE and PythonWin.
There is still much to be done to improve this class, such as line
buffering/recall, autoindent, calltips, autocomplete, fixing the colourizer,
etc... But it's a good start.
8-10-2001 THIS MODULE IS NOW DEPRECATED. Please see the most excellent
PyCrust package instead.
"""
from wxPython.wx import *
from wxPython.stc import *
import sys, keyword
from code import InteractiveInterpreter
#----------------------------------------------------------------------
# default styles, etc. to use for the STC
if wxPlatform == '__WXMSW__':
_defaultSize = 8
else:
_defaultSize = 10
_default_properties = {
'selMargin' : 0,
'marginWidth' : 1,
'ps1' : '>>> ',
'stdout' : 'fore:#0000FF',
'stderr' : 'fore:#007f00',
'trace' : 'fore:#FF0000',
'default' : 'size:%d' % _defaultSize,
'bracegood' : 'fore:#FFFFFF,back:#0000FF,bold',
'bracebad' : 'fore:#000000,back:#FF0000,bold',
# properties for the various Python lexer styles
'comment' : 'fore:#007F00',
'number' : 'fore:#007F7F',
'string' : 'fore:#7F007F,italic',
'char' : 'fore:#7F007F,italic',
'keyword' : 'fore:#00007F,bold',
'triple' : 'fore:#7F0000',
'tripledouble': 'fore:#7F0000',
'class' : 'fore:#0000FF,bold,underline',
'def' : 'fore:#007F7F,bold',
'operator' : 'bold',
}
# new style numbers
_stdout_style = 15
_stderr_style = 16
_trace_style = 17
#----------------------------------------------------------------------
class PyShellWindow(wxStyledTextCtrl, InteractiveInterpreter):
def __init__(self, parent, ID, pos=wxDefaultPosition,
size=wxDefaultSize, style=0,
locals=None, properties=None, banner=None):
wxStyledTextCtrl.__init__(self, parent, ID, pos, size, style)
InteractiveInterpreter.__init__(self, locals)
self.lastPromptPos = 0
# the line cache is used to cycle through previous commands
self.lines = []
self.lastUsedLine = self.curLine = 0
# set defaults and then deal with any user defined properties
self.props = {}
self.props.update(_default_properties)
if properties:
self.props.update(properties)
self.UpdateProperties()
# copyright/banner message
if banner is None:
self.write("Python %s on %s\n" % #%s\n(%s)\n" %
(sys.version, sys.platform,
#sys.copyright, self.__class__.__name__
))
else:
self.write("%s\n" % banner)
# write the initial prompt
self.Prompt()
# Event handlers
EVT_KEY_DOWN(self, self.OnKey)
EVT_STC_UPDATEUI(self, ID, self.OnUpdateUI)
#EVT_STC_STYLENEEDED(self, ID, self.OnStyle)
def GetLocals(self): return self.locals
def SetLocals(self, locals): self.locals = locals
def GetProperties(self): return self.props
def SetProperties(self, properties):
self.props.update(properties)
self.UpdateProperties()
def UpdateProperties(self):
"""
Reset the editor and other settings based on the contents of the
current properties dictionary.
"""
p = self.props
#self.SetEdgeMode(wxSTC_EDGE_LINE)
#self.SetEdgeColumn(80)
# set the selection margin and window margin
self.SetMarginWidth(1, p['selMargin'])
self.SetMargins(p['marginWidth'], p['marginWidth'])
# styles
self.StyleSetSpec(wxSTC_STYLE_DEFAULT, p['default'])
self.StyleClearAll()
self.StyleSetSpec(_stdout_style, p['stdout'])
self.StyleSetSpec(_stderr_style, p['stderr'])
self.StyleSetSpec(_trace_style, p['trace'])
self.StyleSetSpec(wxSTC_STYLE_BRACELIGHT, p['bracegood'])
self.StyleSetSpec(wxSTC_STYLE_BRACEBAD, p['bracebad'])
self.StyleSetSpec(wxSTC_P_COMMENTLINE, p['comment'])
self.StyleSetSpec(wxSTC_P_NUMBER, p['number'])
self.StyleSetSpec(wxSTC_P_STRING, p['string'])
self.StyleSetSpec(wxSTC_P_CHARACTER, p['char'])
self.StyleSetSpec(wxSTC_P_WORD, p['keyword'])
self.StyleSetSpec(wxSTC_P_TRIPLE, p['triple'])
self.StyleSetSpec(wxSTC_P_TRIPLEDOUBLE, p['tripledouble'])
self.StyleSetSpec(wxSTC_P_CLASSNAME, p['class'])
self.StyleSetSpec(wxSTC_P_DEFNAME, p['def'])
self.StyleSetSpec(wxSTC_P_OPERATOR, p['operator'])
self.StyleSetSpec(wxSTC_P_COMMENTBLOCK, p['comment'])
# used for writing to stdout, etc.
def _write(self, text, style=_stdout_style):
self.lastPromptPos = 0
pos = self.GetCurrentPos()
self.AddText(text)
self.StartStyling(pos, 0xFF)
self.SetStyling(len(text), style)
self.EnsureCaretVisible()
wxYield()
write = _write
def writeTrace(self, text):
self._write(text, _trace_style)
def Prompt(self):
# is the current line non-empty?
text, pos = self.GetCurLine()
if pos != 0:
self.AddText('\n')
self.AddText(self.props['ps1'])
self.lastPromptPos = self.GetCurrentPos()
self.EnsureCaretVisible()
self.ScrollToColumn(0)
def PushLine(self, text):
# TODO: Add the text to the line cache, manage the cache so
# it doesn't get too big.
pass
def OnKey(self, evt):
key = evt.KeyCode()
if key == WXK_RETURN:
pos = self.GetCurrentPos()
lastPos = self.GetTextLength()
# if not on the last line, duplicate the current line
if self.GetLineCount()-1 != self.GetCurrentLine():
text, col = self.GetCurLine()
prompt = self.props['ps1']
lp = len(prompt)
if text[:lp] == prompt:
text = text[lp:]
self.SetSelection(self.lastPromptPos, lastPos)
self.ReplaceSelection(text[:-1])
else: # try to execute the text from the prompt to the end
if lastPos == self.lastPromptPos:
self.AddText('\n')
self.Prompt()
return
text = self.GetTextRange(self.lastPromptPos, lastPos)
self.AddText('\n')
more = self.runsource(text)
if not more:
self.PushLine(text)
self.Prompt()
# TODO: Add handlers for Alt-P and Alt-N to cycle through entries
# in the line cache
else:
evt.Skip()
def OnStyle(self, evt):
# Only style from the prompt pos to the end
lastPos = self.GetTextLength()
if self.lastPromptPos and self.lastPromptPos != lastPos:
self.SetLexer(wxSTC_LEX_PYTHON)
self.SetKeywords(0, ' '.join(keyword.kwlist))
self.Colourise(self.lastPromptPos, lastPos)
self.SetLexer(0)
def OnUpdateUI(self, evt):
# check for matching braces
braceAtCaret = -1
braceOpposite = -1
charBefore = None
caretPos = self.GetCurrentPos()
if caretPos > 0:
charBefore = self.GetCharAt(caretPos - 1)
styleBefore = self.GetStyleAt(caretPos - 1)
# check before
if charBefore and chr(charBefore) in "[]{}()" and styleBefore == wxSTC_P_OPERATOR:
braceAtCaret = caretPos - 1
# check after
if braceAtCaret < 0:
charAfter = self.GetCharAt(caretPos)
styleAfter = self.GetStyleAt(caretPos)
if charAfter and chr(charAfter) in "[]{}()" and styleAfter == wxSTC_P_OPERATOR:
braceAtCaret = caretPos
if braceAtCaret >= 0:
braceOpposite = self.BraceMatch(braceAtCaret)
if braceAtCaret != -1 and braceOpposite == -1:
self.BraceBadlight(braceAtCaret)
else:
self.BraceHighlight(braceAtCaret, braceOpposite)
#----------------------------------------------
# overloaded methods from InteractiveInterpreter
def runsource(self, source):
stdout, stderr = sys.stdout, sys.stderr
sys.stdout = FauxFile(self, _stdout_style)
sys.stderr = FauxFile(self, _stderr_style)
more = InteractiveInterpreter.runsource(self, source)
sys.stdout, sys.stderr = stdout, stderr
return more
def showsyntaxerror(self, filename=None):
self.write = self.writeTrace
InteractiveInterpreter.showsyntaxerror(self, filename)
self.write = self._write
def showtraceback(self):
self.write = self.writeTrace
InteractiveInterpreter.showtraceback(self)
self.write = self._write
#----------------------------------------------------------------------
class FauxFile:
def __init__(self, psw, style):
self.psw = psw
self.style = style
def write(self, text):
self.psw.write(text, self.style)
def writelines(self, lst):
map(self.write, lst)
def flush(self):
pass
#----------------------------------------------------------------------
# test code
if __name__ == '__main__':
app = wxPyWidgetTester(size = (640, 480))
app.SetWidget(PyShellWindow, -1)
app.MainLoop()
#----------------------------------------------------------------------
import wx.lib.pyshell
__doc__ = wx.lib.pyshell.__doc__
FauxFile = wx.lib.pyshell.FauxFile
PyShellWindow = wx.lib.pyshell.PyShellWindow

View File

@@ -1,203 +1,9 @@
#----------------------------------------------------------------------
# Name: wxPython.lib.rcsizer
# Purpose: RowColSizer:
#
# Author: Robin Dunn, adapted from code by Niki Spahiev
#
# Created: 26-Feb-2002
# RCS-ID: $Id$
# Copyright: (c) 2002 by Total Control Software
# Licence: wxWindows license
#----------------------------------------------------------------------
"""
A pure-Python wxSizer that lays out items in a grid similar to
wxFlexGridSizer but item position is not implicit but explicitly
specified by row and col, and row/col spanning is supported.
Adapted from code by Niki Spahiev.
If anyone is interested, it would be nice to have this ported to C++.
"""
from wxPython.wx import *
import operator
#----------------------------------------------------------------------
class RowColSizer(wxPySizer):
# default sizes for cells with no item
col_w = 10
row_h = 22
def __init__(self):
wxPySizer.__init__(self)
self.growableRows = []
self.growableCols = []
def AddGrowableRow(self, idx):
self.growableRows.append(idx)
def AddGrowableCol(self, idx):
self.growableCols.append(idx)
#--------------------------------------------------
def Add(self, item, option=0, flag=0, border=0,
row=-1, col=-1, # row, col and spanning can be specified individually...
rowspan=1, colspan=1,
pos=None, size=None, # or as tuples (row,col) and (rowspan,colspan)
):
if pos is not None:
row, col = pos
if size is not None:
rowspan, colspan = size
assert row != -1, "Row must be specified"
assert col != -1, "Column must be specified"
# Do I really want to do this? Probably not...
#if rowspan > 1 or colspan > 1:
# flag = flag | wxEXPAND
wxPySizer.Add(self, item, option, flag, border,
userData=(row, col, row+rowspan, col+colspan))
#AddWindow = Add
#AddSizer = Add
def AddSpacer(self, width, height, option=0, flag=0, border=0,
row=-1, col=-1,
rowspan=1, colspan=1,
pos=None, size=None,
):
if pos is not None:
row, col = pos
if size is not None:
rowspan, colspan = size
assert row != -1, "Row must be specified"
assert col != -1, "Column must be specified"
wxPySizer.AddSpacer(self, width, height, option, flag, border,
userData=(row, col, row+rowspan, col+colspan))
#--------------------------------------------------
def _add( self, size, dim ):
r, c, r2, c2 = dim # unpack coords and spanning
# are the widths and heights lists long enough?
if r2 > len(self.rowHeights):
x = [self.row_h] * (r2-len(self.rowHeights))
self.rowHeights.extend( x )
if c2 > len(self.colWidths):
x = [self.col_w] * (c2-len(self.colWidths))
self.colWidths.extend( x )
# set the widths and heights lists for this item
scale = (r2 - r)
for i in range(r, r2):
self.rowHeights[i] = max( self.rowHeights[i], size.height / scale )
scale = (c2 - c)
for i in range(c, c2):
self.colWidths[i] = max( self.colWidths[i], size.width / scale )
#--------------------------------------------------
def CalcMin( self ):
self.rowHeights = []
self.colWidths = []
items = self.GetChildren()
if not items:
return wxSize(10, 10)
for item in items:
self._add( item.CalcMin(), item.GetUserData() )
size = wxSize( reduce( operator.add, self.colWidths),
reduce( operator.add, self.rowHeights) )
return size
#--------------------------------------------------
def RecalcSizes( self ):
# save current dimensions, etc.
curWidth = self.GetSize().width
curHeight = self.GetSize().height
px = self.GetPosition().x
py = self.GetPosition().y
minWidth = self.CalcMin().width
minHeight = self.CalcMin().height
# Check for growables
if self.growableRows and curHeight > minHeight:
delta = (curHeight - minHeight) / len(self.growableRows)
extra = (curHeight - minHeight) % len(self.growableRows)
for idx in self.growableRows:
self.rowHeights[idx] += delta
self.rowHeights[self.growableRows[0]] += extra
if self.growableCols and curWidth > minWidth:
delta = (curWidth - minWidth) / len(self.growableCols)
extra = (curWidth - minWidth) % len(self.growableCols)
for idx in self.growableCols:
self.colWidths[idx] += delta
self.colWidths[self.growableCols[0]] += extra
rpos = [0] * len(self.rowHeights)
cpos = [0] * len(self.colWidths)
for i in range(len(self.rowHeights)):
height = self.rowHeights[i]
rpos[i] = py
py += height
for i in range(len(self.colWidths)):
width = self.colWidths[i]
cpos[i] = px
px += width
# iterate children and set dimensions...
for item in self.GetChildren():
r, c, r2, c2 = item.GetUserData()
width = reduce( operator.add, self.colWidths[c:c2] )
height = reduce( operator.add, self.rowHeights[r:r2] )
self.SetItemBounds( item, cpos[c], rpos[r], width, height )
#--------------------------------------------------
def SetItemBounds(self, item, x, y, w, h):
# calculate the item's actual size and position within
# its grid cell
ipt = wxPoint(x, y)
isz = item.CalcMin()
flag = item.GetFlag()
if flag & wxEXPAND or flag & wxSHAPED:
isz = wxSize(w, h)
else:
if flag & wxALIGN_CENTER_HORIZONTAL:
ipt.x = x + (w - isz.width) / 2
elif flag & wxALIGN_RIGHT:
ipt.x = x + (w - isz.width)
if flag & wxALIGN_CENTER_VERTICAL:
ipt.y = y + (h - isz.height) / 2
elif flag & wxALIGN_BOTTOM:
ipt.y = y + (h - isz.height)
item.SetDimension(ipt, isz)
#----------------------------------------------------------------------
#----------------------------------------------------------------------
## This file imports items from the wx package into the wxPython package for
## backwards compatibility. Some names will also have a 'wx' added on if
## that is how they used to be named in the old wxPython package.
import wx.lib.rcsizer
__doc__ = wx.lib.rcsizer.__doc__
RowColSizer = wx.lib.rcsizer.RowColSizer

View File

@@ -1,82 +1,9 @@
# -*- coding: iso-8859-1 -*-
#----------------------------------------------------------------------
# Name: wxPython.lib.rightalign
# Purpose: A class derived from wxTextCtrl that aligns the text
# on the right side of the control, (except when editing.)
#
# Author: Josu Oyanguren
#
# Created: 19-October-2001
# RCS-ID: $Id$
# Copyright: (c) 2001 by Total Control Software
# Licence: wxWindows license
#----------------------------------------------------------------------
## This file imports items from the wx package into the wxPython package for
## backwards compatibility. Some names will also have a 'wx' added on if
## that is how they used to be named in the old wxPython package.
"""
Some time ago, I asked about how to right-align
wxTextCtrls. Answer was that it is not supported. I forgot it.
import wx.lib.rightalign
Just a week ago, one of my clients asked me to have numbers right
aligned. (Indeed it was that numbers MUST be right aligned).
So the game begun. Hacking, hacking, ...
At last, i succeed. Here is some code that someone may find
useful. ubRightTextCtrl is right-aligned when you are not editing, but
left-aligned if it has focus.
Hope this can help someone, as much as this list helps me.
Josu Oyanguren
Ubera Servicios Inform<72>ticos.
P.S. This only works well on wxMSW.
"""
from wxPython.wx import *
#----------------------------------------------------------------------
class wxRightTextCtrl(wxTextCtrl):
def __init__(self, parent, id, *args, **kwargs):
wxTextCtrl.__init__(self, parent, id, *args, **kwargs)
EVT_KILL_FOCUS(self, self.OnKillFocus)
EVT_PAINT(self, self.OnPaint)
def OnPaint(self, event):
dc = wxPaintDC(self)
dc.SetFont(self.GetFont())
dc.Clear()
text = self.GetValue()
textwidth, textheight = dc.GetTextExtent(text)
dcwidth, dcheight = self.GetClientSizeTuple()
y = (dcheight - textheight) / 2
x = dcwidth - textwidth - 2
if self.IsEnabled():
fclr = self.GetForegroundColour()
else:
fclr = wxSystemSettings_GetColour(wxSYS_COLOUR_GRAYTEXT)
dc.SetTextForeground(fclr)
dc.SetClippingRegion(0, 0, dcwidth, dcheight)
dc.DrawText(text, x, y)
if x < 0:
toofat = '...'
markwidth = dc.GetTextExtent(toofat)[0]
dc.SetPen(wxPen(dc.GetBackground().GetColour(), 1, wxSOLID ))
dc.DrawRectangle(0,0, markwidth, dcheight)
dc.SetPen(wxPen(wxRED, 1, wxSOLID ))
dc.SetBrush(wxTRANSPARENT_BRUSH)
dc.DrawRectangle(1, 1, dcwidth-2, dcheight-2)
dc.DrawText(toofat, 1, y)
def OnKillFocus(self, event):
if not self.GetParent(): return
self.Refresh()
event.Skip()
__doc__ = wx.lib.rightalign.__doc__
wxRightTextCtrl = wx.lib.rightalign.wxRightTextCtrl

View File

@@ -1,417 +0,0 @@
#
# This was modified from rpcMixin.py distributed with wxPython
#
#----------------------------------------------------------------------
# Name: rpcMixin
# Version: 0.2.0
# 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, 2001 by Greg Landrum and Rational Discovery LLC
# Licence: wxWindows license
#----------------------------------------------------------------------
"""provides xmlrpc server functionality for wxPython applications via a mixin class
**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) 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.
"""
""" ChangeLog
23 May 2001: Version bumped to 0.2.0
Numerous code and design changes
21 Mar. 2001: Version bumped to 0.1.4
Updated rpcMixin.OnExternal to support methods with further references
(i.e. now you can do rpcClient.foo.bar() and have it work)
This probably ain't super legal in xmlrpc land, but it works just fine here
and we need it.
6 Mar. 2001: Version bumped to 0.1.3
Documentation changes to make this compatible with happydoc
21 Jan. 2001: Version bumped to 0.1.2
OnExternal() method in the mixin class now uses getattr() to check if
a desired method is present. It should have been done this way in
the first place.
14 Dec. 2000: Version bumped to 0.1.1
rearranged locking code and made other changes so that multiple
servers in one application are possible.
"""
from wxPython.wx import *
import xmlrpcserver,xmlrpclib
import threading
import SocketServer
import new
import sys
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 Destroy(self):
self.method=None
self.args=None
self.rpcStatus = None
self.rpcStatusLock = None
self.rpcondVar = None
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 log_message(self,*args):
""" causes the server to stop spewing messages every time a request comes in
"""
pass
def call(self,method,params):
"""When an xmlrpc request comes in, this is the method that
gets called.
**Arguments**
- method: name of the method to be called
- params: arguments to that method
"""
if method == '_rpcPing':
# we just acknowledge these without processing them
return 'ack'
# construct the event
evt = ExternalEvent(method,params)
# update the status variable
evt.rpcStatusLock.acquire()
evt.rpcStatus.status = rpcPENDING
evt.rpcStatusLock.release()
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()
evt.Destroy()
self._app = None
return s
# this global Event is used to let the server thread
# know when it should quit
stopEvent = threading.Event()
stopEvent.clear()
class _ServerThread(threading.Thread):
""" this is the Thread class which actually runs the server
"""
def __init__(self,server,verbose=0):
self._xmlServ = server
threading.Thread.__init__(self,verbose=verbose)
def stop(self):
stopEvent.set()
def shouldStop(self):
return stopEvent.isSet()
def run(self):
while not self.shouldStop():
self._xmlServ.handle_request()
self._xmlServ = None
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.
"""
# we'll try a range of ports for the server, this is the size of the
# range to be scanned
nPortsToTry=20
if sys.platform == 'win32':
defPort = 800
else:
defPort = 8023
def __init__(self,host='',port=-1,verbose=0,portScan=1):
"""Constructor
**Arguments**
- host: (optional) the hostname for the server
- port: (optional) the port the server will use
- verbose: (optional) if set, the server thread will be launched
in verbose mode
- portScan: (optional) if set, we'll scan across a number of ports
to find one which is avaiable
"""
if port == -1:
port = self.defPort
self.verbose=verbose
EVT_EXTERNAL_EVENT(self,self.OnExternal)
if hasattr(self,'OnClose'):
self._origOnClose = self.OnClose
self.Disconnect(-1,-1,wxEVT_CLOSE_WINDOW)
else:
self._origOnClose = None
self.OnClose = self.RPCOnClose
EVT_CLOSE(self,self.RPCOnClose)
tClass = new.classobj('Handler%d'%(port),(Handler,),{})
tClass._app = self
if portScan:
self.rpcPort = -1
for i in xrange(self.nPortsToTry):
try:
xmlServ = SocketServer.TCPServer((host,port+i),tClass)
except:
pass
else:
self.rpcPort = port+i
else:
self.rpcPort = port
try:
xmlServ = SocketServer.TCPServer((host,port),tClass)
except:
self.rpcPort = -1
if self.rpcPort == -1:
raise 'RPCMixinError','Cannot initialize server'
self.servThread = _ServerThread(xmlServ,verbose=self.verbose)
self.servThread.setName('XML-RPC Server')
self.servThread.start()
def RPCOnClose(self,event):
""" callback for when the application is closed
be sure to shutdown the server and the server thread before
leaving
"""
# by setting the global stopEvent we inform the server thread
# that it's time to shut down.
stopEvent.set()
if event is not None:
# if we came in here from a user event (as opposed to an RPC event),
# then we'll need to kick the server one last time in order
# to get that thread to terminate. do so now
s1 = xmlrpclib.Server('http://localhost:%d'%(self.rpcPort))
try:
s1._rpcPing()
except:
pass
if self._origOnClose is not None:
self._origOnClose(event)
def RPCQuit(self):
""" shuts down everything, including the rpc server
"""
self.RPCOnClose(None)
def OnExternal(self,event):
""" this is the callback used to handle RPCs
**Arguments**
- event: an _ExternalEvent_ sent by the rpc server
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()
doQuit = 0
try:
methsplit = event.method.split('.')
meth = self
for piece in methsplit:
meth = getattr(meth,piece)
except AttributeError,msg:
event.rpcStatus.result = 'No Such Method',msg
event.rpcStatus.status = rpcEXCEPT
else:
try:
res = apply(meth,event.args)
except:
import traceback
if self.verbose: traceback.print_exc()
event.rpcStatus.result = sys.exc_info()[:2]
event.rpcStatus.status = rpcEXCEPT
else:
if res is None:
# returning None across the xmlrpc interface is problematic
event.rpcStatus.result = []
else:
event.rpcStatus.result = res
event.rpcStatus.status = rpcDONE
event.rpcStatusLock.release()
# broadcast (using the condition var) that we're done with the event
event.rpcCondVar.acquire()
event.rpcCondVar.notify()
event.rpcCondVar.release()
if __name__ == '__main__':
import time
if sys.platform == 'win32':
port = 800
else:
port = 8023
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']
if kwargs.has_key('rpcPortScan'):
mixinArgs['portScan'] = kwargs['rpcPortScan']
del kwargs['rpcPortScan']
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):
self.frame = rpcFrame(NULL, -1, "wxPython RPCDemo", wxDefaultPosition,
wxSize(300,300),
rpcHost='localhost',rpcPort=port)
self.frame.Show(True)
return True
def testcon(port):
s1 = xmlrpclib.Server('http://localhost:%d'%(port))
s1.SetTitle('Munged')
s1._rpcPing()
if doQuit:
s1.RPCQuit()
doQuit = 1
if len(sys.argv)>1 and sys.argv[1] == '-q':
doQuit = 0
nT = threading.activeCount()
app = MyApp(0)
activePort = app.frame.rpcPort
t = threading.Thread(target=lambda x=activePort:testcon(x),verbose=0)
t.start()
app.MainLoop()
# give the threads time to shut down
if threading.activeCount() > nT:
print 'waiting for all threads to terminate'
while threading.activeCount() > nT:
time.sleep(0.5)

View File

@@ -1,95 +1,9 @@
#----------------------------------------------------------------------------
# Name: wxScrolledPanel.py
# Author: Will Sadkin
# Created: 03/21/2003
# Copyright: (c) 2003 by Will Sadkin
# RCS-ID: $Id$
# License: wxWindows license
#----------------------------------------------------------------------------
#
## This file imports items from the wx package into the wxPython package for
## backwards compatibility. Some names will also have a 'wx' added on if
## that is how they used to be named in the old wxPython package.
from wxPython.wx import *
import wx.lib.scrolledpanel
__doc__ = wx.lib.scrolledpanel.__doc__
class wxScrolledPanel( wxScrolledWindow ):
"""
wxScrolledPanel fills a "hole" in the implementation of wxScrolledWindow,
providing automatic scrollbar and scrolling behavior and the tab traversal
management that wxScrolledWindow lacks. This code was based on the original
demo code showing how to do this, but is now available for general use
as a proper class (and the demo is now converted to just use it.)
"""
def __init__(self, parent, id=-1,
pos = wxDefaultPosition, size = wxDefaultSize,
style = wxTAB_TRAVERSAL, name = "scrolledpanel"):
wxScrolledWindow.__init__(self, parent, -1,
pos=pos, size=size,
style=style, name=name)
EVT_CHILD_FOCUS(self, self.OnChildFocus)
def SetupScrolling(self, scroll_x=True, scroll_y=True, rate_x=20, rate_y=20):
"""
This function sets up the event handling necessary to handle
scrolling properly. It should be called within the __init__
function of any class that is derived from wxScrolledPanel,
once the controls on the panel have been constructed and
thus the size of the scrolling area can be determined.
"""
# The following is all that is needed to integrate the sizer and the
# scrolled window.
if not scroll_x: rate_x = 0
if not scroll_y: rate_y = 0
# Round up the virtual size to be a multiple of the scroll rate
sizer = self.GetSizer()
if sizer:
w, h = sizer.GetMinSize()
if rate_x:
w += rate_x - (w % rate_x)
if rate_y:
h += rate_y - (h % rate_y)
self.SetVirtualSize( (w, h) )
self.SetVirtualSizeHints( w, h )
self.SetScrollRate(rate_x, rate_y)
wxCallAfter(self.Scroll, 0, 0) # scroll back to top after initial events
def OnChildFocus(self, evt):
# If the child window that gets the focus is not visible,
# this handler will try to scroll enough to see it.
evt.Skip()
child = evt.GetWindow()
sppu_x, sppu_y = self.GetScrollPixelsPerUnit()
vs_x, vs_y = self.GetViewStart()
cpos = child.GetPosition()
csz = child.GetSize()
new_vs_x, new_vs_y = -1, -1
# is it before the left edge?
if cpos.x < 0 and sppu_x > 0:
new_vs_x = vs_x + (cpos.x / sppu_x)
# is it above the top?
if cpos.y < 0 and sppu_y > 0:
new_vs_y = vs_y + (cpos.y / sppu_y)
# is it past the right edge ?
if cpos.x + csz.width > self.GetClientSize().width and sppu_x > 0:
diff = (cpos.x + csz.width - self.GetClientSize().width) / sppu_x
new_vs_x = vs_x + diff + 1
# is it below the bottom ?
if cpos.y + csz.height > self.GetClientSize().height and sppu_y > 0:
diff = (cpos.y + csz.height - self.GetClientSize().height) / sppu_y
new_vs_y = vs_y + diff + 1
# if we need to adjust
if new_vs_x != -1 or new_vs_y != -1:
self.Scroll(new_vs_x, new_vs_y)
wxScrolledPanel = wx.lib.scrolledpanel.wxScrolledPanel

View File

@@ -1,332 +1,11 @@
# sheet.py
# CSheet - A wxPython spreadsheet class.
# This is free software. Feel free to adapt it as you like.
# Author: Mark F. Russo (russomf@hotmail.com) 2002/01/31
## This file imports items from the wx package into the wxPython package for
## backwards compatibility. Some names will also have a 'wx' added on if
## that is how they used to be named in the old wxPython package.
from wxPython.wx import *
from wxPython.grid import *
import string
import wx.lib.sheet
#---------------------------------------------------------------------------
class CTextCellEditor(wxTextCtrl):
""" Custom text control for cell editing """
def __init__(self, parent, id, grid):
wxTextCtrl.__init__(self, parent, id, "", style=wxNO_BORDER)
self._grid = grid # Save grid reference
EVT_CHAR(self, self.OnChar)
__doc__ = wx.lib.sheet.__doc__
def OnChar(self, evt): # Hook OnChar for custom behavior
"""Customizes char events """
key = evt.GetKeyCode()
if key == WXK_DOWN:
self._grid.DisableCellEditControl() # Commit the edit
self._grid.MoveCursorDown(False) # Change the current cell
elif key == WXK_UP:
self._grid.DisableCellEditControl() # Commit the edit
self._grid.MoveCursorUp(False) # Change the current cell
elif key == WXK_LEFT:
self._grid.DisableCellEditControl() # Commit the edit
self._grid.MoveCursorLeft(False) # Change the current cell
elif key == WXK_RIGHT:
self._grid.DisableCellEditControl() # Commit the edit
self._grid.MoveCursorRight(False) # Change the current cell
evt.Skip() # Continue event
#---------------------------------------------------------------------------
class CCellEditor(wxPyGridCellEditor):
""" Custom cell editor """
def __init__(self, grid):
wxPyGridCellEditor.__init__(self)
self._grid = grid # Save a reference to the grid
def Create(self, parent, id, evtHandler):
""" Create the actual edit control. Must derive from wxControl.
Must Override
"""
self._tc = CTextCellEditor(parent, id, self._grid)
self._tc.SetInsertionPoint(0)
self.SetControl(self._tc)
if evtHandler:
self._tc.PushEventHandler(evtHandler)
def SetSize(self, rect):
""" Position/size the edit control within the cell rectangle. """
# Size text control to exactly overlay in-cell editing
self._tc.SetDimensions(rect.x+3, rect.y+3, rect.width-2, rect.height-2)
def Show(self, show, attr):
""" Show or hide the edit control. Use the attr (if not None)
to set colors or fonts for the control.
"""
self.base_Show(show, attr)
def PaintBackground(self, rect, attr):
""" Draws the part of the cell not occupied by the edit control. The
base class version just fills it with background colour from the
attribute.
"""
# Call base class method.
self.base_PaintBackground(self, rect, attr)
def BeginEdit(self, row, col, grid):
""" Fetch the value from the table and prepare edit control to begin editing.
Set the focus to the edit control. Must Override.
"""
self._startValue = grid.GetTable().GetValue(row, col)
self._tc.SetValue(self._startValue)
self._tc.SetFocus()
# Select the text when initiating an edit so that subsequent typing
# replaces the contents.
self._tc.SetSelection(0, self._tc.GetLastPosition())
def EndEdit(self, row, col, grid):
""" Commit editing the current cell. Returns True if the value has changed.
If necessary, the control may be destroyed. Must Override.
"""
changed = False # Assume value not changed
val = self._tc.GetValue() # Get value in edit control
if val != self._startValue: # Compare
changed = True # If different then changed is True
grid.GetTable().SetValue(row, col, val) # Update the table
self._startValue = '' # Clear the class' start value
self._tc.SetValue('') # Clear contents of the edit control
return changed
def Reset(self):
""" Reset the value in the control back to its starting value. Must Override. """
self._tc.SetValue(self._startValue)
self._tc.SetInsertionPointEnd()
def IsAcceptedKey(self, evt):
""" Return True to allow the given key to start editing. The base class
version only checks that the event has no modifiers. F2 is special
and will always start the editor.
"""
return (not (evt.ControlDown() or evt.AltDown())
and evt.GetKeyCode() != WXK_SHIFT)
def StartingKey(self, evt):
""" If the editor is enabled by pressing keys on the grid, this will be
called to let the editor react to that first key.
"""
key = evt.GetKeyCode() # Get the key code
ch = None # Handle num pad keys
if key in [WXK_NUMPAD0, WXK_NUMPAD1, WXK_NUMPAD2, WXK_NUMPAD3, WXK_NUMPAD4,
WXK_NUMPAD5, WXK_NUMPAD6, WXK_NUMPAD7, WXK_NUMPAD8, WXK_NUMPAD9]:
ch = chr(ord('0') + key - WXK_NUMPAD0)
elif key == WXK_BACK: # Empty text control when init w/ back key
ch = ""
# Handle normal keys
elif key < 256 and key >= 0 and chr(key) in string.printable:
ch = chr(key)
if not evt.ShiftDown():
ch = ch.lower()
if ch is not None: # If are at this point with a key,
self._tc.SetValue(ch) # replace the contents of the text control.
self._tc.SetInsertionPointEnd() # Move to the end so that subsequent keys are appended
else:
evt.Skip()
def StartingClick(self):
""" If the editor is enabled by clicking on the cell, this method will be
called to allow the editor to simulate the click on the control.
"""
pass
def Destroy(self):
""" Final cleanup """
self.base_Destroy()
def Clone(self):
""" Create a new object which is the copy of this one. Must Override. """
return CCellEditor()
#---------------------------------------------------------------------------
class CSheet(wxGrid):
def __init__(self, parent):
wxGrid.__init__(self, parent, -1)
# Init variables
self._lastCol = -1 # Init last cell column clicked
self._lastRow = -1 # Init last cell row clicked
self._selected = None # Init range currently selected
# Map string datatype to default renderer/editor
self.RegisterDataType(wxGRID_VALUE_STRING,
wxGridCellStringRenderer(),
CCellEditor(self))
self.CreateGrid(4, 3) # By default start with a 4 x 3 grid
self.SetColLabelSize(18) # Default sizes and alignment
self.SetRowLabelSize(50)
self.SetRowLabelAlignment(wxALIGN_RIGHT, wxALIGN_BOTTOM)
self.SetColSize(0, 75) # Default column sizes
self.SetColSize(1, 75)
self.SetColSize(2, 75)
# Sink events
EVT_GRID_CELL_LEFT_CLICK( self, self.OnLeftClick)
EVT_GRID_CELL_RIGHT_CLICK( self, self.OnRightClick)
EVT_GRID_CELL_LEFT_DCLICK( self, self.OnLeftDoubleClick)
EVT_GRID_RANGE_SELECT( self, self.OnRangeSelect)
EVT_GRID_ROW_SIZE( self, self.OnRowSize)
EVT_GRID_COL_SIZE( self, self.OnColSize)
EVT_GRID_CELL_CHANGE( self, self.OnCellChange)
EVT_GRID_SELECT_CELL( self, self.OnGridSelectCell)
def OnGridSelectCell(self, event):
""" Track cell selections """
# Save the last cell coordinates
self._lastRow, self._lastCol = event.GetRow(), event.GetCol()
event.Skip()
def OnRowSize(self, event):
event.Skip()
def OnColSize(self, event):
event.Skip()
def OnCellChange(self, event):
event.Skip()
def OnLeftClick(self, event):
""" Override left-click behavior to prevent left-click edit initiation """
# Save the cell clicked
currCell = (event.GetRow(), event.GetCol())
# Suppress event if same cell clicked twice in a row.
# This prevents a single-click from initiating an edit.
if currCell != (self._lastRow, self._lastCol): event.Skip()
def OnRightClick(self, event):
""" Move grid cursor when a cell is right-clicked """
self.SetGridCursor( event.GetRow(), event.GetCol() )
event.Skip()
def OnLeftDoubleClick(self, event):
""" Initiate the cell editor on a double-click """
# Move grid cursor to double-clicked cell
if self.CanEnableCellControl():
self.SetGridCursor( event.GetRow(), event.GetCol() )
self.EnableCellEditControl(True) # Show the cell editor
event.Skip()
def OnRangeSelect(self, event):
""" Track which cells are selected so that copy/paste behavior can be implemented """
# If a single cell is selected, then Selecting() returns False (0)
# and range coords are entire grid. In this case cancel previous selection.
# If more than one cell is selected, then Selecting() is True (1)
# and range accurately reflects selected cells. Save them.
# If more cells are added to a selection, selecting remains True (1)
self._selected = None
if event.Selecting():
self._selected = ((event.GetTopRow(), event.GetLeftCol()),
(event.GetBottomRow(), event.GetRightCol()))
event.Skip()
def Copy(self):
""" Copy the currently selected cells to the clipboard """
# TODO: raise an error when there are no cells selected?
if self._selected == None: return
((r1, c1), (r2, c2)) = self._selected
# Build a string to put on the clipboard
# (Is there a faster way to do this in Python?)
crlf = chr(13) + chr(10)
tab = chr(9)
s = ""
for row in range(r1, r2+1):
for col in range(c1, c2):
s += self.GetCellValue(row,col)
s += tab
s += self.GetCellValue(row, c2)
s += crlf
# Put the string on the clipboard
if wxTheClipboard.Open():
wxTheClipboard.Clear()
wxTheClipboard.SetData(wxTextDataObject(s))
wxTheClipboard.Close()
def Paste(self):
""" Paste the contents of the clipboard into the currently selected cells """
# (Is there a better way to do this?)
if wxTheClipboard.Open():
td = wxTextDataObject()
success = wxTheClipboard.GetData(td)
wxTheClipboard.Close()
if not success: return # Exit on failure
s = td.GetText() # Get the text
crlf = chr(13) + chr(10) # CrLf characters
tab = chr(9) # Tab character
rows = s.split(crlf) # split into rows
rows = rows[0:-1] # leave out last element, which is always empty
for i in range(0, len(rows)): # split rows into elements
rows[i] = rows[i].split(tab)
# Get the starting and ending cell range to paste into
if self._selected == None: # If no cells selected...
r1 = self.GetGridCursorRow() # Start the paste at the current location
c1 = self.GetGridCursorCol()
r2 = self.GetNumberRows()-1 # Go to maximum row and col extents
c2 = self.GetNumberCols()-1
else: # If cells selected, only paste there
((r1, c1), (r2, c2)) = self._selected
# Enter data into spreadsheet cells one at a time
r = r1 # Init row and column counters
c = c1
for row in rows: # Loop over all rows
for element in row: # Loop over all row elements
self.SetCellValue(r, c, str(element)) # Set cell value
c += 1 # Increment the column counter
if c > c2: break # Do not exceed maximum column
r += 1
if r > r2: break # Do not exceed maximum row
c = c1
def Clear(self):
""" Clear the currently selected cells """
if self._selected == None: # If no selection...
r = self.GetGridCursorRow() # clear only current cell
c = self.GetGridCursorCol()
self.SetCellValue(r, c, "")
else: # Otherwise clear selected cells
((r1, c1), (r2, c2)) = self._selected
for r in range(r1, r2+1):
for c in range(c1, c2+1):
self.SetCellValue(r, c, "")
def SetNumberRows(self, numRows=1):
""" Set the number of rows in the sheet """
# Check for non-negative number
if numRows < 0: return False
# Adjust number of rows
curRows = self.GetNumberRows()
if curRows < numRows:
self.AppendRows(numRows - curRows)
elif curRows > numRows:
self.DeleteRows(numRows, curRows - numRows)
return True
def SetNumberCols(self, numCols=1):
""" Set the number of columns in the sheet """
# Check for non-negative number
if numCols < 0: return False
# Adjust number of rows
curCols = self.GetNumberCols()
if curCols < numCols:
self.AppendCols(numCols - curCols)
elif curCols > numCols:
self.DeleteCols(numCols, curCols - numCols)
return True
CCellEditor = wx.lib.sheet.CCellEditor
CSheet = wx.lib.sheet.CSheet
CTextCellEditor = wx.lib.sheet.CTextCellEditor

View File

@@ -1,352 +1,11 @@
# shell.py
"""wxPython interactive shell
## This file imports items from the wx package into the wxPython package for
## backwards compatibility. Some names will also have a 'wx' added on if
## that is how they used to be named in the old wxPython package.
Copyright (c) 1999 SIA "ANK"
import wx.lib.shell
this module is free software. it may be used under same terms as Python itself
Notes:
i would like to use command completion (see rlcompleter library module),
but i cannot load it because i don't have readline...
History:
03-oct-1999 [als] created
04-oct-1999 [als] PyShellOutput.intro moved from __init__ parameters
to class attributes; html debug disabled
04-oct-1999 [als] fixed bug with class attributes
input prompts and output styles added to customized demo
some html cleanups
04-oct-1999 [rpd] Changed to use the new sizers
05-oct-1999 [als] changes inspired by code.InteractiveInterpreter()
from Python Library. if i knew about this class earlier,
i would rather inherit from it.
renamed to wxPyShell.py since i've renounced the 8.3 scheme
8-10-2001 THIS MODULE IS NOW DEPRECATED. Please see the most excellent
PyCrust package instead.
"""
__version__ ="$Revision$"
# $RCSfile$
import sys, code, traceback
from wxPython.wx import *
from wxPython.html import *
class PyShellInput(wxPanel):
"""PyShell input window
"""
PS1 =" Enter Command:"
PS2 ="... continue:"
def __init__(self, parent, shell, id=-1):
"""Create input window
shell must be a PyShell object.
it is used for exception handling, eval() namespaces,
and shell.output is used for output
(print's go to overridden stdout)
"""
wxPanel.__init__(self, parent, id)
self.shell =shell
# make a private copy of class attrs
self.PS1 =PyShellInput.PS1
self.PS2 =PyShellInput.PS2
# create controls
self.label =wxStaticText(self, -1, self.PS1)
tid =wxNewId()
self.entry =wxTextCtrl(self, tid, style = wxTE_MULTILINE)
EVT_CHAR(self.entry, self.OnChar)
self.entry.SetFont(wxFont(9, wxMODERN, wxNORMAL, wxNORMAL, False))
sizer =wxBoxSizer(wxVERTICAL)
sizer.AddMany([(self.label, 0, wxEXPAND), (self.entry, 1, wxEXPAND)])
self.SetSizer(sizer)
self.SetAutoLayout(True)
EVT_SET_FOCUS(self, self.OnSetFocus)
# when in "continuation" mode,
# two consecutive newlines are required
# to avoid execution of unfinished block
self.first_line =1
def OnSetFocus(self, event):
self.entry.SetFocus()
def Clear(self, event=None):
"""reset input state"""
self.label.SetLabel(self.PS1)
self.label.Refresh()
self.entry.SetSelection(0, self.entry.GetLastPosition())
self.first_line =1
# self.entry.SetFocus()
def OnChar(self, event):
"""called on CHARevent. executes input on newline"""
# print "On Char:", event.__dict__.keys()
if event.KeyCode() !=WXK_RETURN:
# not of our business
event.Skip()
return
text =self.entry.GetValue()
# weird CRLF thingy
text = text.replace("\r\n", "\n")
# see if we've finished
if (not (self.first_line or text[-1] =="\n") # in continuation mode
or (text[-1] =="\\") # escaped newline
):
# XXX should escaped newline put myself i "continuation" mode?
event.Skip()
return
# ok, we can try to execute this
rc =self.shell.TryExec(text)
if rc:
# code is incomplete; continue input
if self.first_line:
self.label.SetLabel(self.PS2)
self.label.Refresh()
self.first_line =0
event.Skip()
else:
self.Clear()
class PyShellOutput(wxPanel):
"""PyShell output window
for now, it is based on simple wxTextCtrl,
but i'm looking at HTML classes to provide colorized output
"""
# attributes for for different (input, output, exception) display styles:
# begin tag, end tag, newline
in_style =(" <font color=\"#000080\"><tt>&gt;&gt;&gt;&nbsp;",
"</tt></font><br>\n", "<br>\n...&nbsp;")
out_style =("<tt>", "</tt>\n", "<br>\n")
exc_style =("<font color=\"#FF0000\"><tt>",
"</tt></font>\n", "<br>\n")
intro ="<H3>wxPython Interactive Shell</H3>\n"
html_debug =0
# entity references
erefs =(("&", "&amp;"), (">", "&gt;"), ("<", "&lt;"), (" ", "&nbsp; "))
def __init__(self, parent, id=-1):
wxPanel.__init__(self, parent, id)
# make a private copy of class attrs
self.in_style =PyShellOutput.in_style
self.out_style =PyShellOutput.out_style
self.exc_style =PyShellOutput.exc_style
self.intro =PyShellOutput.intro
self.html_debug =PyShellOutput.html_debug
# create windows
if self.html_debug:
# this was used in html debugging,
# but i don't want to delete it; it's funny
splitter =wxSplitterWindow(self, -1)
self.view =wxTextCtrl(splitter, -1,
style = wxTE_MULTILINE|wxTE_READONLY|wxHSCROLL)
self.html =wxHtmlWindow(splitter)
splitter.SplitVertically(self.view, self.html)
splitter.SetSashPosition(40)
splitter.SetMinimumPaneSize(3)
self.client =splitter
else:
self.view =None
self.html =wxHtmlWindow(self)
self.client =self.html # used in OnSize()
self.text =self.intro
self.html.SetPage(self.text)
self.html.SetAutoLayout(True)
self.line_buffer =""
# refreshes are annoying
self.in_batch =0
self.dirty =0
EVT_SIZE(self, self.OnSize)
EVT_IDLE(self, self.OnIdle)
def OnSize(self, event):
self.client.SetSize(self.GetClientSize())
def OnIdle(self, event):
"""when there's nothing to do, we can update display"""
if self.in_batch and self.dirty: self.UpdWindow()
def BeginBatch(self):
"""do not refresh display till EndBatch()"""
self.in_batch =1
def EndBatch(self):
"""end batch; start updating display immediately"""
self.in_batch =0
if self.dirty: self.UpdWindow()
def UpdWindow(self):
"""sync display with text buffer"""
html =self.html
html.SetPage(self.text)
self.dirty =0
# scroll to the end
(x,y) =html.GetVirtualSize()
html.Scroll(0, y)
def AddText(self, text, style=None):
"""write text to output window"""
# a trick needed to defer default from compile-time to execute-time
if style ==None: style =self.out_style
if 0 and __debug__: sys.__stdout__.write(text)
# handle entities
for (symbol, eref) in self.erefs:
text = text.replace(symbol, eref)
# replace newlines
text = text.replace("\n", style[2])
# add to contents
self.text =self.text +style[0] +text +style[1]
if not self.in_batch: self.UpdWindow()
else: self.dirty =1
if self.html_debug:
# html debug output needn't to be too large
self.view.SetValue(self.text[-4096:])
def write(self, str, style=None):
"""stdout-like interface"""
if style ==None: style =self.out_style
# do not process incomplete lines
if len(str) <1:
# hm... what was i supposed to do?
return
elif str[-1] !="\n":
self.line_buffer =self.line_buffer +str
else:
self.AddText(self.line_buffer +str, style)
self.line_buffer =""
def flush(self, style=None):
"""write out all that was left in line buffer"""
if style ==None: style =self.out_style
self.AddText(self.line_buffer +"\n", style)
def write_in(self, str, style=None):
"""write text in "input" style"""
if style ==None: style =self.in_style
self.AddText(str, style)
def write_exc(self, str, style=None):
"""write text in "exception" style"""
if style ==None: style =self.exc_style
self.AddText(str, style)
class PyShell(wxPanel):
"""interactive Python shell with wxPython interface
"""
def __init__(self, parent, globals=globals(), locals={},
id=-1, pos=wxDefaultPosition, size=wxDefaultSize,
style=wxTAB_TRAVERSAL, name="shell"):
"""create PyShell window"""
wxPanel.__init__(self, parent, id, pos, size, style, name)
self.globals =globals
self.locals =locals
splitter =wxSplitterWindow(self, -1)
self.output =PyShellOutput(splitter)
self.input =PyShellInput(splitter, self)
self.input.SetFocus()
splitter.SplitHorizontally(self.input, self.output)
splitter.SetSashPosition(100)
splitter.SetMinimumPaneSize(20)
self.splitter =splitter
EVT_SET_FOCUS(self, self.OnSetFocus)
EVT_SIZE(self, self.OnSize)
def OnSetFocus(self, event):
self.input.SetFocus()
def TryExec(self, source, symbol="single"):
"""Compile and run some source in the interpreter.
borrowed from code.InteractiveInterpreter().runsource()
as i said above, i would rather like to inherit from that class
returns 1 if more input is required, or 0, otherwise
"""
try:
cc = code.compile_command(source, symbol=symbol)
except (OverflowError, SyntaxError):
# [als] hm... never seen anything of that kind
self.ShowSyntaxError()
return 0
if cc is None:
# source is incomplete
return 1
# source is sucessfully compiled
out =self.output
# redirect system stdout to the output window
prev_out =sys.stdout
sys.stdout =out
# begin printout batch (html updates are deferred until EndBatch())
out.BeginBatch()
out.write_in(source)
try:
exec cc in self.globals, self.locals
except SystemExit:
# SystemExit is not handled and has to be re-raised
raise
except:
# all other exceptions produce traceback output
self.ShowException()
# switch back to saved stdout
sys.stdout =prev_out
# commit printout
out.flush()
out.EndBatch()
return 0
def ShowException(self):
"""display the traceback for the latest exception"""
(etype, value, tb) =sys.exc_info()
# remove myself from traceback
tblist =traceback.extract_tb(tb)[1:]
msg = ' '.join(traceback.format_exception_only(etype, value)
+traceback.format_list(tblist))
self.output.write_exc(msg)
def ShowSyntaxError(self):
"""display message about syntax error (no traceback here)"""
(etype, value, tb) =sys.exc_info()
msg = ' '.join(traceback.format_exception_only(etype, value))
self.output.write_exc(msg)
def OnSize(self, event):
self.splitter.SetSize(self.GetClientSize())
#----------------------------------------------------------------------
if __name__ == '__main__':
class MyFrame(wxFrame):
"""Very standard Frame class. Nothing special here!"""
def __init__(self, parent=NULL, id =-1,
title="wxPython Interactive Shell"):
wxFrame.__init__(self, parent, id, title)
self.shell =PyShell(self)
class MyApp(wxApp):
"""Demonstrates usage of both default and customized shells"""
def OnInit(self):
frame = MyFrame()
frame.Show(True)
self.SetTopWindow(frame)
## PyShellInput.PS1 =" let's get some work done..."
## PyShellInput.PS2 =" ok, what do you really mean?"
## PyShellOutput.in_style =(
## "<I><font color=\"#008000\"><tt>&gt;&gt;&gt;&nbsp;",
## "</tt></font></I><br>\n", "<br>\n...&nbsp;")
## PyShellOutput.out_style =(
## "<font color=\"#000080\"><tt>",
## "</tt></font><br>\n", "<br>\n")
## PyShellOutput.exc_style =("<B><font color=\"#FF0000\"><tt>",
## "</tt></font></B>\n", "<br>\n")
## PyShellOutput.intro ="<I><B>Customized wxPython Shell</B>" \
## "<br>&lt;-- move this sash to see html debug output</I><br>\n"
## PyShellOutput.html_debug =1
## frame = MyFrame(title="Customized wxPython Shell")
## frame.Show(True)
return True
app = MyApp(0)
app.MainLoop()
__doc__ = wx.lib.shell.__doc__
PyShell = wx.lib.shell.PyShell
PyShellInput = wx.lib.shell.PyShellInput
PyShellOutput = wx.lib.shell.PyShellOutput

View File

@@ -1,114 +1,9 @@
#----------------------------------------------------------------------
# Name: wxPython.lib.splashscreen
# Purpose: A simple frame that can display a bitmap and closes itself
# after a specified timeout or a mouse click.
#
# Author: Mike Fletcher, Robin Dunn
#
# Created: 19-Nov-1999
# RCS-ID: $Id$
# Copyright: (c) 1999 by Total Control Software
# Licence: wxWindows license
#----------------------------------------------------------------------
## This file imports items from the wx package into the wxPython package for
## backwards compatibility. Some names will also have a 'wx' added on if
## that is how they used to be named in the old wxPython package.
"""
A Splash Screen implemented in Python.
import wx.lib.splashscreen
NOTE: Now that wxWindows has a wxSplashScrren class and it is wrapped
in wxPython this class is deprecated. See the docs for more details.
"""
__doc__ = wx.lib.splashscreen.__doc__
from wxPython.wx import *
#----------------------------------------------------------------------
class SplashScreen(wxFrame):
def __init__(self, parent, ID=-1, title="SplashScreen",
style=wxSIMPLE_BORDER|wxSTAY_ON_TOP,
duration=1500, bitmapfile="bitmaps/splashscreen.bmp",
callback = None):
'''
parent, ID, title, style -- see wxFrame
duration -- milliseconds to display the splash screen
bitmapfile -- absolute or relative pathname to image file
callback -- if specified, is called when timer completes, callback is
responsible for closing the splash screen
'''
### Loading bitmap
self.bitmap = bmp = wxImage(bitmapfile, wxBITMAP_TYPE_ANY).ConvertToBitmap()
### Determine size of bitmap to size window...
size = (bmp.GetWidth(), bmp.GetHeight())
# size of screen
width = wxSystemSettings_GetSystemMetric(wxSYS_SCREEN_X)
height = wxSystemSettings_GetSystemMetric(wxSYS_SCREEN_Y)
pos = ((width-size[0])/2, (height-size[1])/2)
# check for overflow...
if pos[0] < 0:
size = (wxSystemSettings_GetSystemMetric(wxSYS_SCREEN_X), size[1])
if pos[1] < 0:
size = (size[0], wxSystemSettings_GetSystemMetric(wxSYS_SCREEN_Y))
wxFrame.__init__(self, parent, ID, title, pos, size, style)
EVT_LEFT_DOWN(self, self.OnMouseClick)
EVT_CLOSE(self, self.OnCloseWindow)
EVT_PAINT(self, self.OnPaint)
EVT_ERASE_BACKGROUND(self, self.OnEraseBG)
self.Show(True)
class SplashTimer(wxTimer):
def __init__(self, targetFunction):
self.Notify = targetFunction
wxTimer.__init__(self)
if callback is None:
callback = self.OnSplashExitDefault
self.timer = SplashTimer(callback)
self.timer.Start(duration, 1) # one-shot only
def OnPaint(self, event):
dc = wxPaintDC(self)
dc.DrawBitmap(self.bitmap, 0,0, False)
def OnEraseBG(self, event):
pass
def OnSplashExitDefault(self, event=None):
self.Close(True)
def OnCloseWindow(self, event=None):
self.Show(False)
self.timer.Stop()
del self.timer
self.Destroy()
def OnMouseClick(self, event):
self.timer.Notify()
#----------------------------------------------------------------------
if __name__ == "__main__":
class DemoApp(wxApp):
def OnInit(self):
wxImage_AddHandler(wxJPEGHandler())
wxImage_AddHandler(wxPNGHandler())
wxImage_AddHandler(wxGIFHandler())
self.splash = SplashScreen(NULL, bitmapfile="splashscreen.jpg", callback=self.OnSplashExit)
self.splash.Show(True)
self.SetTopWindow(self.splash)
return True
def OnSplashExit(self, event=None):
print "Yay! Application callback worked!"
self.splash.Close(True)
del self.splash
### Build working windows here...
def test(sceneGraph=None):
app = DemoApp(0)
app.MainLoop()
test()
SplashScreen = wx.lib.splashscreen.SplashScreen

View File

@@ -1,144 +1,8 @@
#----------------------------------------------------------------------
# Name: wxPython.lib.stattext
# Purpose: A generic wxGenStaticText class. Using this should
# eliminate some of the platform differences in wxStaticText,
# such as background colours and mouse sensitivity.
#
# Author: Robin Dunn
#
# Created: 8-July-2002
# RCS-ID: $Id$
# Copyright: (c) 2002 by Total Control Software
# Licence: wxWindows license
#----------------------------------------------------------------------
## This file reverse renames symbols in the wx package to give
## them their wx prefix again, for backwards compatibility.
"""
"""
from wxPython.wx import *
#----------------------------------------------------------------------
class wxGenStaticText(wxPyControl):
labelDelta = 1
def __init__(self, parent, ID, label,
pos = wxDefaultPosition, size = wxDefaultSize,
style = 0,
name = "genstattext"):
wxPyControl.__init__(self, parent, ID, pos, size, style|wxNO_BORDER,
wxDefaultValidator, name)
wxPyControl.SetLabel(self, label) # don't check wxST_NO_AUTORESIZE yet
self.SetPosition(pos)
font = parent.GetFont()
if not font.Ok():
font = wxSystemSettings_GetSystemFont(wxSYS_DEFAULT_GUI_FONT)
wxPyControl.SetFont(self, font) # same here
self.defBackClr = parent.GetBackgroundColour()
if not self.defBackClr.Ok():
self.defBackClr = wxSystemSettings_GetSystemColour(wxSYS_COLOUR_3DFACE)
self.SetBackgroundColour(self.defBackClr)
clr = parent.GetForegroundColour()
if not clr.Ok():
clr = wxSystemSettings_GetSystemColour(wxSYS_COLOUR_BTNTEXT)
self.SetForegroundColour(clr)
rw, rh = size
bw, bh = self.GetBestSize()
if rw == -1: rw = bw
if rh == -1: rh = bh
self.SetSize(wxSize(rw, rh))
EVT_ERASE_BACKGROUND(self, self.OnEraseBackground)
EVT_PAINT(self, self.OnPaint)
def SetLabel(self, label):
"""
Sets the static text label and updates the control's size to exactly
fit the label unless the control has wxST_NO_AUTORESIZE flag.
"""
wxPyControl.SetLabel(self, label)
style = self.GetWindowStyleFlag()
if not style & wxST_NO_AUTORESIZE:
self.SetSize(self.GetBestSize())
self.Refresh()
def SetFont(self, font):
"""
Sets the static text font and updates the control's size to exactly
fit the label unless the control has wxST_NO_AUTORESIZE flag.
"""
wxPyControl.SetFont(self, font)
style = self.GetWindowStyleFlag()
if not style & wxST_NO_AUTORESIZE:
self.SetSize(self.GetBestSize())
self.Refresh()
def DoGetBestSize(self):
"""Overridden base class virtual. Determines the best size of the
button based on the label size."""
label = self.GetLabel()
maxWidth = totalHeight = 0
for line in label.split('\n'):
if line == '':
w, h = self.GetTextExtent('W') # empty lines have height too
else:
w, h = self.GetTextExtent(line)
totalHeight += h
maxWidth = max(maxWidth, w)
return wxSize(maxWidth, totalHeight)
def AcceptsFocus(self):
"""Overridden base class virtual."""
return False
def OnPaint(self, event):
dc = wxBufferedPaintDC(self)
#dc = wxPaintDC(self)
width, height = self.GetClientSize()
if not width or not height:
return
clr = self.GetBackgroundColour()
backBrush = wxBrush(clr, wxSOLID)
if wxPlatform == "__WXMAC__" and clr == self.defBackClr:
# if colour still the default the use the striped background on Mac
backBrush.SetMacTheme(1) # 1 == kThemeBrushDialogBackgroundActive
dc.SetBackground(backBrush)
dc.SetTextForeground(self.GetForegroundColour())
dc.Clear()
dc.SetFont(self.GetFont())
label = self.GetLabel()
style = self.GetWindowStyleFlag()
x = y = 0
for line in label.split('\n'):
if line == '':
w, h = self.GetTextExtent('W') # empty lines have height too
else:
w, h = self.GetTextExtent(line)
if style & wxALIGN_RIGHT:
x = width - w
if style & wxALIGN_CENTER:
x = (width - w)/2
dc.DrawText(line, x, y)
y += h
def OnEraseBackground(self, event):
pass
#----------------------------------------------------------------------
import wx.lib.stattext
__doc__ = wx.lib.stattext.__doc__
wxGenStaticText = wx.lib.stattext.GenStaticText

View File

@@ -1,245 +1,11 @@
"""
A throbber displays an animated image that can be
started, stopped, reversed, etc. Useful for showing
an ongoing process (like most web browsers use) or
simply for adding eye-candy to an application.
## This file imports items from the wx package into the wxPython package for
## backwards compatibility. Some names will also have a 'wx' added on if
## that is how they used to be named in the old wxPython package.
Throbbers utilize a wxTimer so that normal processing
can continue unencumbered.
"""
import wx.lib.throbber
#
# throbber.py - Cliff Wells <clifford.wells@comcast.net>
#
# Thanks to Harald Massa <harald.massa@suedvers.de> for
# suggestions and sample code.
#
# $Id$
#
import os
import wx
# ------------------------------------------------------------------------------
THROBBER_EVENT = wx.NewEventType()
def EVT_UPDATE_THROBBER(win, func):
win.Connect(-1, -1, THROBBER_EVENT, func)
class UpdateThrobberEvent(wx.PyEvent):
def __init__(self):
wx.PyEvent.__init__(self)
self.SetEventType(THROBBER_EVENT)
# ------------------------------------------------------------------------------
class Throbber(wx.Panel):
"""
The first argument is either the name of a file that will be split into frames
(a composite image) or a list of strings of image names that will be treated
as individual frames. If a single (composite) image is given, then additional
information must be provided: the number of frames in the image and the width
of each frame. The first frame is treated as the "at rest" frame (it is not
shown during animation, but only when Throbber.Rest() is called.
A second, single image may be optionally specified to overlay on top of the
animation. A label may also be specified to show on top of the animation.
"""
def __init__(self, parent, id,
bitmap, # single (composite) bitmap or list of bitmaps
pos = wx.DefaultPosition,
size = wx.DefaultSize,
frameDelay = 0.1,# time between frames
frames = 0, # number of frames (only necessary for composite image)
frameWidth = 0, # width of each frame (only necessary for composite image)
label = None, # optional text to be displayed
overlay = None, # optional image to overlay on animation
reverse = 0, # reverse direction at end of animation
style = 0, # window style
name = "throbber"):
wx.Panel.__init__(self, parent, id, pos, size, style, name)
self.name = name
self.label = label
self.running = (1 != 1)
_seqTypes = (type([]), type(()))
# set size, guessing if necessary
width, height = size
if width == -1:
if type(bitmap) in _seqTypes:
width = bitmap[0].GetWidth()
else:
if frameWidth:
width = frameWidth
if height == -1:
if type(bitmap) in _seqTypes:
height = bitmap[0].GetHeight()
else:
height = bitmap.GetHeight()
self.width, self.height = width, height
# double check it
assert width != -1 and height != -1, "Unable to guess size"
if label:
extentX, extentY = self.GetTextExtent(label)
self.labelX = (width - extentX)/2
self.labelY = (height - extentY)/2
self.frameDelay = frameDelay
self.current = 0
self.direction = 1
self.autoReverse = reverse
self.overlay = overlay
if overlay is not None:
self.overlay = overlay
self.overlayX = (width - self.overlay.GetWidth()) / 2
self.overlayY = (height - self.overlay.GetHeight()) / 2
self.showOverlay = overlay is not None
self.showLabel = label is not None
# do we have a sequence of images?
if type(bitmap) in _seqTypes:
self.submaps = bitmap
self.frames = len(self.submaps)
# or a composite image that needs to be split?
else:
self.frames = frames
self.submaps = []
for chunk in range(frames):
rect = (chunk * frameWidth, 0, width, height)
self.submaps.append(bitmap.GetSubBitmap(rect))
# self.sequence can be changed, but it's not recommended doing it
# while the throbber is running. self.sequence[0] should always
# refer to whatever frame is to be shown when 'resting' and be sure
# that no item in self.sequence >= self.frames or < 0!!!
self.sequence = range(self.frames)
self.SetClientSize((width, height))
timerID = wx.NewId()
self.timer = wx.Timer(self, timerID)
EVT_UPDATE_THROBBER(self, self.Rotate)
wx.EVT_PAINT(self, self.OnPaint)
wx.EVT_TIMER(self, timerID, self.OnTimer)
wx.EVT_WINDOW_DESTROY(self, self.OnDestroyWindow)
def OnTimer(self, event):
wx.PostEvent(self, UpdateThrobberEvent())
def OnDestroyWindow(self, event):
self.Stop()
event.Skip()
def Draw(self, dc):
dc.DrawBitmap(self.submaps[self.sequence[self.current]], 0, 0, True)
if self.overlay and self.showOverlay:
dc.DrawBitmap(self.overlay, self.overlayX, self.overlayY, True)
if self.label and self.showLabel:
dc.DrawText(self.label, self.labelX, self.labelY)
dc.SetTextForeground(wx.WHITE)
dc.DrawText(self.label, self.labelX-1, self.labelY-1)
def OnPaint(self, event):
self.Draw(wx.PaintDC(self))
event.Skip()
def Rotate(self, event):
self.current += self.direction
if self.current >= len(self.sequence):
if self.autoReverse:
self.Reverse()
self.current = len(self.sequence) - 1
else:
self.current = 1
if self.current < 1:
if self.autoReverse:
self.Reverse()
self.current = 1
else:
self.current = len(self.sequence) - 1
self.Draw(wx.ClientDC(self))
# --------- public methods ---------
def SetFont(self, font):
"""Set the font for the label"""
wx.Panel.SetFont(self, font)
self.SetLabel(self.label)
self.Draw(wx.ClientDC(self))
def Rest(self):
"""Stop the animation and return to frame 0"""
self.Stop()
self.current = 0
self.Draw(wx.ClientDC(self))
def Reverse(self):
"""Change the direction of the animation"""
self.direction = -self.direction
def Running(self):
"""Returns True if the animation is running"""
return self.running
def Start(self):
"""Start the animation"""
if not self.running:
self.running = not self.running
self.timer.Start(self.frameDelay * 1000)
def Stop(self):
"""Stop the animation"""
if self.running:
self.timer.Stop()
self.running = not self.running
def SetFrameDelay(self, frameDelay = 0.05):
"""Delay between each frame"""
self.frameDelay = frameDelay
if self.running:
self.Stop()
self.Start()
def ToggleOverlay(self, state = None):
"""Toggle the overlay image"""
if state is None:
self.showOverlay = not self.showOverlay
else:
self.showOverlay = state
self.Draw(wx.ClientDC(self))
def ToggleLabel(self, state = None):
"""Toggle the label"""
if state is None:
self.showLabel = not self.showLabel
else:
self.showLabel = state
self.Draw(wx.ClientDC(self))
def SetLabel(self, label):
"""Change the text of the label"""
self.label = label
if label:
extentX, extentY = self.GetTextExtent(label)
self.labelX = (self.width - extentX)/2
self.labelY = (self.height - extentY)/2
self.Draw(wx.ClientDC(self))
# ------------------------------------------------------------------------------
__doc__ = wx.lib.throbber.__doc__
EVT_UPDATE_THROBBER = wx.lib.throbber.EVT_UPDATE_THROBBER
Throbber = wx.lib.throbber.Throbber
UpdateThrobberEvent = wx.lib.throbber.UpdateThrobberEvent

File diff suppressed because it is too large Load Diff

View File

@@ -1,569 +1,8 @@
"""
VTK is now including a package for using VTK with wxPython, so this
module is now officially nothing but ancient history. If for some
strange reason you really need this code (I don't know why, it didn't
work all that well anyway,) then just remove the triple quotes below.
I'm told that the module from Kitware is excellent and so you should
really use it. See the URL below to get a copy from CVS.
## This file imports items from the wx package into the wxPython package for
## backwards compatibility. Some names will also have a 'wx' added on if
## that is how they used to be named in the old wxPython package.
http://public.kitware.com/cgi-bin/cvsweb.cgi/VTK/Wrapping/Python/vtk/wx/
"""
import wx.lib.vtk
print __doc__
__doc__ = wx.lib.vtk.__doc__
'''
#----------------------------------------------------------------------
# Name: wxPython.lib.vtk
# Purpose: Provides a wrapper around the vtkRenderWindow from the
# VTK Visualization Toolkit. Requires the VTK Python
# extensions from http://www.kitware.com/
#
# Author: Robin Dunn
#
# Created: 16-Nov-1999
# RCS-ID: $Id$
# Copyright: (c) 1999 by Total Control Software
# Licence: wxWindows license
#----------------------------------------------------------------------
# This class has been rewritten and improved by Prabhu Ramachandran
# <prabhu@aero.iitm.ernet.in>. It has been tested under Win32 and
# Linux. Many thanks to Eric Boix <frog@creatis.insa-lyon.fr> for
# testing it under Windows and finding and fixing many errors.
# Thanks also to Sebastien BARRE <sebastien@barre.nom.fr> for his
# suggestions.
try:
from vtkpython import *
except ImportError:
raise ImportError, "VTK extension module not found"
from wxPython.wx import *
import math
#----------------------------------------------------------------------
DEBUG = 0
def debug(msg):
if DEBUG:
print msg
class wxVTKRenderWindowBase(wxWindow):
"""
A base class that enables one to embed a vtkRenderWindow into
a wxPython widget. This class embeds the RenderWindow correctly
under different platforms. Provided are some empty methods that
can be overloaded to provide a user defined interaction behaviour.
The event handling functions have names that are similar to the
ones in the vtkInteractorStyle class included with VTK.
"""
def __init__(self, parent, id, position=wxDefaultPosition,
size=wxDefaultSize, style=0):
wxWindow.__init__(self, parent, id, position, size, style | wxWANTS_CHARS)
self._RenderWindow = vtkRenderWindow()
self.__InExpose = 0
self.__Created = 0
if wxPlatform != '__WXMSW__':
# We can't get the handle in wxGTK until after the widget
# is created, the window create event happens later so we'll
# catch it there
EVT_WINDOW_CREATE(self, self.OnCreateWindow)
EVT_PAINT (self, self.OnExpose)
else:
# but in MSW, the window create event happens durring the above
# call to __init__ so we have to do it here.
hdl = self.GetHandle()
self._RenderWindow.SetWindowInfo(str(hdl))
EVT_PAINT (self, self.OnExpose)
self.__Created = 1
# common for all platforms
EVT_SIZE (self, self.OnConfigure)
# setup the user defined events.
self.SetupEvents()
def SetupEvents(self):
"Setup the user defined event bindings."
# Remember to bind everything to self.box and NOT self
EVT_LEFT_DOWN (self, self.OnLeftButtonDown)
EVT_MIDDLE_DOWN (self, self.OnMiddleButtonDown)
EVT_RIGHT_DOWN (self, self.OnRightButtonDown)
EVT_LEFT_UP (self, self.OnLeftButtonUp)
EVT_MIDDLE_UP (self, self.OnMiddleButtonUp)
EVT_RIGHT_UP (self, self.OnRightButtonUp)
EVT_MOTION (self, self.OnMouseMove)
EVT_ENTER_WINDOW (self, self.OnEnter)
EVT_LEAVE_WINDOW (self, self.OnLeave)
EVT_CHAR (self, self.OnChar)
# Add your bindings if you want them in the derived class.
def GetRenderer(self):
self._RenderWindow.GetRenderers().InitTraversal()
return self._RenderWindow.GetRenderers().GetNextItem()
def GetRenderWindow(self):
return self._RenderWindow
def Render(self):
if self.__Created:
# if block needed because calls to render before creation
# will prevent the renderwindow from being embedded into a
# wxPython widget.
self._RenderWindow.Render()
def OnExpose(self, event):
# I need this for the MDIDemo. Somehow OnCreateWindow was
# not getting called.
if not self.__Created:
self.OnCreateWindow(event)
if (not self.__InExpose):
self.__InExpose = 1
dc = wxPaintDC(self)
self._RenderWindow.Render()
self.__InExpose = 0
def OnCreateWindow(self, event):
hdl = self.GetHandle()
try:
self._RenderWindow.SetParentInfo(str(hdl))
except:
self._RenderWindow.SetWindowInfo(str(hdl))
msg = "Warning:\n "\
"Unable to call vtkRenderWindow.SetParentInfo\n\n"\
"Using the SetWindowInfo method instead. This\n"\
"is likely to cause a lot of flicker when\n"\
"rendering in the vtkRenderWindow. Please\n"\
"use a recent Nightly VTK release (later than\n"\
"March 10 2001) to eliminate this problem."
dlg = wxMessageDialog(NULL, msg, "Warning!",
wxOK |wxICON_INFORMATION)
dlg.ShowModal()
dlg.Destroy()
self.__Created = 1
def OnConfigure(self, event):
sz = self.GetSize()
self.SetSize(sz)
# Ugly hack that according to Eric Boix is necessary under
# Windows. If possible Try commenting this out and test under
# Windows.
#self._RenderWindow.GetSize()
#
self._RenderWindow.SetSize(sz.width, sz.height)
def OnLeftButtonDown(self, event):
"Left mouse button pressed."
pass
def OnMiddleButtonDown(self, event):
"Middle mouse button pressed."
pass
def OnRightButtonDown(self, event):
"Right mouse button pressed."
pass
def OnLeftButtonUp(self, event):
"Left mouse button released."
pass
def OnMiddleButtonUp(self, event):
"Middle mouse button released."
pass
def OnRightButtonUp(self, event):
"Right mouse button released."
pass
def OnMouseMove(self, event):
"Mouse has moved."
pass
def OnEnter(self, event):
"Entering the vtkRenderWindow."
pass
def OnLeave(self, event):
"Leaving the vtkRenderWindow."
pass
def OnChar(self, event):
"Process Key events."
pass
def OnKeyDown(self, event):
"Key pressed down."
pass
def OnKeyUp(self, event):
"Key released."
pass
class wxVTKRenderWindow(wxVTKRenderWindowBase):
"""
An example of a fully functional wxVTKRenderWindow that is
based on the vtkRenderWidget.py provided with the VTK sources.
"""
def __init__(self, parent, id, position=wxDefaultPosition,
size=wxDefaultSize, style=0):
wxVTKRenderWindowBase.__init__(self, parent, id, position, size,
style)
self._CurrentRenderer = None
self._CurrentCamera = None
self._CurrentZoom = 1.0
self._CurrentLight = None
self._ViewportCenterX = 0
self._ViewportCenterY = 0
self._Picker = vtkCellPicker()
self._PickedAssembly = None
self._PickedProperty = vtkProperty()
self._PickedProperty.SetColor(1,0,0)
self._PrePickedProperty = None
self._OldFocus = None
# these record the previous mouse position
self._LastX = 0
self._LastY = 0
def OnLeftButtonDown(self, event):
"Left mouse button pressed."
self.StartMotion(event)
def OnMiddleButtonDown(self, event):
"Middle mouse button pressed."
self.StartMotion(event)
def OnRightButtonDown(self, event):
"Right mouse button pressed."
self.StartMotion(event)
def OnLeftButtonUp(self, event):
"Left mouse button released."
self.EndMotion(event)
def OnMiddleButtonUp(self, event):
"Middle mouse button released."
self.EndMotion(event)
def OnRightButtonUp(self, event):
"Right mouse button released."
self.EndMotion(event)
def OnMouseMove(self, event):
event.x, event.y = event.GetPositionTuple()
if event.LeftIsDown():
if event.ShiftDown():
self.Pan(event.x, event.y)
else:
self.Rotate(event.x, event.y)
elif event.MiddleIsDown():
self.Pan(event.x, event.y)
elif event.RightIsDown():
self.Zoom(event.x, event.y)
def OnEnter(self, event):
self.__OldFocus = wxWindow_FindFocus()
self.SetFocus()
x, y = event.GetPositionTuple()
self.UpdateRenderer(x,y)
def OnLeave(self, event):
if (self._OldFocus != None):
self.__OldFocus.SetFocus()
def OnChar(self, event):
key = event.KeyCode()
if (key == ord('r')) or (key == ord('R')):
self.Reset()
elif (key == ord('w')) or (key == ord('W')):
self.Wireframe()
elif (key == ord('s')) or (key == ord('S')):
self.Surface()
elif (key == ord('p')) or (key == ord('P')):
x, y = event.GetPositionTuple()
self.PickActor(x, y)
else:
event.Skip()
# Start of internal functions
def GetZoomFactor(self):
return self._CurrentZoom
def SetZoomFactor(self, zf):
self._CurrentZoom = zf
def GetPicker(self):
return self._Picker
def Render(self):
if (self._CurrentLight):
light = self._CurrentLight
light.SetPosition(self._CurrentCamera.GetPosition())
light.SetFocalPoint(self._CurrentCamera.GetFocalPoint())
wxVTKRenderWindowBase.Render(self)
def UpdateRenderer(self, x, y):
"""
UpdateRenderer will identify the renderer under the mouse and set
up _CurrentRenderer, _CurrentCamera, and _CurrentLight.
"""
sz = self.GetSize()
windowX = sz.width
windowY = sz.height
renderers = self._RenderWindow.GetRenderers()
numRenderers = renderers.GetNumberOfItems()
self._CurrentRenderer = None
renderers.InitTraversal()
for i in range(0,numRenderers):
renderer = renderers.GetNextItem()
vx,vy = (0,0)
if (windowX > 1):
vx = float (x)/(windowX-1)
if (windowY > 1):
vy = (windowY-float(y)-1)/(windowY-1)
(vpxmin,vpymin,vpxmax,vpymax) = renderer.GetViewport()
if (vx >= vpxmin and vx <= vpxmax and
vy >= vpymin and vy <= vpymax):
self._CurrentRenderer = renderer
self._ViewportCenterX = float(windowX)*(vpxmax-vpxmin)/2.0\
+vpxmin
self._ViewportCenterY = float(windowY)*(vpymax-vpymin)/2.0\
+vpymin
self._CurrentCamera = self._CurrentRenderer.GetActiveCamera()
lights = self._CurrentRenderer.GetLights()
lights.InitTraversal()
self._CurrentLight = lights.GetNextItem()
break
self._LastX = x
self._LastY = y
def GetCurrentRenderer(self):
return self._CurrentRenderer
def StartMotion(self, event):
x, y = event.GetPositionTuple()
self.UpdateRenderer(x,y)
self.CaptureMouse()
def EndMotion(self, event=None):
if self._CurrentRenderer:
self.Render()
self.ReleaseMouse()
def Rotate(self,x,y):
if self._CurrentRenderer:
self._CurrentCamera.Azimuth(self._LastX - x)
self._CurrentCamera.Elevation(y - self._LastY)
self._CurrentCamera.OrthogonalizeViewUp()
self._LastX = x
self._LastY = y
self._CurrentRenderer.ResetCameraClippingRange()
self.Render()
def PanAbsolute(self, x_vec, y_vec):
if self._CurrentRenderer:
renderer = self._CurrentRenderer
camera = self._CurrentCamera
(pPoint0,pPoint1,pPoint2) = camera.GetPosition()
(fPoint0,fPoint1,fPoint2) = camera.GetFocalPoint()
if (camera.GetParallelProjection()):
renderer.SetWorldPoint(fPoint0,fPoint1,fPoint2,1.0)
renderer.WorldToDisplay()
fx,fy,fz = renderer.GetDisplayPoint()
renderer.SetDisplayPoint(fx+x_vec,
fy+y_vec,
fz)
renderer.DisplayToWorld()
fx,fy,fz,fw = renderer.GetWorldPoint()
camera.SetFocalPoint(fx,fy,fz)
renderer.SetWorldPoint(pPoint0,pPoint1,pPoint2,1.0)
renderer.WorldToDisplay()
fx,fy,fz = renderer.GetDisplayPoint()
renderer.SetDisplayPoint(fx+x_vec,
fy+y_vec,
fz)
renderer.DisplayToWorld()
fx,fy,fz,fw = renderer.GetWorldPoint()
camera.SetPosition(fx,fy,fz)
else:
(fPoint0,fPoint1,fPoint2) = camera.GetFocalPoint()
# Specify a point location in world coordinates
renderer.SetWorldPoint(fPoint0,fPoint1,fPoint2,1.0)
renderer.WorldToDisplay()
# Convert world point coordinates to display coordinates
dPoint = renderer.GetDisplayPoint()
focalDepth = dPoint[2]
aPoint0 = self._ViewportCenterX + x_vec
aPoint1 = self._ViewportCenterY + y_vec
renderer.SetDisplayPoint(aPoint0,aPoint1,focalDepth)
renderer.DisplayToWorld()
(rPoint0,rPoint1,rPoint2,rPoint3) = renderer.GetWorldPoint()
if (rPoint3 != 0.0):
rPoint0 = rPoint0/rPoint3
rPoint1 = rPoint1/rPoint3
rPoint2 = rPoint2/rPoint3
camera.SetFocalPoint((fPoint0 - rPoint0) + fPoint0,
(fPoint1 - rPoint1) + fPoint1,
(fPoint2 - rPoint2) + fPoint2)
camera.SetPosition((fPoint0 - rPoint0) + pPoint0,
(fPoint1 - rPoint1) + pPoint1,
(fPoint2 - rPoint2) + pPoint2)
self.Render()
def Pan(self, x, y):
self.PanAbsolute(x - self._LastX, - y + self._LastY)
self._LastX = x
self._LastY = y
def Zoom(self,x,y):
if self._CurrentRenderer:
renderer = self._CurrentRenderer
camera = self._CurrentCamera
zoomFactor = math.pow(1.02,(0.5*(self._LastY - y)))
self._CurrentZoom = self._CurrentZoom * zoomFactor
if camera.GetParallelProjection():
parallelScale = camera.GetParallelScale()/zoomFactor
camera.SetParallelScale(parallelScale)
else:
camera.Dolly(zoomFactor)
renderer.ResetCameraClippingRange()
self._LastX = x
self._LastY = y
self.Render()
def Reset(self):
if self._CurrentRenderer:
self._CurrentRenderer.ResetCamera()
self.Render()
def Wireframe(self):
actors = self._CurrentRenderer.GetActors()
numActors = actors.GetNumberOfItems()
actors.InitTraversal()
for i in range(0,numActors):
actor = actors.GetNextItem()
actor.GetProperty().SetRepresentationToWireframe()
self.Render()
def Surface(self):
actors = self._CurrentRenderer.GetActors()
numActors = actors.GetNumberOfItems()
actors.InitTraversal()
for i in range(0,numActors):
actor = actors.GetNextItem()
actor.GetProperty().SetRepresentationToSurface()
self.Render()
def PickActor(self,x,y):
if self._CurrentRenderer:
renderer = self._CurrentRenderer
picker = self._Picker
windowY = self.GetSize().height
picker.Pick(x,(windowY - y - 1),0.0,renderer)
assembly = picker.GetAssembly()
if (self._PickedAssembly != None and
self._PrePickedProperty != None):
self._PickedAssembly.SetProperty(self._PrePickedProperty)
# release hold of the property
self._PrePickedProperty.UnRegister(self._PrePickedProperty)
self._PrePickedProperty = None
if (assembly != None):
self._PickedAssembly = assembly
self._PrePickedProperty = self._PickedAssembly.GetProperty()
# hold onto the property
self._PrePickedProperty.Register(self._PrePickedProperty)
self._PickedAssembly.SetProperty(self._PickedProperty)
self.Render()
'''

View File

@@ -1,470 +0,0 @@
"""
This is a port of Konrad Hinsen's tkPlotCanvas.py plotting module.
After thinking long and hard I came up with the name "wxPlotCanvas.py".
This file contains two parts; first the re-usable library stuff, then, after
a "if __name__=='__main__'" test, a simple frame and a few default plots
for testing.
Harm van der Heijden, feb 1999
Original comment follows below:
# This module defines a plot widget for Tk user interfaces.
# It supports only elementary line plots at the moment.
# See the example at the end for documentation...
#
# Written by Konrad Hinsen <hinsen@cnrs-orleans.fr>
# With contributions from RajGopal Srinivasan <raj@cherubino.med.jhmi.edu>
# Last revision: 1998-7-28
#
"""
from wxPython import wx
# Not everybody will have Numeric, so let's be cool about it...
try:
import Numeric
except:
# bummer!
msg = """This module requires the Numeric module, which could not be
imported. It probably is not installed (it's not part of the standard
Python distribution). See the Python site (http://www.python.org) for
information on downloading source or binaries."""
if wx.wxPlatform == '__WXMSW__':
d = wx.wxMessageDialog(wx.NULL, msg, "Numeric not found")
if d.ShowModal() == wx.wxID_CANCEL:
d = wx.wxMessageDialog(wx.NULL, "I kid you not! Pressing Cancel won't help you!", "Not a joke", wx.wxOK)
d.ShowModal()
else:
print msg
raise ImportError
#
# Plotting classes...
#
class PolyPoints:
def __init__(self, points, attr):
self.points = Numeric.array(points)
self.scaled = self.points
self.attributes = {}
for name, value in self._attributes.items():
try:
value = attr[name]
except KeyError: pass
self.attributes[name] = value
def boundingBox(self):
return Numeric.minimum.reduce(self.points), \
Numeric.maximum.reduce(self.points)
def scaleAndShift(self, scale=1, shift=0):
self.scaled = scale*self.points+shift
class PolyLine(PolyPoints):
def __init__(self, points, **attr):
PolyPoints.__init__(self, points, attr)
_attributes = {'color': 'black',
'width': 1}
def draw(self, dc):
color = self.attributes['color']
width = self.attributes['width']
arguments = []
dc.SetPen(wx.wxPen(wx.wxNamedColour(color), width))
dc.DrawLines(map(tuple,self.scaled))
class PolyMarker(PolyPoints):
def __init__(self, points, **attr):
PolyPoints.__init__(self, points, attr)
_attributes = {'color': 'black',
'width': 1,
'fillcolor': None,
'size': 2,
'fillstyle': wx.wxSOLID,
'outline': 'black',
'marker': 'circle'}
def draw(self, dc):
color = self.attributes['color']
width = self.attributes['width']
size = self.attributes['size']
fillcolor = self.attributes['fillcolor']
fillstyle = self.attributes['fillstyle']
marker = self.attributes['marker']
dc.SetPen(wx.wxPen(wx.wxNamedColour(color),width))
if fillcolor:
dc.SetBrush(wx.wxBrush(wx.wxNamedColour(fillcolor),fillstyle))
else:
dc.SetBrush(wx.wxBrush(wx.wxNamedColour('black'), wx.wxTRANSPARENT))
self._drawmarkers(dc, self.scaled, marker, size)
def _drawmarkers(self, dc, coords, marker,size=1):
f = eval('self._' +marker)
for xc, yc in coords:
f(dc, xc, yc, size)
def _circle(self, dc, xc, yc, size=1):
dc.DrawEllipse(xc-2.5*size,yc-2.5*size,5.*size,5.*size)
def _dot(self, dc, xc, yc, size=1):
dc.DrawPoint(xc,yc)
def _square(self, dc, xc, yc, size=1):
dc.DrawRectangle(xc-2.5*size,yc-2.5*size,5.*size,5.*size)
def _triangle(self, dc, xc, yc, size=1):
dc.DrawPolygon([(-0.5*size*5,0.2886751*size*5),
(0.5*size*5,0.2886751*size*5),
(0.0,-0.577350*size*5)],xc,yc)
def _triangle_down(self, dc, xc, yc, size=1):
dc.DrawPolygon([(-0.5*size*5,-0.2886751*size*5),
(0.5*size*5,-0.2886751*size*5),
(0.0,0.577350*size*5)],xc,yc)
def _cross(self, dc, xc, yc, size=1):
dc.DrawLine(xc-2.5*size,yc-2.5*size,xc+2.5*size,yc+2.5*size)
dc.DrawLine(xc-2.5*size,yc+2.5*size,xc+2.5*size,yc-2.5*size)
def _plus(self, dc, xc, yc, size=1):
dc.DrawLine(xc-2.5*size,yc,xc+2.5*size,yc)
dc.DrawLine(xc,yc-2.5*size,xc,yc+2.5*size)
class PlotGraphics:
def __init__(self, objects):
self.objects = objects
def boundingBox(self):
p1, p2 = self.objects[0].boundingBox()
for o in self.objects[1:]:
p1o, p2o = o.boundingBox()
p1 = Numeric.minimum(p1, p1o)
p2 = Numeric.maximum(p2, p2o)
return p1, p2
def scaleAndShift(self, scale=1, shift=0):
for o in self.objects:
o.scaleAndShift(scale, shift)
def draw(self, canvas):
for o in self.objects:
o.draw(canvas)
def __len__(self):
return len(self.objects)
def __getitem__(self, item):
return self.objects[item]
class PlotCanvas(wx.wxWindow):
def __init__(self, parent, id=-1,
pos = wx.wxDefaultPosition, size = wx.wxDefaultSize,
style = 0, name = 'plotCanvas'):
wx.wxWindow.__init__(self, parent, id, pos, size, style, name)
self.border = (1,1)
self.SetClientSizeWH(400,400)
self.SetBackgroundColour(wx.wxNamedColour("white"))
wx.EVT_SIZE(self,self.reconfigure)
wx.EVT_PAINT(self, self.OnPaint)
self._setsize()
self.last_draw = None
# self.font = self._testFont(font)
def OnPaint(self, event):
pdc = wx.wxPaintDC(self)
if self.last_draw is not None:
apply(self.draw, self.last_draw + (pdc,))
def reconfigure(self, event):
(new_width,new_height) = self.GetClientSizeTuple()
if new_width == self.width and new_height == self.height:
return
self._setsize()
# self.redraw()
def _testFont(self, font):
if font is not None:
bg = self.canvas.cget('background')
try:
item = CanvasText(self.canvas, 0, 0, anchor=NW,
text='0', fill=bg, font=font)
self.canvas.delete(item)
except TclError:
font = None
return font
def _setsize(self):
(self.width,self.height) = self.GetClientSizeTuple();
self.plotbox_size = 0.97*Numeric.array([self.width, -self.height])
xo = 0.5*(self.width-self.plotbox_size[0])
yo = self.height-0.5*(self.height+self.plotbox_size[1])
self.plotbox_origin = Numeric.array([xo, yo])
def draw(self, graphics, xaxis = None, yaxis = None, dc = None):
if dc == None: dc = wx.wxClientDC(self)
dc.BeginDrawing()
dc.Clear()
self.last_draw = (graphics, xaxis, yaxis)
p1, p2 = graphics.boundingBox()
xaxis = self._axisInterval(xaxis, p1[0], p2[0])
yaxis = self._axisInterval(yaxis, p1[1], p2[1])
text_width = [0., 0.]
text_height = [0., 0.]
if xaxis is not None:
p1[0] = xaxis[0]
p2[0] = xaxis[1]
xticks = self._ticks(xaxis[0], xaxis[1])
bb = dc.GetTextExtent(xticks[0][1])
text_height[1] = bb[1]
text_width[0] = 0.5*bb[0]
bb = dc.GetTextExtent(xticks[-1][1])
text_width[1] = 0.5*bb[0]
else:
xticks = None
if yaxis is not None:
p1[1] = yaxis[0]
p2[1] = yaxis[1]
yticks = self._ticks(yaxis[0], yaxis[1])
for y in yticks:
bb = dc.GetTextExtent(y[1])
text_width[0] = max(text_width[0],bb[0])
h = 0.5*bb[1]
text_height[0] = h
text_height[1] = max(text_height[1], h)
else:
yticks = None
text1 = Numeric.array([text_width[0], -text_height[1]])
text2 = Numeric.array([text_width[1], -text_height[0]])
scale = (self.plotbox_size-text1-text2) / (p2-p1)
shift = -p1*scale + self.plotbox_origin + text1
self._drawAxes(dc, xaxis, yaxis, p1, p2,
scale, shift, xticks, yticks)
graphics.scaleAndShift(scale, shift)
graphics.draw(dc)
dc.EndDrawing()
def _axisInterval(self, spec, lower, upper):
if spec is None:
return None
if spec == 'minimal':
if lower == upper:
return lower-0.5, upper+0.5
else:
return lower, upper
if spec == 'automatic':
range = upper-lower
if range == 0.:
return lower-0.5, upper+0.5
log = Numeric.log10(range)
power = Numeric.floor(log)
fraction = log-power
if fraction <= 0.05:
power = power-1
grid = 10.**power
lower = lower - lower % grid
mod = upper % grid
if mod != 0:
upper = upper - mod + grid
return lower, upper
if type(spec) == type(()):
lower, upper = spec
if lower <= upper:
return lower, upper
else:
return upper, lower
raise ValueError, str(spec) + ': illegal axis specification'
def _drawAxes(self, dc, xaxis, yaxis,
bb1, bb2, scale, shift, xticks, yticks):
dc.SetPen(wx.wxPen(wx.wxNamedColour('BLACK'),1))
if xaxis is not None:
lower, upper = xaxis
text = 1
for y, d in [(bb1[1], -3), (bb2[1], 3)]:
p1 = scale*Numeric.array([lower, y])+shift
p2 = scale*Numeric.array([upper, y])+shift
dc.DrawLine(p1[0],p1[1],p2[0],p2[1])
for x, label in xticks:
p = scale*Numeric.array([x, y])+shift
dc.DrawLine(p[0],p[1],p[0],p[1]+d)
if text:
dc.DrawText(label,p[0],p[1])
text = 0
if yaxis is not None:
lower, upper = yaxis
text = 1
h = dc.GetCharHeight()
for x, d in [(bb1[0], -3), (bb2[0], 3)]:
p1 = scale*Numeric.array([x, lower])+shift
p2 = scale*Numeric.array([x, upper])+shift
dc.DrawLine(p1[0],p1[1],p2[0],p2[1])
for y, label in yticks:
p = scale*Numeric.array([x, y])+shift
dc.DrawLine(p[0],p[1],p[0]-d,p[1])
if text:
dc.DrawText(label,p[0]-dc.GetTextExtent(label)[0],
p[1]-0.5*h)
text = 0
def _ticks(self, lower, upper):
ideal = (upper-lower)/7.
log = Numeric.log10(ideal)
power = Numeric.floor(log)
fraction = log-power
factor = 1.
error = fraction
for f, lf in self._multiples:
e = Numeric.fabs(fraction-lf)
if e < error:
error = e
factor = f
grid = factor * 10.**power
if power > 3 or power < -3:
format = '%+7.0e'
elif power >= 0:
digits = max(1, int(power))
format = '%' + `digits`+'.0f'
else:
digits = -int(power)
format = '%'+`digits+2`+'.'+`digits`+'f'
ticks = []
t = -grid*Numeric.floor(-lower/grid)
while t <= upper:
ticks.append( (t, format % (t,)) )
t = t + grid
return ticks
_multiples = [(2., Numeric.log10(2.)), (5., Numeric.log10(5.))]
def redraw(self,dc=None):
if self.last_draw is not None:
apply(self.draw, self.last_draw + (dc,))
def clear(self):
self.canvas.delete('all')
#---------------------------------------------------------------------------
# if running standalone...
#
# ...a sample implementation using the above
#
if __name__ == '__main__':
def _InitObjects():
# 100 points sin function, plotted as green circles
data1 = 2.*Numeric.pi*Numeric.arange(200)/200.
data1.shape = (100, 2)
data1[:,1] = Numeric.sin(data1[:,0])
markers1 = PolyMarker(data1, color='green', marker='circle',size=1)
# 50 points cos function, plotted as red line
data1 = 2.*Numeric.pi*Numeric.arange(100)/100.
data1.shape = (50,2)
data1[:,1] = Numeric.cos(data1[:,0])
lines = PolyLine(data1, color='red')
# A few more points...
pi = Numeric.pi
markers2 = PolyMarker([(0., 0.), (pi/4., 1.), (pi/2, 0.),
(3.*pi/4., -1)], color='blue',
fillcolor='green', marker='cross')
return PlotGraphics([markers1, lines, markers2])
class AppFrame(wx.wxFrame):
def __init__(self, parent, id, title):
wx.wxFrame.__init__(self, parent, id, title,
wx.wxPyDefaultPosition, wx.wxSize(400, 400))
# Now Create the menu bar and items
self.mainmenu = wx.wxMenuBar()
menu = wx.wxMenu()
menu.Append(200, '&Print...', 'Print the current plot')
wx.EVT_MENU(self, 200, self.OnFilePrint)
menu.Append(209, 'E&xit', 'Enough of this already!')
wx.EVT_MENU(self, 209, self.OnFileExit)
self.mainmenu.Append(menu, '&File')
menu = wx.wxMenu()
menu.Append(210, '&Draw', 'Draw plots')
wx.EVT_MENU(self,210,self.OnPlotDraw)
menu.Append(211, '&Redraw', 'Redraw plots')
wx.EVT_MENU(self,211,self.OnPlotRedraw)
menu.Append(212, '&Clear', 'Clear canvas')
wx.EVT_MENU(self,212,self.OnPlotClear)
self.mainmenu.Append(menu, '&Plot')
menu = wx.wxMenu()
menu.Append(220, '&About', 'About this thing...')
wx.EVT_MENU(self, 220, self.OnHelpAbout)
self.mainmenu.Append(menu, '&Help')
self.SetMenuBar(self.mainmenu)
# A status bar to tell people what's happening
self.CreateStatusBar(1)
self.client = PlotCanvas(self)
def OnFilePrint(self, event):
d = wx.wxMessageDialog(self,
"""As of this writing, printing support in wxPython is shaky at best.
Are you sure you want to do this?""", "Danger!", wx.wxYES_NO)
if d.ShowModal() == wx.wxID_YES:
psdc = wx.wxPostScriptDC("out.ps", wx.True, self)
self.client.redraw(psdc)
def OnFileExit(self, event):
self.Close()
def OnPlotDraw(self, event):
self.client.draw(_InitObjects(),'automatic','automatic');
def OnPlotRedraw(self,event):
self.client.redraw()
def OnPlotClear(self,event):
self.client.last_draw = None
dc = wx.wxClientDC(self.client)
dc.Clear()
def OnHelpAbout(self, event):
about = wx.wxMessageDialog(self, __doc__, "About...", wx.wxOK)
about.ShowModal()
class MyApp(wx.wxApp):
def OnInit(self):
frame = AppFrame(wx.NULL, -1, "wxPlotCanvas")
frame.Show(wx.True)
self.SetTopWindow(frame)
return wx.True
app = MyApp(0)
app.MainLoop()
#----------------------------------------------------------------------------

View File

@@ -1,270 +1,12 @@
#----------------------------------------------------------------------
# Name: wxPython.lib.wxpTag
# Purpose: A wxHtmlTagHandler that knows how to build and place
# wxPython widgets onto web pages.
#
# Author: Robin Dunn
#
# Created: 13-Sept-1999
# RCS-ID: $Id$
# Copyright: (c) 1999 by Total Control Software
# Licence: wxWindows license
#----------------------------------------------------------------------
## This file imports items from the wx package into the wxPython package for
## backwards compatibility. Some names will also have a 'wx' added on if
## that is how they used to be named in the old wxPython package.
'''
wxPython.lib.wxpTag
import wx.lib.wxpTag
This module contains a wxHtmlTagHandler that knows how to build
and place wxPython widgets onto wxHtmlWindow web pages.
__doc__ = wx.lib.wxpTag.__doc__
You don\'t need to use anything in this module directly, just
importing it will create the tag handler and add it to any
wxHtmlWinParsers created from that time forth.
Tags of the following form are recognised:
<WXP class="classname" [module="modulename"] [width="num"] [height="num"]>
<PARAM name="parameterName" value="parameterValue>
...
</WXP>
where modulename is the name of a module (possibly in package
notation) to import and classname is the name of a class in that
module to create an instance of. If the module tag-attribute is not
given or is an empty string, then wxPython.wx is used. The width and
height attributes are expected to be integers and will be passed to
the __init__ method of the class as a wxSize object named size.
However, if the width attribute ends with the percent (%) symbol then
the value will be used as a percentage of the available width and the
wxHtmlWindow will manage the size.
The name-value pairs in all the nested PARAM tags are packaged up as
strings into a python dictionary and passed to the __init__ method of
the class as keyword arguments. This means that they are all
accessible from the __init__ method as regular parameters, or you use
the special Python **kw syntax in your __init__ method to get the
dictionary directly.
Some parameter values are special and if they are present then they will
be converted from strings to alternate datatypes. They are:
id If the value of id can be converted to an integer, it will
be. Otherwise it is assumed to be the name of an integer
variable in the module.
colours Any value of the form "#123ABC" will automatically be
converted to a wxColour object.
Py Types Any value begining with "(", "[" or "{" are expected to
be a Python tuple, list, or dictionary and eval()
will be used to convert them to that type. If the
eval() fails then the original string value will be
preserved.
wx Types Any value begining with "wx" is expected to be an attempt
to create a wxPython object, such as a wxSize, etc.
The eval() will be used to try and construct the
object and if it fails then the original string value
will be used instead.
An example:
<wxp module="" class="wxButton">
<param name="label" value="Click here">
<param name="id" value="wxID_OK">
</wxp>
Both the begining and ending WXP tags are required.
In the future support will be added for another tag that can be
embedded between the two begining and ending WXP tags and will
facilitate calling methods of the widget to help initialize it.
Additionally, support may be added to fetch the module from a web
server as is done with java applets.
'''
#----------------------------------------------------------------------
from wxPython.wx import *
from wxPython.html import *
import wxPython.wx
import types
#----------------------------------------------------------------------
WXPTAG = 'WXP'
PARAMTAG = 'PARAM'
#----------------------------------------------------------------------
class wxpTagHandler(wxHtmlWinTagHandler):
def __init__(self):
wxHtmlWinTagHandler.__init__(self)
self.ctx = None
def GetSupportedTags(self):
return WXPTAG+','+PARAMTAG
def HandleTag(self, tag):
name = tag.GetName()
if name == WXPTAG:
return self.HandleWxpTag(tag)
elif name == PARAMTAG:
return self.HandleParamTag(tag)
else:
raise ValueError, 'unknown tag: ' + name
def HandleWxpTag(self, tag):
# create a new context object
self.ctx = _Context()
# find and import the module
modName = ''
if tag.HasParam('MODULE'):
modName = tag.GetParam('MODULE')
if modName:
self.ctx.classMod = _my_import(modName)
else:
self.ctx.classMod = wxPython.wx
# find and verify the class
if not tag.HasParam('CLASS'):
raise AttributeError, "WXP tag requires a CLASS attribute"
className = tag.GetParam('CLASS')
self.ctx.classObj = getattr(self.ctx.classMod, className)
if type(self.ctx.classObj) != types.ClassType:
raise TypeError, "WXP tag attribute CLASS must name a class"
# now look for width and height
width = -1
height = -1
if tag.HasParam('WIDTH'):
width = tag.GetParam('WIDTH')
if width[-1] == '%':
self.ctx.floatWidth = int(width[:-1], 0)
width = self.ctx.floatWidth
else:
width = int(width)
if tag.HasParam('HEIGHT'):
height = int(tag.GetParam('HEIGHT'))
self.ctx.kwargs['size'] = wxSize(width, height)
# parse up to the closing tag, and gather any nested Param tags.
self.ParseInner(tag)
# create the object
parent = self.GetParser().GetWindow()
if parent:
obj = apply(self.ctx.classObj,
(parent,),
self.ctx.kwargs)
obj.Show(True)
# add it to the HtmlWindow
self.GetParser().GetContainer().InsertCell(wxHtmlWidgetCell(obj, self.ctx.floatWidth))
self.ctx = None
return True
def HandleParamTag(self, tag):
if not tag.HasParam('NAME'):
return False
name = tag.GetParam('NAME')
value = ""
if tag.HasParam('VALUE'):
value = tag.GetParam('VALUE')
# check for a param named 'id'
if name == 'id':
theID = -1
try:
theID = int(value)
except ValueError:
theID = getattr(self.ctx.classMod, value)
value = theID
# check for something that should be evaluated
elif value[0] in '[{(' or value[:2] == 'wx':
saveVal = value
try:
value = eval(value, self.ctx.classMod.__dict__)
except:
value = saveVal
# convert to wxColour
elif value[0] == '#':
try:
red = int('0x'+value[1:3], 16)
green = int('0x'+value[3:5], 16)
blue = int('0x'+value[5:], 16)
value = wxColor(red, green, blue)
except:
pass
self.ctx.kwargs[str(name)] = value
return False
#----------------------------------------------------------------------
# just a place to hold some values
class _Context:
def __init__(self):
self.kwargs = {}
self.width = -1
self.height = -1
self.classMod = None
self.classObj = None
self.floatWidth = 0
#----------------------------------------------------------------------
# Function to assist with importing packages
def _my_import(name):
mod = __import__(name)
components = name.split('.')
for comp in components[1:]:
mod = getattr(mod, comp)
return mod
#----------------------------------------------------------------------
# Function to parse a param string (of the form 'item=value item2="value etc"'
# and creates a dictionary
def _param2dict(param):
i = 0; j = 0; s = len(param); d = {}
while 1:
while i<s and param[i] == " " : i = i+1
if i>=s: break
j = i
while j<s and param[j] != "=": j=j+1
if j+1>=s:
break
word = param[i:j]
i=j+1
if (param[i] == '"'):
j=i+1
while j<s and param[j] != '"' : j=j+1
if j == s: break
val = param[i+1:j]
elif (param[i] != " "):
j=i+1
while j<s and param[j] != " " : j=j+1
val = param[i:j]
else:
val = ""
i=j+1
d[word] = val
return d
#----------------------------------------------------------------------
wxHtmlWinParser_AddTagHandler(wxpTagHandler)
_Context = wx.lib.wxpTag._Context
_my_import = wx.lib.wxpTag._my_import
_param2dict = wx.lib.wxpTag._param2dict
wxpTagHandler = wx.lib.wxpTag.wxpTagHandler