Merge recent wxPython changes from 2.8 branch to HEAD

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@46675 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Robin Dunn 2007-06-23 20:50:39 +00:00
parent e31f4da5f0
commit fe45b493dc
50 changed files with 7989 additions and 2997 deletions

View File

@ -200,6 +200,10 @@ WXDLLVER = '%d%d' % (VER_MAJOR, VER_MINOR)
WXPY_SRC = '.' # Assume we're in the source tree already, but allow the
# user to change it, particularly for extension building.
ARCH = '' # If this is set, add an -arch XXX flag to cflags
# Only tested (and presumably, needed) for OS X universal
# binary builds created using lipo.
#----------------------------------------------------------------------
@ -271,7 +275,7 @@ for flag in [ 'BUILD_ACTIVEX', 'BUILD_DLLWIDGET',
# String options
for option in ['WX_CONFIG', 'SYS_WX_CONFIG', 'WXDLLVER', 'BUILD_BASE',
'WXPORT', 'SWIG', 'CONTRIBS_INC', 'WXPY_SRC', 'FLAVOUR',
'VER_FLAGS',
'VER_FLAGS', 'ARCH',
]:
for x in range(len(sys.argv)):
if sys.argv[x].find(option) == 0:
@ -483,7 +487,10 @@ class wx_install_headers(distutils.command.install_headers.install_headers):
return
root = self.root
if root is None or WXPREFIX.startswith(root):
#print "WXPREFIX is %s, root is %s" % (WXPREFIX, root)
# hack for universal builds, which append i386/ppc
# to the root
if root is None or WXPREFIX.startswith(os.path.dirname(root)):
root = ''
for header, location in headers:
install_dir = os.path.normpath(root +
@ -600,9 +607,9 @@ def adjustLFLAGS(lflags, libdirs, libs):
# remove any flags for universal binaries, we'll get those from
# distutils instead
return [flag for flag in newLFLAGS
if flag not in ['-isysroot', '-arch', 'ppc', 'i386'] and
not flag.startswith('/Developer') ]
return newLFLAGS #[flag for flag in newLFLAGS
# if flag not in ['-isysroot', '-arch', 'ppc', 'i386'] and
# not flag.startswith('/Developer') ]
@ -789,6 +796,14 @@ elif os.name == 'posix':
GENDIR = 'mac'
libs = ['stdc++']
NO_SCRIPTS = 1
if not ARCH == "":
cflags.append("-arch")
cflags.append(ARCH)
lflags.append("-arch")
lflags.append(ARCH)
#if ARCH == "ppc":
# cflags.append("-isysroot")
# cflags.append("/Developer/SDKs/MacOSX10.3.9.sdk")
else:

View File

@ -1442,7 +1442,10 @@ class wxPythonDemo(wx.Frame):
menu = wx.Menu()
findItem = wx.MenuItem(menu, -1, '&Find\tCtrl-F', 'Find in the Demo Code')
findItem.SetBitmap(images.catalog['find'].getBitmap())
findNextItem = wx.MenuItem(menu, -1, 'Find &Next\tF3', 'Find Next')
if 'wxMac' not in wx.PlatformInfo:
findNextItem = wx.MenuItem(menu, -1, 'Find &Next\tF3', 'Find Next')
else:
findNextItem = wx.MenuItem(menu, -1, 'Find &Next\tCtrl-G', 'Find Next')
findNextItem.SetBitmap(images.catalog['findnext'].getBitmap())
menu.AppendItem(findItem)
menu.AppendItem(findNextItem)
@ -1455,8 +1458,9 @@ class wxPythonDemo(wx.Frame):
inspToolItem = wx.MenuItem(menu, -1, 'Open &Widget Inspector\tF6',
'A tool that lets you browse the live widgets and sizers in an application')
inspToolItem.SetBitmap(images.catalog['inspect'].getBitmap())
menu.AppendItem(inspToolItem)
menu.AppendSeparator()
menu.AppendItem(inspToolItem)
if 'wxMac' not in wx.PlatformInfo:
menu.AppendSeparator()
helpItem = menu.Append(-1, '&About wxPython Demo', 'wxPython RULES!!!')
wx.App.SetMacAboutMenuItemId(helpItem.GetId())

View File

@ -176,15 +176,17 @@ class RichTextFrame(wx.Frame):
def OnFileOpen(self, evt):
# TODO: Use RichTextBuffer.GetExtWildcard to get the wildcard string
# This gives us a string suitable for the file dialog based on
# the file handlers that are loaded
wildcard, types = rt.RichTextBuffer.GetExtWildcard(save=False)
dlg = wx.FileDialog(self, "Choose a filename",
wildcard="All files (*.*)|*.*",
wildcard=wildcard,
style=wx.OPEN)
if dlg.ShowModal() == wx.ID_OK:
path = dlg.GetPath()
if path:
# TODO: use the filter index to determine what file type to use
self.rtc.LoadFile(path, rt.RICHTEXT_TYPE_TEXT)
fileType = types[dlg.GetFilterIndex()]
self.rtc.LoadFile(path, fileType)
dlg.Destroy()
@ -193,20 +195,53 @@ class RichTextFrame(wx.Frame):
self.OnFileSaveAs(evt)
return
self.rtc.SaveFile()
def OnFileSaveAs(self, evt):
# TODO: Use RichTextBuffer.GetExtWildcard to get the wildcard string
wildcard, types = rt.RichTextBuffer.GetExtWildcard(save=True)
dlg = wx.FileDialog(self, "Choose a filename",
wildcard="All files (*.*)|*.*",
wildcard=wildcard,
style=wx.SAVE)
if dlg.ShowModal() == wx.ID_OK:
path = dlg.GetPath()
if path:
self.rtc.SaveFile(path)
fileType = types[dlg.GetFilterIndex()]
ext = rt.RichTextBuffer.FindHandlerByType(fileType).GetExtension()
if not path.endswith(ext):
path += '.' + ext
self.rtc.SaveFile(path, fileType)
dlg.Destroy()
def OnFileViewHTML(self, evt): pass
def OnFileViewHTML(self, evt):
# Get an instance of the html file handler, use it to save the
# document to a StringIO stream, and then display the
# resulting html text in a dialog with a HtmlWindow.
handler = rt.RichTextHTMLHandler()
handler.SetFlags(rt.RICHTEXT_HANDLER_SAVE_IMAGES_TO_MEMORY)
handler.SetFontSizeMapping([7,9,11,12,14,22,100])
import cStringIO
stream = cStringIO.StringIO()
if not handler.SaveStream(self.rtc.GetBuffer(), stream):
return
import wx.html
dlg = wx.Dialog(self, title="HTML", style=wx.DEFAULT_DIALOG_STYLE|wx.RESIZE_BORDER)
html = wx.html.HtmlWindow(dlg, size=(500,400), style=wx.BORDER_SUNKEN)
html.SetPage(stream.getvalue())
btn = wx.Button(dlg, wx.ID_CANCEL)
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(html, 1, wx.ALL|wx.EXPAND, 5)
sizer.Add(btn, 0, wx.ALL|wx.CENTER, 10)
dlg.SetSizer(sizer)
sizer.Fit(dlg)
dlg.ShowModal()
handler.DeleteTemporaryImages()
def OnFileExit(self, evt):
@ -533,6 +568,7 @@ class RichTextFrame(wx.Frame):
#----------------------------------------------------------------------
class TestPanel(wx.Panel):
def __init__(self, parent, log):
self.log = log
@ -541,6 +577,30 @@ class TestPanel(wx.Panel):
b = wx.Button(self, -1, "Show the RichTextCtrl sample", (50,50))
self.Bind(wx.EVT_BUTTON, self.OnButton, b)
self.AddRTCHandlers()
def AddRTCHandlers(self):
# make sure we haven't already added them.
if rt.RichTextBuffer.FindHandlerByType(rt.RICHTEXT_TYPE_HTML) is not None:
return
# This would normally go in your app's OnInit method. I'm
# not sure why these file handlers are not loaded by
# default by the C++ richtext code, I guess it's so you
# can change the name or extension if you wanted...
rt.RichTextBuffer.AddHandler(rt.RichTextHTMLHandler())
rt.RichTextBuffer.AddHandler(rt.RichTextXMLHandler())
# ...like this
rt.RichTextBuffer.AddHandler(rt.RichTextXMLHandler(name="Other XML",
ext="ox",
type=99))
# This is needed for the view as HTML option since we tell it
# to store the images in the memory file system.
wx.FileSystem.AddHandler(wx.MemoryFSHandler())
def OnButton(self, evt):
win = RichTextFrame(self, -1, "wx.richtext.RichTextCtrl",
@ -548,10 +608,12 @@ class TestPanel(wx.Panel):
style = wx.DEFAULT_FRAME_STYLE)
win.Show(True)
# give easy access to PyShell if it's running
# give easy access to the demo's PyShell if it's running
self.rtfrm = win
self.rtc = win.rtc
#----------------------------------------------------------------------
def runTest(frame, nb, log):

View File

@ -9,6 +9,7 @@ class TestPanel(wx.Panel):
wx.Panel.__init__(self, parent, -1)
sizer = wx.FlexGridSizer(0, 3, 5, 5)
sizer.AddGrowableCol(1)
box = wx.BoxSizer(wx.VERTICAL)
fs = self.GetFont().GetPointSize()
bf = wx.Font(fs+4, wx.SWISS, wx.NORMAL, wx.BOLD)
@ -38,7 +39,7 @@ class TestPanel(wx.Panel):
0, wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL)
sizer.Add(wx.TextCtrl(self, -1, func(*args),
size=(275,-1), style=wx.TE_READONLY),
0, wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL)
0, wx.EXPAND|wx.ALIGN_CENTER_VERTICAL)
btn = wx.Button(self, wx.ID_HELP)
sizer.Add(btn)
@ -64,7 +65,8 @@ class TestPanel(wx.Panel):
wx.StandardPaths.ResourceCat_Messages )
self.Bind(wx.EVT_BUTTON, self.OnShowDoc, id=wx.ID_HELP)
box.Add(sizer, 0, wx.CENTER|wx.ALL, 10)
box.Add(sizer, 0, wx.CENTER|wx.EXPAND|wx.ALL, 20)
self.SetSizer(box)

View File

@ -211,10 +211,13 @@ class TestPanel(wx.Panel):
def OnButton(self, evt):
win = TestFrame(self, self.log)
win.Show(True)
self.win = TestFrame(self, self.log)
self.win.Show(True)
def ShutdownDemo(self):
self.win.Close()
#---------------------------------------------------------------------------

View File

@ -5,7 +5,7 @@ debug=no
reswig=no
all=no
if [ "$1" = "all" ]; then
if [ "$1" = all ]; then
all=yes
else
PY_VERSION=$1
@ -99,7 +99,7 @@ if [ "$OSTYPE" = "cygwin" ]; then
$WXWIN/wxPython/distrib/makedemo
$TOOLS/Python$PY_VERSION/python `cygpath -d $WXWIN/wxPython/distrib/make_installer_inno4.py` $UNICODE_FLAG
elif [ "$OSTYPE" = "darwin" ]; then
elif [ "${OSTYPE:0:6}" = "darwin" ]; then
OSX_VERSION=`sw_vers -productVersion`
echo "OS X Version: ${OSX_VERSION:0:4}"
cd $WXWIN/wxPython

View File

@ -276,7 +276,10 @@ if [ $skipbuild != yes ]; then
export WXROOT
export BUILDPREFIX=$PREFIX
export INSTALLDIR=$INSTALLROOT$PREFIX
$WXDIR/distrib/scripts/mac/macbuild wxpython universal $CHARTYPE
$WXDIR/distrib/scripts/mac/macbuild-lipo wxpython $CHARTYPE
if [ $? != 0 ]; then
exit $?
fi
else
make $MAKEJOBS
make $MAKEJOBS -C contrib/src/gizmos
@ -289,20 +292,60 @@ if [ $skipbuild != yes ]; then
fi
# Build wxPython
if [ $universal = yes ]; then
# build ppc, then i386, then lipo them together
ARCH=ppc
export CXX="g++-3.3 -DMAC_OS_X_VERSION_MAX_ALLOWED=1030"
export CC="gcc-3.3 -DMAC_OS_X_VERSION_MAX_ALLOWED=1030"
export MACOSX_DEPLOYMENT_TARGET=10.3
mkdir -p $INSTALLROOT/$ARCH
mkdir -p $WXBLD/$ARCH
echo "Building wxPython for PPC..."
cd $WXROOT/wxPython
$PYTHON setup.py \
UNICODE=$PYUNICODEOPT \
NO_SCRIPTS=1 \
EP_ADD_OPTS=1 \
WX_CONFIG="$INSTALLROOT/$PREFIX/bin/wx-config --prefix=$INSTALLROOT$PREFIX" \
BUILD_BASE=$WXBLD/$ARCH/wxPython \
ARCH="$ARCH" \
build
ARCH=i386
export CXX="g++-4.0 -arch i386"
export CC="gcc-4.0 -arch i386"
export MACOSX_DEPLOYMENT_TARGET=10.4
mkdir -p $INSTALLROOT/$ARCH
mkdir -p $WXBLD/$ARCH
echo "Building wxPython for Intel..."
cd $WXROOT/wxPython
$PYTHON setup.py \
UNICODE=$PYUNICODEOPT \
NO_SCRIPTS=1 \
EP_ADD_OPTS=1 \
WX_CONFIG="$INSTALLROOT/$PREFIX/bin/wx-config --prefix=$INSTALLROOT$PREFIX" \
BUILD_BASE=$WXBLD/$ARCH/wxPython \
ARCH="$ARCH" \
build
else
cd $WXROOT/wxPython
$PYTHON setup.py \
UNICODE=$PYUNICODEOPT \
NO_SCRIPTS=1 \
EP_ADD_OPTS=1 \
WX_CONFIG="$WXBLD_CONFIG --inplace" \
BUILD_BASE=$WXBLD/wxPython \
SWIG=$SWIGBIN \
USE_SWIG=$SWIGIT \
build
fi
fi
#----------------------------------------------------------------------
if [ $skipinstall != yes ]; then
# Install wxWidgets
cd $WXBLD
@ -317,17 +360,51 @@ if [ $skipinstall != yes ]; then
rm wx-config
ln -s ../lib/wx/config/* wx-config
# and wxPython
if [ $universal == yes ]; then
ARCH=ppc
export CXX="g++-3.3 -DMAC_OS_X_VERSION_MAX_ALLOWED=1030"
export CC="gcc-3.3 -DMAC_OS_X_VERSION_MAX_ALLOWED=1030"
export MACOSX_DEPLOYMENT_TARGET=10.3
cd $WXROOT/wxPython
$PYTHON setup.py \
UNICODE=$PYUNICODEOPT \
NO_SCRIPTS=1 \
EP_ADD_OPTS=1 \
WX_CONFIG="$INSTALLROOT$PREFIX/bin/wx-config --prefix=$INSTALLROOT$PREFIX" \
BUILD_BASE=$WXBLD/$ARCH/wxPython \
install \
--root=$INSTALLROOT/$ARCH
ARCH=i386
export CXX="g++-4.0 -arch i386"
export CC="gcc-4.0 -arch i386"
export MACOSX_DEPLOYMENT_TARGET=10.4
cd $WXROOT/wxPython
$PYTHON setup.py \
UNICODE=$PYUNICODEOPT \
NO_SCRIPTS=1 \
EP_ADD_OPTS=1 \
WX_CONFIG="$INSTALLROOT$PREFIX/bin/wx-config --prefix=$INSTALLROOT$PREFIX" \
BUILD_BASE=$WXBLD/$ARCH/wxPython \
install \
--root=$INSTALLROOT/$ARCH
echo "Lipoing $INSTALLROOT/ppc and $INSTALLROOT/i386..."
$PYTHON $WXROOT/distrib/scripts/mac/lipo-dir.py $INSTALLROOT/ppc $INSTALLROOT/i386 $INSTALLROOT
rm -rf $INSTALLROOT/ppc $INSTALLROOT/i386
else
cd $WXROOT/wxPython
$PYTHON setup.py \
UNICODE=$PYUNICODEOPT \
NO_SCRIPTS=1 \
EP_ADD_OPTS=1 \
WX_CONFIG="$INSTALLROOT$PREFIX/bin/wx-config --prefix=$INSTALLROOT$PREFIX" \
BUILD_BASE=$WXBLD/wxPython \
install \
--root=$INSTALLROOT
fi
# Apple's Python Framework (such as what comes with Panther)
# sym-links the site-packages dir in the framework to

View File

@ -14,7 +14,7 @@
#define __PYISTREAM__
//----------------------------------------------------------------------
//---------------------------------------------------------------------------
// Handling of wxInputStreams by Joerg Baumann
// See stream.i for implementations
@ -34,19 +34,22 @@ public:
void close();
void flush();
bool eof();
PyObject* read(int size=-1);
PyObject* readline(int size=-1);
PyObject* readlines(int sizehint=-1);
void seek(int offset, int whence=0);
int tell();
/* do these later?
bool isatty();
int fileno();
void truncate(int size=-1);
void write(wxString data);
void writelines(wxStringPtrList);
*/
PyObject* read(int size=-1);
PyObject* readline(int size=-1);
PyObject* readlines(int sizehint=-1);
// do these later?
//bool isatty();
//int fileno();
//void truncate(int size=-1);
//PyObject* next();
// It's an input stream, can't write to it.
//void write(wxString data);
//void writelines(wxStringPtrList);
// wxInputStream methods that may come in handy...
@ -86,14 +89,82 @@ protected:
virtual wxFileOffset OnSysSeek(wxFileOffset off, wxSeekMode mode);
virtual wxFileOffset OnSysTell() const;
// helper
static PyObject* getMethod(PyObject* py, char* name);
PyObject* m_read;
PyObject* m_seek;
PyObject* m_tell;
bool m_block;
};
//----------------------------------------------------------------------
//---------------------------------------------------------------------------
// C++ class wxPyOutputStream to act as base for python class wxOutputStream
// You can use it in python like a python file object.
class wxPyOutputStream {
public:
// underlying wxOutputStream
wxOutputStream* m_wxos;
public:
wxPyOutputStream(wxOutputStream* wxos) : m_wxos(wxos) {}
~wxPyOutputStream();
void close();
void flush();
bool eof();
void seek(int offset, int whence=0);
int tell();
// it's an output stream, can't read from it.
//PyObject* read(int size=-1);
//PyObject* readline(int size=-1);
//PyObject* readlines(int sizehint=-1);
// do these later?
//bool isatty();
//int fileno();
//void truncate(int size=-1);
void write(PyObject* data);
//void writelines(wxStringArray& arr);
// wxOutputStream methods that may come in handy...
void PutC(char c) { if (m_wxos) m_wxos->PutC(c); }
size_t LastWrite() { if (m_wxos) return m_wxos->LastWrite(); }
unsigned long SeekO(unsigned long pos, wxSeekMode mode = wxFromStart)
{ if (m_wxos) return m_wxos->SeekO(pos, mode); else return 0; }
unsigned long TellO() { if (m_wxos) return m_wxos->TellO(); else return 0; }
};
// This is a wxOutputStream that wraps a Python file-like
// object and calls the Python methods as needed.
class wxPyCBOutputStream : public wxOutputStream {
public:
~wxPyCBOutputStream();
virtual wxFileOffset GetLength() const;
// factory function
static wxPyCBOutputStream* create(PyObject *py, bool block=true);
wxPyCBOutputStream(const wxPyCBOutputStream& other);
protected:
// can only be created via the factory
wxPyCBOutputStream(PyObject *w, PyObject *s, PyObject *t, bool block);
// wxStreamBase methods
virtual size_t OnSysRead(void *buffer, size_t bufsize);
virtual size_t OnSysWrite(const void *buffer, size_t bufsize);
virtual wxFileOffset OnSysSeek(wxFileOffset off, wxSeekMode mode);
virtual wxFileOffset OnSysTell() const;
PyObject* m_write;
PyObject* m_seek;
PyObject* m_tell;
bool m_block;
};
//---------------------------------------------------------------------------
#endif

View File

@ -124,6 +124,8 @@ inline wxPyCoreAPI* wxPyGetCoreAPIPtr()
#define wxRect2D_helper(a,b) (wxPyGetCoreAPIPtr()->p_wxRect2D_helper(a,b))
#define wxPosition_helper(a,b) (wxPyGetCoreAPIPtr()->p_wxPosition_helper(a,b))
#define wxPyCBOutputStream_create(a, b) (wxPyGetCoreAPIPtr()->p_wxPyCBOutputStream_create(a, b))
#define wxPyCBOutputStream_copy(a) (wxPyGetCoreAPIPtr()->p_wxPyCBOutputStream_copy(a))
//----------------------------------------------------------------------
#endif

View File

@ -353,6 +353,7 @@ class wxPyClientData;
class wxPyUserData;
class wxPyOORClientData;
class wxPyCBInputStream;
class wxPyCBOutputStream;
void wxPyClientData_dtor(wxPyClientData* self);
void wxPyUserData_dtor(wxPyUserData* self);
@ -360,6 +361,9 @@ void wxPyOORClientData_dtor(wxPyOORClientData* self);
wxPyCBInputStream* wxPyCBInputStream_create(PyObject *py, bool block);
wxPyCBInputStream* wxPyCBInputStream_copy(wxPyCBInputStream* other);
wxPyCBOutputStream* wxPyCBOutputStream_create(PyObject *py, bool block);
wxPyCBOutputStream* wxPyCBOutputStream_copy(wxPyCBOutputStream* other);
//---------------------------------------------------------------------------
// Export a C API in a struct. Other modules will be able to load this from
// the wx.core module and will then have safe access to these functions, even if
@ -437,6 +441,8 @@ struct wxPyCoreAPI {
bool (*p_wxRect2D_helper)(PyObject* source, wxRect2D** obj);
bool (*p_wxPosition_helper)(PyObject* source, wxPosition** obj);
wxPyCBOutputStream* (*p_wxPyCBOutputStream_create)(PyObject *py, bool block);
wxPyCBOutputStream* (*p_wxPyCBOutputStream_copy)(wxPyCBOutputStream* other);
};

File diff suppressed because it is too large Load Diff

View File

@ -25,13 +25,18 @@ class TextDocument(wx.lib.docview.Document):
def SaveObject(self, fileObject):
view = self.GetFirstView()
fileObject.write(view.GetTextCtrl().GetValue())
val = view.GetTextCtrl().GetValue()
if wx.USE_UNICODE:
val = val.encode('utf-8')
fileObject.write(val)
return True
def LoadObject(self, fileObject):
view = self.GetFirstView()
data = fileObject.read()
if wx.USE_UNICODE:
data = data.decode('utf-8')
view.GetTextCtrl().SetValue(data)
return True
@ -93,7 +98,7 @@ class TextView(wx.lib.docview.View):
wordWrapStyle = wx.TE_WORDWRAP
else:
wordWrapStyle = wx.TE_DONTWRAP
textCtrl = wx.TextCtrl(parent, -1, pos = wx.DefaultPosition, size = parent.GetClientSize(), style = wx.TE_MULTILINE | wordWrapStyle)
textCtrl = wx.TextCtrl(parent, -1, pos = wx.DefaultPosition, size = parent.GetClientSize(), style = wx.TE_MULTILINE | wx.TE_RICH | wordWrapStyle)
textCtrl.SetFont(font)
textCtrl.SetForegroundColour(color)
textCtrl.SetValue(value)
@ -521,7 +526,7 @@ class TextOptionsPanel(wx.Panel):
nativeFont.FromString(self._textFont.GetNativeFontInfoDesc())
font = wx.NullFont
font.SetNativeFontInfo(nativeFont)
font.SetPointSize(self._sampleTextCtrl.GetFont().GetPointSize()) # Use the standard point size
#font.SetPointSize(self._sampleTextCtrl.GetFont().GetPointSize()) # Use the standard point size
self._sampleTextCtrl.SetFont(font)
self._sampleTextCtrl.SetForegroundColour(self._textColor)
self._sampleTextCtrl.SetValue(_("%d pt. %s") % (self._textFont.GetPointSize(), self._textFont.GetFaceName()))

View File

@ -0,0 +1,372 @@
#----------------------------------------------------------------------------
# Name: clroses.py
# Purpose: Class definitions for Roses interactive display programs.
#
# Author: Ric Werme
# WWW: http://WermeNH.com/roses
#
# Created: June 2007
# CVS-ID: $Id$
# Copyright: Public Domain, please give credit where credit is due.
# License: Sorry, no EULA.
#----------------------------------------------------------------------------
# This is yet another incarnation of an old graphics hack based around
# misdrawing an analytic geometry curve called a rose. The basic form is
# simply the polar coordinate function r = cos(a * theta). "a" is the
# "order" of the rose, a zero value degenerates to r = 1, a circle. While
# this program is happy to draw that, much more interesting things happen when
# one or more of the following is in effect:
# 1) The "delta theta" between points is large enough to distort the curve,
# e.g. 90 degrees will draw a square, slightly less will be interesting.
# 2) The order of the rose is too large to draw it accurately.
# 3) Vectors are drawn at less than full speed.
# 4) The program is stepping through different patterns on its own.
# While you will be able to predict some aspects of the generated patterns,
# a lot of what there is to be found is found at random!
# The rose class has all the knowledge to implement generating vector data for
# roses and handles all the timing issues. It does not have the user interface
# for changing all the drawing parameters. It offers a "vision" of what an
# ideal Roses program should be, however, callers are welcome to assert their
# independence, override defaults, ignore features, etc.
from math import sin, cos, pi
# Rose class knows about:
# > Generating points and vectors (returning data as a list of points)
# > Starting a new rose (e.g. telling user to erase old vectors)
# > Stepping from one pattern to the next.
class rose:
"Defines everything needed for drawing a rose with timers."
# The following data is accessible by callers, but there are set
# methods for most everything and various method calls to client methods
# to display current values.
style = 100 # Angular distance along curve between points
sincr = -1 # Amount to increment style by in auto mode
petals = 2 # Lobes on the rose (even values have 2X lobes)
pincr = 1 # Amount to increment petals by in auto mode
nvec = 399 # Number of vectors to draw the rose
minvec = 0 # Minimum number acceptable in automatic mode
maxvec = 3600 # Maximum number acceptable in automatic mode
skipvec = 0 # Don't draw this many at the start (cheap animations)
drawvec = 3600 # Draw only this many (cheap animations)
step = 20 # Number of vectors to draw each clock tick
draw_delay = 50 # Time between roselet calls to watch pattern draw
wait_delay = 2000 # Time between roses in automatic mode
# Other variables that the application shouldn't access.
verbose = 0 # No good way to set this at the moment.
nextpt = 0 # Next position to draw on next clock tick
# Internal states:
INT_IDLE, INT_DRAW, INT_SEARCH, INT_WAIT, INT_RESIZE = range(5)
int_state = INT_IDLE
# Command states
CMD_STOP, CMD_GO = range(2)
cmd_state = CMD_STOP
# Return full rose line (a tuple of (x, y) tuples). Not used by interactive
# clients but still useful for command line and batch clients.
# This is the "purest" code and doesn't require the App* methods defined
# by the caller.
def rose(self, style, petals, vectors):
self.nvec = vectors
self.make_tables(vectors)
line = [(1.0, 0.0)]
for i in range (1, vectors):
theta = (style * i) % vectors
r = self.cos_table[(petals * theta) % vectors]
line.append((r * self.cos_table[theta], r * self.sin_table[theta]))
line.append((1.0, 0.0))
return line
# Generate vectors for the next chunk of rose.
# This is not meant to be called from an external module, as it is closely
# coupled to parameters set up within the class and limits set up by
# restart(). Restart() initializes all data this needs to start drawing a
# pattern, and clock() calls this to compute the next batch of points and
# hear if that is the last batch. We maintain all data we need to draw each
# batch after the first. theta should be 2.0*pi * style*i/self.nvec
# radians, but we deal in terms of the lookup table so it's just the index
# that refers to the same spot.
def roselet(self):
line = []
stop = self.nextpt + self.step
keep_running = True
if stop >= self.endpt:
stop = self.endpt
keep_running = False
for i in range (self.nextpt, stop + 1):
theta = (self.style * i) % self.nvec
r = self.cos_table[(self.petals * theta) % self.nvec]
line.append((r * self.cos_table[theta], r * self.sin_table[theta]))
self.nextpt = stop
return line, keep_running
# Generate sine and cosine lookup tables. We could create data for just
# 1/4 of a circle, at least if vectors was a multiple of 4, and share a
# table for both sine and cosine, but memory is cheaper than it was in
# PDP-11 days. OTOH, small, shared tables would be more cache friendly,
# but if we were that concerned, this would be in C.
def make_tables(self, vectors):
self.sin_table = [sin(2.0 * pi * i / vectors) for i in range(vectors)]
self.cos_table = [cos(2.0 * pi * i / vectors) for i in range(vectors)]
# Rescale (x,y) data to match our window. Note the negative scaling in the
# Y direction, this compensates for Y moving down the screen, but up on
# graph paper.
def rescale(self, line, offset, scale):
for i in range(len(line)):
line[i] = (line[i][0] * scale + offset[0],
line[i][1] * (-scale) + offset[1])
return line
# Euler's Method for computing the greatest common divisor. Knuth's
# "The Art of Computer Programming" vol.2 is the standard reference,
# but the web has several good ones too. Basically this sheds factors
# that aren't in the GCD and returns when there's nothing left to shed.
# N.B. Call with a >= b.
def gcd(self, a, b):
while b != 0:
a, b = b, a % b
return a
# Erase any old vectors and start drawing a new rose. When the program
# starts, the sine and cosine tables don't exist, build them here. (Of
# course, if an __init__() method is added, move the call there.
# If we're in automatic mode, check to see if the new pattern has neither
# too few or too many vectors and skip it if so. Skip by setting up for
# a one tick wait to let us get back to the main loop so the user can
# update parameters or stop.
def restart(self):
if self.verbose:
print 'restart: int_state', self.int_state, 'cmd_state', self.cmd_state
try:
tmp = self.sin_table[0]
except:
self.make_tables(self.nvec)
new_state = self.INT_DRAW
self.takesvec = self.nvec / self.gcd(self.nvec, self.style)
if not self.takesvec & 1 and self.petals & 1:
self.takesvec /= 2
if self.cmd_state == self.CMD_GO:
if self.minvec > self.takesvec or self.maxvec < self.takesvec:
new_state = self.INT_SEARCH
self.AppSetTakesVec(self.takesvec)
self.AppClear()
self.nextpt = self.skipvec
self.endpt = min(self.takesvec, self.skipvec + self.drawvec)
old_state, self.int_state = self.int_state, new_state
if old_state == self.INT_IDLE: # Clock not running
self.clock()
elif old_state == self.INT_WAIT: # May be long delay, restart
self.AppCancelTimer()
self.clock()
else:
return 1 # If called by clock(), return and start clock
return 0 # We're in INT_IDLE or INT_WAIT, clock running
# Called from App. Recompute the center and scale values for the subsequent pattern.
# Force us into INT_RESIZE state if not already there so that in 100 ms we'll start
# to draw something to give an idea of the new size.
def resize(self, size, delay):
xsize, ysize = size
self.center = (xsize / 2, ysize / 2)
self.scale = min(xsize, ysize) / 2.1
self.repaint(delay)
# Called from App or above. From App, called with small delay because
# some window managers will produce a flood of expose events or call us
# before initialization is done.
def repaint(self, delay):
if self.int_state != self.INT_RESIZE:
# print 'repaint after', delay
self.int_state = self.INT_RESIZE
self.AppCancelTimer()
self.AppAfter(delay, self.clock)
# Method that returns the next style and petal values for automatic
# mode and remembers them internally. Keep things scaled in the
# range [0:nvec) because there's little reason to exceed that.
def next(self):
self.style += self.sincr
self.petals += self.pincr
if self.style <= 0 or self.petals < 0:
self.style, self.petals = \
abs(self.petals) + 1, abs(self.style)
if self.style >= self.nvec:
self.style %= self.nvec # Don't bother defending against 0
if self.petals >= self.nvec:
self.petals %= self.nvec
self.AppSetParam(self.style, self.petals, self.nvec)
# Resume pattern drawing with the next one to display.
def resume(self):
self.next()
return self.restart()
# Go/Stop button.
def cmd_go_stop(self):
if self.cmd_state == self.CMD_STOP:
self.cmd_state = self.CMD_GO
self.resume() # Draw next pattern
elif self.cmd_state == self.CMD_GO:
self.cmd_state = self.CMD_STOP
self.update_labels()
# Centralize button naming to share with initialization.
# Leave colors to the application (assuming it cares), we can't guess
# what's available.
def update_labels(self):
if self.cmd_state == self.CMD_STOP:
self.AppCmdLabels(('Go', 'Redraw', 'Backward', 'Forward'))
else: # Must be in state CMD_GO
self.AppCmdLabels(('Stop', 'Redraw', 'Reverse', 'Skip'))
# Redraw/Redraw button
def cmd_redraw(self):
self.restart() # Redraw current pattern
# Backward/Reverse button
# Useful for when you see an interesting pattern and want
# to go back to it. If running, just change direction. If stopped, back
# up one step. The resume code handles the step, then we change the
# incrementers back to what they were. (Unless resume changed them too.)
def cmd_backward(self):
self.sincr = -self.sincr
self.pincr = -self.pincr
if self.cmd_state == self.CMD_STOP:
self.resume();
self.sincr = -self.sincr # Go forward again
self.pincr = -self.pincr
else:
self.AppSetIncrs(self.sincr, self.pincr)
# Forward/Skip button. CMD_STOP & CMD_GO both just call resume.
def cmd_step(self):
self.resume() # Draw next pattern
# Handler called on each timer event. This handles the metered drawing
# of a rose and the delays between them. It also registers for the next
# timer event unless we're idle (rose is done and the delay between
# roses is 0.)
def clock(self):
if self.int_state == self.INT_IDLE:
# print 'clock called in idle state'
delay = 0
elif self.int_state == self.INT_DRAW:
line, run = self.roselet()
self.AppCreateLine(self.rescale(line, self.center, self.scale))
if run:
delay = self.draw_delay
else:
if self.cmd_state == self.CMD_GO:
self.int_state = self.INT_WAIT
delay = self.wait_delay
else:
self.int_state = self.INT_IDLE
delay = 0
elif self.int_state == self.INT_SEARCH:
delay = self.resume() # May call us to start drawing
if self.int_state == self.INT_SEARCH:
delay = self.draw_delay # but not if searching.
elif self.int_state == self.INT_WAIT:
if self.cmd_state == self.CMD_GO:
delay = self.resume() # Calls us to start drawing
else:
self.int_state = self.INT_IDLE
delay = 0
elif self.int_state == self.INT_RESIZE: # Waiting for resize event stream to settle
self.AppSetParam(self.style, self.petals, self.nvec)
self.AppSetIncrs(self.sincr, self.pincr)
delay = self.restart() # Calls us to start drawing
if delay == 0:
if self.verbose:
print 'clock: going idle from state', self.int_state
else:
self.AppAfter(delay, self.clock)
# Methods to allow App to change the parameters on the screen.
# These expect to be called when the associated paramenter changes,
# but work reasonably well if several are called at once. (E.g.
# tkroses.py groups them into things that affect the visual display
# and warrant a new start, and things that just change and don't affect
# the ultimate pattern. All parameters within a group are updated
# at once even if the value hasn't changed.
# We restrict the style and petals parameters to the range [0: nvec)
# since numbers outside of that range aren't interesting. We don't
# immediately update the value in the application, we probably should.
# NW control window - key parameters
def SetStyle(self, value):
self.style = value % self.nvec
self.restart()
def SetSincr(self, value):
self.sincr = value
def SetPetals(self, value):
self.petals = value % self.nvec
self.restart()
def SetPincr(self, value):
self.pincr = value
# SW control window - vectors
def SetVectors(self, value):
self.nvec = value
self.style %= value
self.petals %= value
self.AppSetParam(self.style, self.petals, self.nvec)
self.make_tables(value)
self.restart()
def SetMinVec(self, value):
if self.maxvec >= value and self.nvec >= value:
self.minvec = value
def SetMaxVec(self, value):
if self.minvec < value:
self.maxvec = value
def SetSkipFirst(self, value):
self.skipvec = value
self.restart()
def SetDrawOnly(self, value):
self.drawvec = value
self.restart()
# SE control window - timings
def SetStep(self, value):
self.step = value
def SetDrawDelay(self, value):
self.draw_delay = value
def SetWaitDelay(self, value):
self.wait_delay = value
# Method for client to use to have us supply our defaults.
def SupplyControlValues(self):
self.update_labels()
self.AppSetParam(self.style, self.petals, self.nvec)
self.AppSetIncrs(self.sincr, self.pincr)
self.AppSetVectors(self.nvec, self.minvec, self.maxvec,
self.skipvec, self.drawvec)
self.AppSetTiming(self.step, self.draw_delay, self.wait_delay)

View File

@ -0,0 +1,544 @@
#----------------------------------------------------------------------------
# Name: wxroses.py
# Purpose: wxPython GUI using clroses.py to display a classic graphics
# hack.
#
# Author: Ric Werme, Robin Dunn.
# WWW: http://WermeNH.com/roses
#
# Created: June 2007
# CVS-ID: $Id$
# Copyright: Public Domain, please give credit where credit is due.
# License: Sorry, no EULA.
#----------------------------------------------------------------------------
# This module is responsible for everything involving GUI usage
# as clroses knows nothing about wxpython, tkintr, etc.
# There are some notes about how the Roses algorithm works in clroses.py,
# but the best reference should be at http://WermeNH.com/roses/index.html .
# There are a number of enhancements that could be done to wxRoses, and
# contributions are welcome as long as you don't destory the general
# structure, flavor, and all that. The following list is in the order
# I'd like to see done. Some are easy, some aren't, some are easy if
# you have experience in the right parts of external code.
# Brighter crossing points.
# Where many vectors cross, the display becomes washed out as a solid shape
# of light. On (antique) refresh vector graphics systems, crossing points
# are brighter because the electron beam paints the pixels multiple times.
# This gives complex patterns a lacy feel to some, and a 3-D sense to
# fluted shapes where vectors lie tangent to some curve. It would be
# nice to do the same in a bitmap buffer, the code to draw a vector is
# pretty simple, adding something that adds brightness to it via math or
# a lookup table ought to be a simple addition.
# Monochrome is so 20th century.
# There are a number of things that could be done with color. The simplest
# is to step through colors in a color list, better things to do would be
# for clroses.py to determine the length of an interesting "generator pattern,"
# e.g. the square in the opening display. Then it could change colors either
# every four vectors or cycle through the first four colors in the list.
# Bookmark that Rose!
# As you play with wxRoses, you'll come across some patterns that are
# "keepers." A bookmark mechanism would be handy.
# Save that Rose!
# It would be nice to have a Menu-bar/File/Save-as dialog to save a pattern
# as a jpg/png/gif file.
# Themes
# A pulldown option to select various themes is worthwhile. E.g.:
# Start an interesting animation,
# Select complex, lacy Roses,
# Select the author's favorites,
# Return to the initial Rose.
# Actually, all that's necessary are some pre-loaded bookmarks.
# Help text
# Standard fare, or:
# Slide show
# At CMU I created an interactive slide show that walked people through
# all the options and made suggestions about how to choose Style and Petal.
# I forget exactly what I said and may not have listings for it. At any rate,
# making the help mechanism start one of several "lessons" where it could
# control the display (without blocking the user's control) would be pretty
# straightforward.
import wx
import clroses
import wx.lib.colourselect as cs
# Class SpinPanel creates a control that includes both a StaticText widget
# which holds the the name of a parameter and a SpinCtrl widget which
# displays the current value. Values are set at initialization and can
# change via the SpinCtrl widget or by the program. So that the program
# can easily access the SpinCtrl, the SpinPanel handles are saved in the
# spin_panels dictionary.
class SpinPanel(wx.Panel):
def __init__(self, parent, name, min_value, value, max_value, callback):
wx.Panel.__init__(self, parent, -1)
if "wxMac" in wx.PlatformInfo:
self.SetWindowVariant(wx.WINDOW_VARIANT_SMALL)
self.st = wx.StaticText(self, -1, name)
self.sc = wx.SpinCtrl(self, -1, "", size = (70, -1))
self.sc.SetRange(min_value, max_value)
self.sc.SetValue(value)
self.sc.Bind(wx.EVT_SPINCTRL, self.OnSpin)
self.callback = callback
sizer = wx.BoxSizer(wx.HORIZONTAL)
sizer.Add(self.st, 0, wx.ALIGN_CENTER_VERTICAL)
sizer.Add((1,1), 1)
sizer.Add(self.sc)
self.SetSizer(sizer)
global spin_panels
spin_panels[name] = self
# Called (generally through spin_panels{}) to set the SpinCtrl value.
def SetValue(self, value):
self.sc.SetValue(value)
# Called when user changes the SpinCtrl value.
def OnSpin(self, event):
name = self.st.GetLabel()
value = self.sc.GetValue()
if verbose:
print 'OnSpin', name, '=', value
self.callback(name, value) # Call MyFrame.OnSpinback to call clroses
# This class is used to display the current rose diagram. It keeps a
# buffer bitmap of the current display, which it uses to refresh the
# screen with when needed. When it is told to draw some lines it does
# so to the buffer in order for it to always be up to date.
class RosePanel(wx.Panel):
def __init__(self, *args, **kw):
wx.Panel.__init__(self, *args, **kw)
self.InitBuffer()
self.resizeNeeded = False
self.useGCDC = False
self.useBuffer = True
# set default colors
self.SetBackgroundColour((51, 51, 51)) # gray20
self.SetForegroundColour((164, 211, 238)) # lightskyblue2
# connect the size and paint events to handlers
self.Bind(wx.EVT_SIZE, self.OnSize)
self.Bind(wx.EVT_PAINT, self.OnPaint)
self.Bind(wx.EVT_IDLE, self.OnIdle)
def InitBuffer(self):
size = self.GetClientSize()
self.buffer = wx.EmptyBitmap(max(1, size.width),
max(1, size.height))
def Clear(self):
dc = self.useBuffer and wx.MemoryDC(self.buffer) or wx.ClientDC(self)
dc.SetBackground(wx.Brush(self.GetBackgroundColour()))
dc.Clear()
if self.useBuffer:
self.Refresh(False)
def DrawLines(self, lines):
if len(lines) <= 1:
return
dc = self.useBuffer and wx.MemoryDC(self.buffer) or wx.ClientDC(self)
if self.useGCDC:
dc = wx.GCDC(dc)
dc.SetPen(wx.Pen(self.GetForegroundColour(), 1))
dc.DrawLines(lines)
if self.useBuffer:
self.Refresh(False)
def TriggerResize(self):
self.GetParent().TriggerResize(self.buffer.GetSize())
def TriggerRedraw(self):
self.GetParent().TriggerRedraw()
def OnSize(self, evt):
self.resizeNeeded = True
def OnIdle(self, evt):
if self.resizeNeeded:
self.InitBuffer()
self.TriggerResize()
if self.useBuffer:
self.Refresh()
self.resizeNeeded = False
def OnPaint(self, evt):
dc = wx.PaintDC(self)
if self.useBuffer:
dc.DrawBitmap(self.buffer, 0,0)
else:
self.TriggerRedraw()
# A panel used to collect options on how the rose is drawn
class OptionsPanel(wx.Panel):
def __init__(self, parent, rose):
wx.Panel.__init__(self, parent)
self.rose = rose
sizer = wx.StaticBoxSizer(wx.StaticBox(self, label='Options'),
wx.VERTICAL)
self.useGCDC = wx.CheckBox(self, label="Use GCDC")
sizer.Add(self.useGCDC, 0, wx.BOTTOM|wx.LEFT, 2)
self.useBuffer = wx.CheckBox(self, label="Use buffering")
sizer.Add(self.useBuffer, 0, wx.BOTTOM|wx.LEFT, 2)
def makeCButton(label):
btn = cs.ColourSelect(self, size=(20,22))
lbl = wx.StaticText(self, -1, label)
sizer = wx.BoxSizer(wx.HORIZONTAL)
sizer.Add(btn)
sizer.Add((4,4))
sizer.Add(lbl, 0, wx.ALIGN_CENTER_VERTICAL)
return sizer, btn
s, self.fg = makeCButton('Foreground')
sizer.Add(s)
s, self.bg = makeCButton('Background')
sizer.Add(s)
self.SetSizer(sizer)
self.Bind(wx.EVT_CHECKBOX, self.OnUseGCDC, self.useGCDC)
self.Bind(wx.EVT_CHECKBOX, self.OnUseBuffer, self.useBuffer)
self.Bind(wx.EVT_IDLE, self.OnIdle)
self.Bind(cs.EVT_COLOURSELECT, self.OnSetFG, self.fg)
self.Bind(cs.EVT_COLOURSELECT, self.OnSetBG, self.bg)
def OnIdle(self, evt):
if self.useGCDC.GetValue() != self.rose.useGCDC:
self.useGCDC.SetValue(self.rose.useGCDC)
if self.useBuffer.GetValue() != self.rose.useBuffer:
self.useBuffer.SetValue(self.rose.useBuffer)
if self.fg.GetValue() != self.rose.GetForegroundColour():
self.fg.SetValue(self.rose.GetForegroundColour())
if self.bg.GetValue() != self.rose.GetBackgroundColour():
self.bg.SetValue(self.rose.GetBackgroundColour())
def OnUseGCDC(self, evt):
self.rose.useGCDC = evt.IsChecked()
self.rose.TriggerRedraw()
def OnUseBuffer(self, evt):
self.rose.useBuffer = evt.IsChecked()
self.rose.TriggerRedraw()
def OnSetFG(self, evt):
self.rose.SetForegroundColour(evt.GetValue())
self.rose.TriggerRedraw()
def OnSetBG(self, evt):
self.rose.SetBackgroundColour(evt.GetValue())
self.rose.TriggerRedraw()
# MyFrame is the traditional class name to create and populate the
# application's frame. The general GUI has control/status panels on
# the right side and a panel on the left side that draws the rose
#
# This class also derives from clroses.rose so it can implement the
# required interfaces to connect the GUI to the rose engine.
class MyFrame(wx.Frame, clroses.rose):
# Color matching dictionary, convert label name to color:
# Stop and Go ala traffic lights,
# Skip and Forward look ahead to the purple mountain majesties (really bluish),
# Reverse and Backward look morosely behind to maroon memories,
# Redraw looks at the brown earth right below your feet.
# Yeah, so it's lame. All I really wanted was to color Stop and Go.
labelColours = {
'Go': 'dark green', 'Stop': 'red',
'Redraw': 'brown', 'Skip': 'dark slate blue',
'Backward': 'maroon', 'Forward': 'dark slate blue', 'Reverse': 'maroon'
}
def __init__(self):
def makeSP(name, labels, statictexts = None):
panel = wx.Panel(self.side_panel, -1)
box = wx.StaticBox(panel, -1, name)
sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
for name, min_value, value, max_value in labels:
sp = SpinPanel(panel, name, min_value, value, max_value, self.OnSpinback)
sizer.Add(sp, 0, wx.EXPAND)
if statictexts:
for name, text in statictexts:
st = wx.StaticText(panel, -1, text)
spin_panels[name] = st # Supposed to be a SpinPanel....
sizer.Add(st, 0, wx.EXPAND)
panel.SetSizer(sizer)
return panel
wx.Frame.__init__(self, None, title="Roses in wxPython")
self.rose_panel = RosePanel(self)
self.side_panel = wx.Panel(self)
# The cmd panel is four buttons whose names and foreground colors
# change. Plop them in a StaticBox like the SpinPanels. Use
# a 2x2 grid, but StaticBoxSizer can't handle that. Therefore,
# create a sub panel, layout the buttons there, then give that to
# a higher panel that has the static box stuff.
self.cmd_panel = wx.Panel(self.side_panel, -1)
self.sub_panel = wx.Panel(self.cmd_panel, -1)
sizer = wx.GridSizer(rows = 2, cols = 2)
global ctrl_buttons
border = 'wxMac' in wx.PlatformInfo and 3 or 1
for name, handler in (
('Go', self.OnGoStop),
('Redraw', self.OnRedraw),
('Backward', self.OnBackward),
('Forward', self.OnForward)):
button = wx.Button(self.sub_panel, -1, name)
button.SetForegroundColour(self.labelColours[name])
ctrl_buttons[name] = button
button.Bind(wx.EVT_BUTTON, handler)
sizer.Add(button, 0, wx.EXPAND|wx.ALL, border)
self.sub_panel.SetSizer(sizer)
# Set up cmd_panel with StaticBox stuff
box = wx.StaticBox(self.cmd_panel, -1, 'Command')
sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
sizer.Add(self.sub_panel)
self.cmd_panel.SetSizer(sizer)
# Now make the rest of the control panels...
# The order of creation of SpinCtrls and Buttons is the order that
# the tab key will step through, so the order of panel creation is
# important.
# In the SpinPanel data (name, min, value, max), value will be
# overridden by clroses.py defaults.
self.coe_panel = makeSP('Coefficient',
(('Style', 0, 100, 3600),
('Sincr', -3600, -1, 3600),
('Petal', 0, 2, 3600),
('Pincr', -3600, 1, 3600)))
self.vec_panel = makeSP('Vector',
(('Vectors' , 1, 399, 3600),
('Minimum' , 1, 1, 3600),
('Maximum' , 1, 3600, 3600),
('Skip first', 0, 0, 3600),
('Draw only' , 1, 3600, 3600)),
(('Takes', 'Takes 0000 vectors'), ))
self.tim_panel = makeSP('Timing',
(('Vec/tick' , 1, 20, 3600),
('msec/tick', 1, 50, 1000),
('Delay' , 1, 2000, 9999)))
self.opt_panel = OptionsPanel(self.side_panel, self.rose_panel)
# put them all on in a sizer attached to the side_panel
panelSizer = wx.BoxSizer(wx.VERTICAL)
panelSizer.Add(self.cmd_panel, 0, wx.EXPAND|wx.TOP|wx.LEFT|wx.RIGHT, 5)
panelSizer.Add(self.coe_panel, 0, wx.EXPAND|wx.TOP|wx.LEFT|wx.RIGHT, 5)
panelSizer.Add(self.vec_panel, 0, wx.EXPAND|wx.TOP|wx.LEFT|wx.RIGHT, 5)
panelSizer.Add(self.tim_panel, 0, wx.EXPAND|wx.TOP|wx.LEFT|wx.RIGHT, 5)
panelSizer.Add(self.opt_panel, 0, wx.EXPAND|wx.TOP|wx.LEFT|wx.RIGHT, 5)
self.side_panel.SetSizer(panelSizer)
# and now arrange the two main panels in another sizer for the frame
mainSizer = wx.BoxSizer(wx.HORIZONTAL)
mainSizer.Add(self.rose_panel, 1, wx.EXPAND)
mainSizer.Add(self.side_panel, 0, wx.EXPAND)
self.SetSizer(mainSizer)
# bind event handlers
self.timer = wx.Timer(self)
self.Bind(wx.EVT_TIMER, self.OnTimer, self.timer)
# Determine appropriate image size.
# At this point, the rose_panel and side_panel will both report
# size (20, 20). After mainSizer.Fit(self) they will report the
# same, but the Frame size, self.GetSize(), will report the desired
# side panel dimensions plus an extra 20 on the width. That lets
# us determine the frame size that will display the side panel and
# a square space for the diagram. Only after Show() will the two
# panels report the accurate sizes.
mainSizer.Fit(self)
rw, rh = self.rose_panel.GetSize()
sw, sh = self.side_panel.GetSize()
fw, fh = self.GetSize()
h = max(600, fh) # Change 600 to desired minimum size
w = h + fw - rw
if verbose:
print 'rose panel size', (rw, rh)
print 'side panel size', (sw, sh)
print ' frame size', (fw, fh)
print 'Want size', (w,h)
self.SetSize((w, h))
self.SupplyControlValues() # Ask clroses to tell us all the defaults
self.Show()
# Command button event handlers. These are relabled when changing between auto
# and manual modes. They simply reflect the call to a method in the base class.
#
# Go/Stop button
def OnGoStop(self, event):
if verbose:
print 'OnGoStop'
self.cmd_go_stop()
# Redraw/Redraw
def OnRedraw(self, event):
if verbose:
print 'OnRedraw'
self.cmd_redraw()
# Backward/Reverse
def OnBackward(self, event):
if verbose:
print 'OnBackward'
self.cmd_backward()
# Forward/Skip
def OnForward(self, event):
if verbose:
print 'OnForward'
self.cmd_step()
# The clroses.roses class expects to have methods available that
# implement the missing parts of the functionality needed to do
# the actual work of getting the diagram to the screen and etc.
# Those are implemented here as the App* methods.
def AppClear(self):
if verbose:
print 'AppClear: clear screen'
self.rose_panel.Clear()
def AppCreateLine(self, line):
# print 'AppCreateLine, len', len(line), 'next', self.nextpt
self.rose_panel.DrawLines(line)
# Here when clroses has set a new style and/or petal value, update
# strings on display.
def AppSetParam(self, style, petals, vectors):
spin_panels['Style'].SetValue(style)
spin_panels['Petal'].SetValue(petals)
spin_panels['Vectors'].SetValue(vectors)
def AppSetIncrs(self, sincr, pincr):
spin_panels['Sincr'].SetValue(sincr)
spin_panels['Pincr'].SetValue(pincr)
def AppSetVectors(self, vectors, minvec, maxvec, skipvec, drawvec):
spin_panels['Vectors'].SetValue(vectors)
spin_panels['Minimum'].SetValue(minvec)
spin_panels['Maximum'].SetValue(maxvec)
spin_panels['Skip first'].SetValue(skipvec)
spin_panels['Draw only'].SetValue(drawvec)
def AppSetTakesVec(self, takes):
spin_panels['Takes'].SetLabel('Takes %d vectors' % takes)
# clroses doesn't change this data, so it's not telling us something
# we don't already know.
def AppSetTiming(self, vecPtick, msecPtick, delay):
spin_panels['Vec/tick'].SetValue(vecPtick)
spin_panels['msec/tick'].SetValue(msecPtick)
spin_panels['Delay'].SetValue(delay)
# Command buttons change their names based on the whether we're in auto
# or manual mode.
def AppCmdLabels(self, labels):
for name, label in map(None, ('Go', 'Redraw', 'Backward', 'Forward'), labels):
ctrl_buttons[name].SetLabel(label)
ctrl_buttons[name].SetForegroundColour(self.labelColours[label])
# Timer methods. The paranoia about checking up on the callers is
# primarily because it's easier to check here. We expect that calls to
# AppAfter and OnTimer alternate, but don't verify that AppCancelTimer()
# is canceling anything as callers of that may be uncertain about what's
# happening.
# Method to provide a single callback after some amount of time.
def AppAfter(self, msec, callback):
if self.timer_callback:
print 'AppAfter: timer_callback already set!',
# print 'AppAfter:', callback
self.timer_callback = callback
self.timer.Start(msec, True)
# Method to cancel something we might be waiting for but have lost
# interest in.
def AppCancelTimer(self):
self.timer.Stop()
# print 'AppCancelTimer'
self.timer_callback = None
# When the timer happens, we come here and jump off to clroses internal code.
def OnTimer(self, evt):
callback = self.timer_callback
self.timer_callback = None
# print 'OnTimer,', callback
if callback:
callback() # Often calls AppAfter() and sets the callback
else:
print 'OnTimer: no callback!'
resize_delay = 300
def TriggerResize(self, size):
self.resize(size, self.resize_delay)
self.resize_delay = 100
def TriggerRedraw(self):
self.repaint(10)
# Called when data in spin boxes changes.
def OnSpinback(self, name, value):
if verbose:
print 'OnSpinback', name, value
if name == 'Style':
self.SetStyle(value)
elif name == 'Sincr':
self.SetSincr(value)
elif name == 'Petal':
self.SetPetals(value)
elif name == 'Pincr':
self.SetPincr(value)
elif name == 'Vectors':
self.SetVectors(value)
elif name == 'Minimum':
self.SetMinVec(value)
elif name == 'Maximum':
self.SetMaxVec(value)
elif name == 'Skip first':
self.SetSkipFirst(value)
elif name == 'Draw only':
self.SetDrawOnly(value)
elif name == 'Vec/tick':
self.SetStep(value)
elif name == 'msec/tick':
self.SetDrawDelay(value)
elif name == 'Delay':
self.SetWaitDelay(value)
else:
print 'OnSpinback: Don\'t recognize', name
verbose = 0 # Need some command line options...
spin_panels = {} # Hooks to get from rose to panel labels
ctrl_buttons = {} # Button widgets for command (NE) panel
app = wx.App(False)
MyFrame()
if verbose:
print 'spin_panels', spin_panels.keys()
print 'ctrl_buttons', ctrl_buttons.keys()
app.MainLoop()

View File

@ -482,7 +482,12 @@ wxpExtensions.append(ext)
swig_sources = run_swig(['richtext.i'], 'src', GENDIR, PKGDIR,
USE_SWIG, swig_force, swig_args, swig_deps)
USE_SWIG, swig_force, swig_args,
swig_deps + [ 'src/_richtextbuffer.i',
'src/_richtextctrl.i',
'src/_richtexthtml.i',
'src/_richtextxml.i',
])
if not MONOLITHIC and findLib('richtext', libdirs):
richLib = makeLibName('richtext')
else:
@ -569,6 +574,11 @@ if BUILD_GLCANVAS:
gl_libs = libs + ['opengl32', 'glu32'] + makeLibName('gl')
gl_lflags = lflags
if sys.platform[:6] == "darwin" and WXPORT == 'mac':
if not ARCH == "":
gl_lflags.append("-arch")
gl_lflags.append(ARCH)
ext = Extension('_glcanvas',
swig_sources,

View File

@ -24,10 +24,10 @@
//---------------------------------------------------------------------------
%{
// See http://tinyurl.com/e5adr for what premultiplying alpha means. It
// appears to me that the other platforms are already doing it, so I'll just
// automatically do it for wxMSW here.
#ifdef __WXMSW__
// See http://tinyurl.com/e5adr for what premultiplying alpha means. wxMSW and
// wxMac want to have the values premultiplied by the alpha value, but the
// other platforms don't. These macros help keep the code clean.
#if defined(__WXMSW__) || (defined(__WXMAC__) && wxMAC_USE_CORE_GRAPHICS)
#define wxPy_premultiply(p, a) ((p) * (a) / 0xff)
#define wxPy_unpremultiply(p, a) ((a) ? ((p) * 0xff / (a)) : (p))
#else
@ -500,8 +500,8 @@ def BitmapFromBuffer(width, height, dataBuffer, alphaBuffer=None):
expected to contain a series of RGB bytes and be width*height*3
bytes long. A buffer object can optionally be supplied for the
image's alpha channel data, and it is expected to be width*height
bytes long. On Windows the RGB values are 'premultiplied' by the
alpha values. (The other platforms do the multiplication
bytes long. On Windows and Mac the RGB values are 'premultiplied'
by the alpha values. (The other platforms do the multiplication
themselves.)
Unlike `wx.ImageFromBuffer` the bitmap created with this function
@ -567,8 +567,8 @@ def BitmapFromBufferRGBA(width, height, dataBuffer):
parameter must be a Python object that implements the buffer
interface, such as a string, array, etc. The dataBuffer object is
expected to contain a series of RGBA bytes (red, green, blue and
alpha) and be width*height*4 bytes long. On Windows the RGB
values are 'premultiplied' by the alpha values. (The other
alpha) and be width*height*4 bytes long. On Windows and Mac the
RGB values are 'premultiplied' by the alpha values. (The other
platforms do the multiplication themselves.)
Unlike `wx.ImageFromBuffer` the bitmap created with this function

View File

@ -35,7 +35,7 @@ Blue (RGB) intensity values, and is used to determine drawing colours,
window colours, etc. Valid RGB values are in the range 0 to 255.
In wxPython there are typemaps that will automatically convert from a
colour name, from a '#RRGGBB' colour hex value string, or from a 3
colour name, from a '#RRGGBB' colour hex value string, or from a 3 or 4
integer tuple to a wx.Colour object when calling C++ methods that
expect a wxColour. This means that the following are all
equivallent::
@ -59,7 +59,7 @@ public:
DocCtorStr(
wxColour(byte red=0, byte green=0, byte blue=0, byte alpha=wxALPHA_OPAQUE),
"Constructs a colour from red, green and blue values.
"Constructs a colour from red, green, blue and alpha values.
:see: Alternate constructors `wx.NamedColour` and `wx.ColourRGB`.
", "");
@ -165,8 +165,8 @@ is returned if the pixel is invalid (on X, unallocated).", "");
%extend {
KeepGIL(Get);
DocAStr(Get,
"Get() -> (r, g, b)",
"Returns the RGB intensity values as a tuple.", "");
"Get(self, bool includeAlpha=False) -> (r,g,b) or (r,g,b,a)",
"Returns the RGB intensity values as a tuple, optionally the alpha value as well.", "");
PyObject* Get(bool includeAlpha=false) {
PyObject* rv = PyTuple_New(includeAlpha ? 4 : 3);
int red = -1;

View File

@ -242,6 +242,8 @@ static wxPyCoreAPI API = {
wxRect2D_helper,
wxPosition_helper,
wxPyCBOutputStream_create,
wxPyCBOutputStream_copy,
};
#endif

View File

@ -93,6 +93,7 @@ typedef unsigned int size_t;
typedef unsigned int time_t;
typedef unsigned char byte;
typedef unsigned long wxUIntPtr;
typedef double wxDouble;
#define wxWindowID int
#define wxCoord int
@ -408,6 +409,19 @@ typedef unsigned long wxUIntPtr;
%enddef
#endif
#ifdef _DO_FULL_DOCS
%define %RenameDocStr(newname, docstr, details, type, decl)
%feature("docstring") decl docstr;
%rename(newname) decl;
type decl
%enddef
#else
%define %RenameDocStr(newname, docstr, details, type, decl)
%feature("docstring") decl docstr details;
%rename(newname) decl;
type decl
%enddef
#endif
//---------------------------------------------------------------------------
// Generates a base_On* method that just wraps a call to the On*, and mark it
@ -459,6 +473,204 @@ FORWARD_DECLARE(wxIcon, Icon);
FORWARD_DECLARE(wxStaticBox, StaticBox);
//---------------------------------------------------------------------------
// This macro makes a class to wrap a type specific class derived from wxList,
// and make it look like a Python sequence, including with iterator support
%define wxLIST_WRAPPER(ListClass, ItemClass)
// first a bit of C++ code...
%{
class ListClass##_iterator
{
public:
ListClass##_iterator(ListClass::compatibility_iterator start)
: m_node(start) {}
ItemClass* next() {
ItemClass* obj = NULL;
if (m_node) {
obj = m_node->GetData();
m_node = m_node->GetNext();
}
else PyErr_SetString(PyExc_StopIteration, "");
return obj;
}
private:
ListClass::compatibility_iterator m_node;
};
%}
// Now declare the classes for SWIG
DocStr(ListClass##_iterator,
"This class serves as an iterator for a ListClass object.", "");
class ListClass##_iterator
{
public:
//ListClass##_iterator();
~ListClass_iterator();
KeepGIL(next);
ItemClass* next();
};
DocStr(ListClass,
"This class wraps a wxList-based class and gives it a Python
sequence-like interface. Sequence operations supported are length,
index access and iteration.", "");
class ListClass
{
public:
//ListClass(); This will always be created by some C++ function
~ListClass();
%extend {
KeepGIL(__len__);
size_t __len__() {
return self->size();
}
KeepGIL(__getitem__);
ItemClass* __getitem__(size_t index) {
if (index < self->size()) {
ListClass::compatibility_iterator node = self->Item(index);
if (node) return node->GetData();
}
PyErr_SetString(PyExc_IndexError, "Invalid list index");
return NULL;
}
KeepGIL(__contains__);
bool __contains__(const ItemClass* obj) {
return self->Find(obj) != NULL;
}
KeepGIL(__iter__);
%newobject __iter__;
ListClass##_iterator* __iter__() {
return new ListClass##_iterator(self->GetFirst());
}
}
%pythoncode {
def __repr__(self):
return "ListClass: " + repr(list(self))
}
};
%enddef
// This macro is similar to the above, but it is to be used when there isn't a
// type-specific C++ list class to use. In other words the C++ code is using
// a plain wxList and typecasting the node values, so we'll do the same.
%define wxUNTYPED_LIST_WRAPPER(ListClass, ItemClass)
// first a bit of C++ code...
%{
class ListClass
{
public:
ListClass(wxList* theList)
: m_list(theList) {}
~ListClass() {}
public:
wxList* m_list;
};
class ListClass##_iterator
{
public:
ListClass##_iterator(wxList::compatibility_iterator start)
: m_node(start) {}
ItemClass* next() {
ItemClass* obj = NULL;
if (m_node) {
obj = (ItemClass*)m_node->GetData();
m_node = m_node->GetNext();
}
else PyErr_SetString(PyExc_StopIteration, "");
return obj;
}
private:
wxList::compatibility_iterator m_node;
};
%}
// Now declare the classes for SWIG
DocStr(ListClass##_iterator,
"This class serves as an iterator for a ListClass object.", "");
class ListClass##_iterator
{
public:
//ListClass##_iterator();
~ListClass_iterator();
KeepGIL(next);
ItemClass* next();
};
DocStr(ListClass,
"This class wraps a wxList-based class and gives it a Python
sequence-like interface. Sequence operations supported are length,
index access and iteration.", "");
class ListClass
{
public:
//ListClass(); This will always be created by some C++ function
~ListClass();
%extend {
KeepGIL(__len__);
size_t __len__() {
return self->m_list->size();
}
KeepGIL(__getitem__);
ItemClass* __getitem__(size_t index) {
if (index < self->m_list->size()) {
wxList::compatibility_iterator node = self->m_list->Item(index);
if (node) return (ItemClass*)node->GetData();
}
PyErr_SetString(PyExc_IndexError, "Invalid list index");
return NULL;
}
KeepGIL(__contains__);
bool __contains__(const ItemClass* obj) {
return self->m_list->Find(obj) != NULL;
}
KeepGIL(__iter__);
%newobject __iter__;
ListClass##_iterator* __iter__() {
return new ListClass##_iterator(self->m_list->GetFirst());
}
}
%pythoncode {
def __repr__(self):
return "ListClass: " + repr(list(self))
}
};
// A typemap to handle converting a wxList& return value to this new list
// type. To use this just change the return value type in the class
// definition to this typedef instead of wxList, then SWIG will use the
// typemap.
%{
typedef wxList ListClass##_t;
%}
%typemap(out) ListClass##_t& {
ListClass* mylist = new ListClass($1);
$result = SWIG_NewPointerObj(SWIG_as_voidptr(mylist), SWIGTYPE_p_##ListClass, SWIG_POINTER_OWN );
}
%enddef
//---------------------------------------------------------------------------
%{

View File

@ -245,7 +245,7 @@ public:
wxPyEndBlockThreads(blocked);
wxMemoryFSHandler::AddFile(filename, ptr, size);
}
}
%}
@ -280,6 +280,26 @@ public:
// Add a file to the memory FS
%pythoncode { AddFile = staticmethod(MemoryFSHandler_AddFile) }
%extend {
static void AddFileWithMimeType(const wxString& filename,
PyObject* data,
const wxString& mimetype)
{
if (! PyString_Check(data)) {
wxPyBLOCK_THREADS(PyErr_SetString(PyExc_TypeError,
"Expected string object"));
return;
}
wxPyBlock_t blocked = wxPyBeginBlockThreads();
void* ptr = (void*)PyString_AsString(data);
size_t size = PyString_Size(data);
wxPyEndBlockThreads(blocked);
wxMemoryFSHandler::AddFileWithMimeType(filename, ptr, size, mimetype);
}
}
bool CanOpen(const wxString& location);
%newobject OpenFile;
wxFSFile* OpenFile(wxFileSystem& fs, const wxString& location);

View File

@ -451,7 +451,7 @@ public:
};
MustHaveApp(wxThread);
MustHaveApp(wxThread_IsMain);
%inline %{
bool wxThread_IsMain() {
#ifdef WXP_WITH_THREAD

View File

@ -488,6 +488,9 @@ DocStr(wxRect,
width and height properties. In wxPython most palces that expect a
wx.Rect can also accept a (x,y,width,height) tuple.", "");
%typemap(in) wxRect*;
class wxRect
{
public:
@ -777,6 +780,9 @@ usually, but not necessarily, the larger one.", "");
%property(Empty, IsEmpty, doc="See `IsEmpty`");
};
%apply wxRect& { wxRect* };
MustHaveApp(wxIntersectRect);

View File

@ -350,9 +350,6 @@ MustHaveApp(wxGraphicsPath);
MustHaveApp(wxGraphicsContext);
MustHaveApp(wxGCDC);
typedef double wxDouble;
//---------------------------------------------------------------------------

View File

@ -642,6 +642,17 @@ string.", "",
bool , SaveFile( const wxString& name, const wxString& mimetype ),
"Saves an image in the named file.", "",
SaveMimeFile);
DocDeclStrName(
bool , SaveFile( wxOutputStream& stream, int type ),
"Saves an image in the named file.", "",
SaveStream);
DocDeclStrName(
bool , SaveFile( wxOutputStream& stream, const wxString& mimetype ),
"Saves an image in the named file.", "",
SaveMimeStream);
DocDeclStrName(

View File

@ -214,7 +214,8 @@ public:
void PassMessages(bool bDoPass);
bool IsPassingMessages();
wxLog *GetOldLog();
void DetachOldLog();
%property(OldLog, GetOldLog, doc="See `GetOldLog`");
};

View File

@ -16,6 +16,9 @@
//---------------------------------------------------------------------------
%newgroup
wxLIST_WRAPPER(wxMenuItemList, wxMenuItem);
MustHaveApp(wxMenu);
@ -169,12 +172,7 @@ public:
// get the items
size_t GetMenuItemCount() const;
%extend {
PyObject* GetMenuItems() {
wxMenuItemList& list = self->GetMenuItems();
return wxPy_ConvertList(&list);
}
}
wxMenuItemList& GetMenuItems();
// search
int FindItem(const wxString& item) const;

View File

@ -1,5 +1,5 @@
/////////////////////////////////////////////////////////////////////////////
// Name: _window.i
// Name: _panel.i
// Purpose: SWIG interface for wxPanel and wxScrolledWindow
//
// Author: Robin Dunn

File diff suppressed because it is too large Load Diff

1237
wxPython/src/_richtextctrl.i Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,102 @@
/////////////////////////////////////////////////////////////////////////////
// Name: _richtexthtml
// Purpose: wxRichTextHTMLHandler
//
// Author: Robin Dunn
//
// Created: 18-May-2007
// RCS-ID: $Id$
// Copyright: (c) 2007 by Total Control Software
// Licence: wxWindows license
/////////////////////////////////////////////////////////////////////////////
// Not a %module
//---------------------------------------------------------------------------
%{
#include <wx/richtext/richtexthtml.h>
%}
//---------------------------------------------------------------------------
%newgroup
MAKE_CONST_WXSTRING2(HtmlName, wxT("HTML"));
MAKE_CONST_WXSTRING2(HtmlExt, wxT("html"));
class wxRichTextHTMLHandler: public wxRichTextFileHandler
{
public:
wxRichTextHTMLHandler(const wxString& name = wxPyHtmlName,
const wxString& ext = wxPyHtmlExt,
int type = wxRICHTEXT_TYPE_HTML);
DocDeclStr(
virtual bool , CanSave() const,
"Can we save using this handler?", "");
DocDeclStr(
virtual bool , CanLoad() const,
"Can we load using this handler?", "");
DocDeclStr(
virtual bool , CanHandle(const wxString& filename) const,
"Can we handle this filename (if using files)? By default, checks the
extension.", "");
DocDeclStr(
void , SetTemporaryImageLocations(const wxArrayString& locations),
"Set the list of image locations generated by the last operation", "");
DocDeclStr(
const wxArrayString& , GetTemporaryImageLocations() const,
"Get the list of image locations generated by the last operation", "");
%property(TemporaryImageLocations, GetTemporaryImageLocations, SetTemporaryImageLocations);
DocDeclStr(
void , ClearTemporaryImageLocations(),
"Clear the image locations generated by the last operation", "");
DocDeclStr(
bool , DeleteTemporaryImages(),
"Delete the in-memory or temporary files generated by the last operation", "");
// DocDeclStr(
// static bool , DeleteTemporaryImages(int flags, const wxArrayString& imageLocations),
// "Delete the in-memory or temporary files generated by the last operation. This
// is a static function that can be used to delete the saved locations from an
// earlier operation, for example after the user has viewed the HTML file.", "");
DocDeclStr(
static void , SetFileCounter(int counter),
"Reset the file counter, in case, for example, the same names are required each
time", "");
DocDeclStr(
void , SetTempDir(const wxString& tempDir),
"Set the directory for storing temporary files. If empty, the system temporary
directory will be used.", "");
DocDeclStr(
const wxString& , GetTempDir() const,
"Get the directory for storing temporary files. If empty, the system temporary
directory will be used.", "");
%property(TempDir, GetTempDir, SetTempDir);
DocDeclStr(
void , SetFontSizeMapping(const wxArrayInt& fontSizeMapping),
"Set mapping from point size to HTML font size. There should be 7 elements, one
for each HTML font size, each element specifying the maximum point size for
that HTML font size. E.g. 8, 10, 13, 17, 22, 29, 100
", "");
DocDeclStr(
wxArrayInt , GetFontSizeMapping() const,
"Get mapping deom point size to HTML font size.", "");
%property(FontSizeMapping, GetFontSizeMapping, SetFontSizeMapping);
};
//---------------------------------------------------------------------------

View File

@ -0,0 +1,67 @@
/////////////////////////////////////////////////////////////////////////////
// Name: _richtextxml
// Purpose: wxRichTextXMLHandler
//
// Author: Robin Dunn
//
// Created: 18-May-2007
// RCS-ID: $Id$
// Copyright: (c) 2007 by Total Control Software
// Licence: wxWindows license
/////////////////////////////////////////////////////////////////////////////
// Not a %module
//---------------------------------------------------------------------------
%{
#include <wx/richtext/richtextxml.h>
%}
//---------------------------------------------------------------------------
%newgroup
MAKE_CONST_WXSTRING2(XmlName, wxT("XML"));
MAKE_CONST_WXSTRING2(XmlExt, wxT("xml"));
class wxRichTextXMLHandler: public wxRichTextFileHandler
{
public:
wxRichTextXMLHandler(const wxString& name = wxPyXmlName,
const wxString& ext = wxPyXmlExt,
int type = wxRICHTEXT_TYPE_XML);
// #if wxUSE_STREAMS
// /// Recursively export an object
// bool ExportXML(wxOutputStream& stream, wxMBConv* convMem, wxMBConv* convFile, wxRichTextObject& obj, int level);
// bool ExportStyleDefinition(wxOutputStream& stream, wxMBConv* convMem, wxMBConv* convFile, wxRichTextStyleDefinition* def, int level);
// /// Recursively import an object
// bool ImportXML(wxRichTextBuffer* buffer, wxXmlNode* node);
// bool ImportStyleDefinition(wxRichTextStyleSheet* sheet, wxXmlNode* node);
// /// Create style parameters
// wxString CreateStyle(const wxTextAttrEx& attr, bool isPara = false);
// /// Get style parameters
// bool GetStyle(wxTextAttrEx& attr, wxXmlNode* node, bool isPara = false);
// #endif
/// Can we save using this handler?
virtual bool CanSave() const;
/// Can we load using this handler?
virtual bool CanLoad() const;
// bool HasParam(wxXmlNode* node, const wxString& param);
// wxXmlNode *GetParamNode(wxXmlNode* node, const wxString& param);
// wxString GetNodeContent(wxXmlNode *node);
// wxString GetParamValue(wxXmlNode *node, const wxString& param);
// wxString GetText(wxXmlNode *node, const wxString& param = wxEmptyString, bool translate = false);
};
//---------------------------------------------------------------------------

View File

@ -169,6 +169,11 @@ border size.", "");
};
//---------------------------------------------------------------------------
%newgroup
wxLIST_WRAPPER( wxSizerItemList, wxSizerItem );
DocStr(wxSizerItem,
"The wx.SizerItem class is used to track the position, size and other
@ -1247,21 +1252,12 @@ as well.", "");
// wxList& GetChildren();
%extend {
DocAStr(GetChildren,
"GetChildren(self) -> list",
"Returns a list of all the `wx.SizerItem` objects managed by the sizer.", "");
PyObject* GetChildren() {
wxSizerItemList& list = self->GetChildren();
return wxPy_ConvertList(&list);
}
}
DocStr(GetChildren,
"Returns all of the `wx.SizerItem` objects managed by the sizer in a
list-like object.", "");
wxSizerItemList& GetChildren();
// Manage whether individual windows or subsizers are considered
// in the layout calculations or not.
%extend {
DocAStr(Show,
"Show(self, item, bool show=True, bool recursive=false) -> bool",

View File

@ -32,7 +32,7 @@ given for the Unix, Windows and Mac OS X systems, however please note
that these are just examples and the actual values may differ. For
example, under Windows the system administrator may change the
standard directories locations, i.e. the Windows directory may be
named W:\Win2003 instead of the default C:\Windows.
named W:/Win2003 instead of the default C:/Windows.
The strings appname and username should be replaced with the value
returned by `wx.App.GetAppName` and the name of the currently logged
@ -85,14 +85,14 @@ absolute path whenever possible.", "");
DocDeclStr(
virtual wxString , GetConfigDir() const,
"Return the directory with system config files: /etc under Unix,
'c:\\Documents and Settings\\All Users\\Application Data' under Windows,
'c:/Documents and Settings/All Users/Application Data' under Windows,
/Library/Preferences for Mac", "");
DocDeclStr(
virtual wxString , GetUserConfigDir() const,
"Return the directory for the user config files: $HOME under Unix,
'c:\\Documents and Settings\\username' under Windows, and
'c:/Documents and Settings/username' under Windows, and
~/Library/Preferences under Mac
Only use this if you have a single file to put there, otherwise
@ -103,7 +103,7 @@ Only use this if you have a single file to put there, otherwise
virtual wxString , GetDataDir() const,
"Return the location of the application's global, (i.e. not
user-specific,) data files: prefix/share/appname under Unix,
'c:\\Program Files\\appname' under Windows,
'c:/Program Files/appname' under Windows,
appname.app/Contents/SharedSupport app bundle directory under Mac.", "");
@ -117,8 +117,8 @@ host-specific. Same as `GetDataDir` except under Unix where it is
DocDeclStr(
virtual wxString , GetUserDataDir() const,
"Return the directory for the user-dependent application data files:
$HOME/.appname under Unix, c:\\Documents and
Settings\\username\\Application Data\\appname under Windows and
$HOME/.appname under Unix, c:/Documents and
Settings/username/Application Data/appname under Windows and
~/Library/Application Support/appname under Mac", "");
@ -128,7 +128,7 @@ Settings\\username\\Application Data\\appname under Windows and
with the other machines
Same as `GetUserDataDir` for all platforms except Windows where it is
the 'Local Settings\\Application Data\\appname' directory.", "");
the 'Local Settings/Application Data/appname' directory.", "");
DocDeclStr(
@ -168,7 +168,7 @@ standard prefix/share/locale/lang/LC_MESSAGES.)", "");
virtual wxString , GetDocumentsDir() const,
"Return the Documents directory for the current user.
C:\Documents and Settings\username\Documents under Windows,
C:/Documents and Settings/username/Documents under Windows,
$HOME under Unix and ~/Documents under Mac", "");
DocDeclStr(

View File

@ -61,18 +61,43 @@
}
}
%typemap(out) wxInputStream* {
wxPyInputStream * _ptr = NULL;
if ($1) {
if ($1)
_ptr = new wxPyInputStream($1);
}
$result = wxPyConstructObject(_ptr, wxT("wxPyInputStream"), $owner);
}
//---------------------------------------------------------------------------
// Typemaps for wxOutputStream. We only need in by reference and out by
// pointer in this one.
%typemap(in) wxOutputStream& (wxPyOutputStream* temp, bool created) {
if (wxPyConvertSwigPtr($input, (void **)&temp, wxT("wxPyOutputStream"))) {
$1 = temp->m_wxos;
created = false;
} else {
PyErr_Clear(); // clear the failure of the wxPyConvert above
$1 = wxPyCBOutputStream_create($input, false);
if ($1 == NULL) {
PyErr_SetString(PyExc_TypeError, "Expected wx.OutputStream or Python file-like object.");
SWIG_fail;
}
created = true;
}
}
%typemap(freearg) wxOutputStream& { if (created$argnum) delete $1; }
%typemap(out) wxOutputStream* {
wxPyOutputStream * _ptr = NULL;
if ($1)
_ptr = new wxPyOutputStream($1);
$result = wxPyConstructObject(_ptr, wxT("wxPyOutputStream"), $owner);
}
//---------------------------------------------------------------------------
enum wxSeekMode
@ -107,14 +132,6 @@ public:
void seek(int offset, int whence=0);
int tell();
/*
bool isatty();
int fileno();
void truncate(int size=-1);
void write(wxString data);
void writelines(wxStringPtrList);
*/
char Peek();
char GetC();
size_t LastRead();
@ -128,43 +145,41 @@ public:
// TODO: make a more fully implemented file interface...
class wxOutputStream {
public:
/*
void close();
void flush();
wxString* read(int size=-1);
wxString* readline(int size=-1);
wxStringPtrList* readlines(int sizehint=-1);
void seek(int offset, int whence=0);
int tell();
bool isatty();
int fileno();
void truncate(int size=-1);
void write(wxString data);
void writelines(wxStringPtrList);
*/
%rename(OutputStream) wxPyOutputStream;
class wxPyOutputStream
{
public:
%extend {
void write(PyObject* obj) {
// We use only strings for the streams, not unicode
PyObject* str = PyObject_Str(obj);
if (! str) {
PyErr_SetString(PyExc_TypeError, "Unable to convert to string");
return;
}
self->Write(PyString_AS_STRING(str),
PyString_GET_SIZE(str));
Py_DECREF(str);
wxPyOutputStream(PyObject* p) {
wxOutputStream* wxis = wxPyCBOutputStream::create(p);
if (wxis)
return new wxPyOutputStream(wxis);
else
return NULL;
}
}
size_t LastWrite() const;
~wxPyOutputStream();
void close();
void flush();
bool eof();
void seek(int offset, int whence=0);
int tell();
void write(PyObject* data);
//void writelines(wxStringArray& arr);
void PutC(char c);
size_t LastWrite();
unsigned long SeekO(unsigned long pos, wxSeekMode mode = wxFromStart);
unsigned long TellO();
};
//---------------------------------------------------------------------------
%init %{
wxPyPtrTypeMap_Add("wxInputStream", "wxPyInputStream");
wxPyPtrTypeMap_Add("wxOutputStream", "wxPyOutputStream");
%}
//---------------------------------------------------------------------------

View File

@ -24,6 +24,9 @@ MAKE_CONST_WXSTRING(PanelNameStr);
%newgroup
wxLIST_WRAPPER(wxWindowList, wxWindow);
DocStr(wxVisualAttributes,
"struct containing all the visual attributes of a control", "");
@ -124,9 +127,14 @@ Styles
deactivate it.
wx.VSCROLL Use this style to enable a vertical scrollbar.
Notice that this style cannot be used with
native controls which don't support scrollbars
nor with top-level windows in most ports.
wx.HSCROLL Use this style to enable a horizontal scrollbar.
The same limitations as for wx.VSCROLL apply to
this style.
wx.ALWAYS_SHOW_SB If a window has scrollbars, disable them
instead of hiding them when they are
not needed (i.e. when the size of the
@ -990,26 +998,16 @@ before win instead of putting it right after it.", "");
// parent/children relations
// -------------------------
//wxWindowList& GetChildren(); // TODO: Do a typemap or a wrapper for wxWindowList
%extend {
DocStr(GetChildren,
"Returns a list of the window's children. NOTE: Currently this is a
copy of the child window list maintained by the window, so the return
value of this function is only valid as long as the window's children
do not change.", "");
PyObject* GetChildren() {
wxWindowList& list = self->GetChildren();
return wxPy_ConvertList(&list);
}
}
"Returns an object containing a list of the window's children. The
object provides a Python sequence-like interface over the internal
list maintained by the window..", "");
wxWindowList& GetChildren();
DocDeclStr(
wxWindow *, GetParent() const,
@ -2318,14 +2316,11 @@ MustHaveApp(wxWindow_FromHWND);
//---------------------------------------------------------------------------
DocStr(GetTopLevelWindows,
"Returns a list of the the application's top-level windows, (frames,
dialogs, etc.) NOTE: Currently this is a copy of the list maintained
by wxWidgets, and so it is only valid as long as no top-level windows
are closed or new top-level windows are created.
", "");
"Returns a list-like object of the the application's top-level windows, (frames,
dialogs, etc.)", "");
%inline %{
PyObject* GetTopLevelWindows() {
return wxPy_ConvertList(&wxTopLevelWindows);
wxWindowList& GetTopLevelWindows() {
return wxTopLevelWindows;
}
%}

View File

@ -11,7 +11,7 @@
/////////////////////////////////////////////////////////////////////////////
%define DOCSTRING
"The wx.aui moduleis an Advanced User Interface library that aims to
"The wx.aui module is an Advanced User Interface library that aims to
implement \"cutting-edge\" interface usability and design features so
developers can quickly and easily create beautiful and usable
application interfaces.

View File

@ -712,6 +712,7 @@ Nearly all of the methods of this class are overridable in Python.", "");
MustHaveApp(wxPyComboPopup);
%rename(ComboPopup) wxPyComboPopup;
%typemap(out) wxPyComboCtrl* { $result = wxPyMake_wxObject($1, (bool)$owner); }
class wxPyComboPopup
{
@ -851,7 +852,6 @@ is associated with.", "");
};
//---------------------------------------------------------------------------
%newgroup

View File

@ -1090,6 +1090,21 @@ void wxPyEndBlockThreads(wxPyBlock_t blocked) {
// wxPyInputStream and wxPyCBInputStream methods
static PyObject* wxPyGetMethod(PyObject* py, char* name)
{
if (!PyObject_HasAttrString(py, name))
return NULL;
PyObject* o = PyObject_GetAttrString(py, name);
if (!PyMethod_Check(o) && !PyCFunction_Check(o)) {
Py_DECREF(o);
return NULL;
}
return o;
}
void wxPyInputStream::close() {
/* do nothing for now */
}
@ -1246,7 +1261,7 @@ void wxPyInputStream::seek(int offset, int whence) {
m_wxis->SeekI(offset, wxSeekMode(whence));
}
int wxPyInputStream::tell(){
int wxPyInputStream::tell() {
if (m_wxis)
return m_wxis->TellI();
else return 0;
@ -1285,9 +1300,9 @@ wxPyCBInputStream* wxPyCBInputStream::create(PyObject *py, bool block) {
wxPyBlock_t blocked = wxPyBlock_t_default;
if (block) blocked = wxPyBeginBlockThreads();
PyObject* read = getMethod(py, "read");
PyObject* seek = getMethod(py, "seek");
PyObject* tell = getMethod(py, "tell");
PyObject* read = wxPyGetMethod(py, "read");
PyObject* seek = wxPyGetMethod(py, "seek");
PyObject* tell = wxPyGetMethod(py, "tell");
if (!read) {
PyErr_SetString(PyExc_TypeError, "Not a file-like object");
@ -1311,17 +1326,6 @@ wxPyCBInputStream* wxPyCBInputStream_copy(wxPyCBInputStream* other) {
return new wxPyCBInputStream(*other);
}
PyObject* wxPyCBInputStream::getMethod(PyObject* py, char* name) {
if (!PyObject_HasAttrString(py, name))
return NULL;
PyObject* o = PyObject_GetAttrString(py, name);
if (!PyMethod_Check(o) && !PyCFunction_Check(o)) {
Py_DECREF(o);
return NULL;
}
return o;
}
wxFileOffset wxPyCBInputStream::GetLength() const {
wxPyCBInputStream* self = (wxPyCBInputStream*)this; // cast off const
@ -1406,6 +1410,196 @@ wxFileOffset wxPyCBInputStream::OnSysTell() const {
return o;
}
//----------------------------------------------------------------------
// Output stream
wxPyOutputStream::~wxPyOutputStream()
{
if (m_wxos)
delete m_wxos;
}
void wxPyOutputStream::close()
{
}
void wxPyOutputStream::flush()
{
}
bool wxPyOutputStream::eof()
{
return false;
}
void wxPyOutputStream::seek(int offset, int whence)
{
if (m_wxos)
m_wxos->SeekO(offset, wxSeekMode(whence));
}
int wxPyOutputStream::tell()
{
if (m_wxos)
return m_wxos->TellO();
else return 0;
}
void wxPyOutputStream::write(PyObject* data)
{
if (!m_wxos)
return;
// We use only strings for the streams, not unicode
PyObject* str = PyObject_Str(data);
if (! str) {
PyErr_SetString(PyExc_TypeError, "Unable to convert to string");
return;
}
m_wxos->Write(PyString_AS_STRING(str), PyString_GET_SIZE(str));
Py_DECREF(str);
}
wxPyCBOutputStream::wxPyCBOutputStream(PyObject *w, PyObject *s, PyObject *t, bool block)
: wxOutputStream(), m_write(w), m_seek(s), m_tell(t), m_block(block)
{}
wxPyCBOutputStream::wxPyCBOutputStream(const wxPyCBOutputStream& other)
{
m_write = other.m_write;
m_seek = other.m_seek;
m_tell = other.m_tell;
m_block = other.m_block;
Py_INCREF(m_write);
Py_INCREF(m_seek);
Py_INCREF(m_tell);
}
wxPyCBOutputStream::~wxPyCBOutputStream() {
wxPyBlock_t blocked = wxPyBlock_t_default;
if (m_block) blocked = wxPyBeginBlockThreads();
Py_XDECREF(m_write);
Py_XDECREF(m_seek);
Py_XDECREF(m_tell);
if (m_block) wxPyEndBlockThreads(blocked);
}
wxPyCBOutputStream* wxPyCBOutputStream::create(PyObject *py, bool block) {
wxPyBlock_t blocked = wxPyBlock_t_default;
if (block) blocked = wxPyBeginBlockThreads();
PyObject* write = wxPyGetMethod(py, "write");
PyObject* seek = wxPyGetMethod(py, "seek");
PyObject* tell = wxPyGetMethod(py, "tell");
if (!write) {
PyErr_SetString(PyExc_TypeError, "Not a file-like object");
Py_XDECREF(write);
Py_XDECREF(seek);
Py_XDECREF(tell);
if (block) wxPyEndBlockThreads(blocked);
return NULL;
}
if (block) wxPyEndBlockThreads(blocked);
return new wxPyCBOutputStream(write, seek, tell, block);
}
wxPyCBOutputStream* wxPyCBOutputStream_create(PyObject *py, bool block) {
return wxPyCBOutputStream::create(py, block);
}
wxPyCBOutputStream* wxPyCBOutputStream_copy(wxPyCBOutputStream* other) {
return new wxPyCBOutputStream(*other);
}
wxFileOffset wxPyCBOutputStream::GetLength() const {
wxPyCBOutputStream* self = (wxPyCBOutputStream*)this; // cast off const
if (m_seek && m_tell) {
wxFileOffset temp = self->OnSysTell();
wxFileOffset ret = self->OnSysSeek(0, wxFromEnd);
self->OnSysSeek(temp, wxFromStart);
return ret;
}
else
return wxInvalidOffset;
}
size_t wxPyCBOutputStream::OnSysRead(void *buffer, size_t bufsize) {
m_lasterror = wxSTREAM_READ_ERROR;
return 0;
}
size_t wxPyCBOutputStream::OnSysWrite(const void *buffer, size_t bufsize) {
if (bufsize == 0)
return 0;
wxPyBlock_t blocked = wxPyBeginBlockThreads();
PyObject* arglist = PyTuple_New(1);
PyTuple_SET_ITEM(arglist, 0, PyString_FromStringAndSize((char*)buffer, bufsize));
PyObject* result = PyEval_CallObject(m_write, arglist);
Py_DECREF(arglist);
if (result != NULL)
Py_DECREF(result);
else
m_lasterror = wxSTREAM_WRITE_ERROR;
wxPyEndBlockThreads(blocked);
return bufsize;
}
wxFileOffset wxPyCBOutputStream::OnSysSeek(wxFileOffset off, wxSeekMode mode) {
wxPyBlock_t blocked = wxPyBeginBlockThreads();
PyObject* arglist = PyTuple_New(2);
if (sizeof(wxFileOffset) > sizeof(long))
// wxFileOffset is a 64-bit value...
PyTuple_SET_ITEM(arglist, 0, PyLong_FromLongLong(off));
else
PyTuple_SET_ITEM(arglist, 0, PyInt_FromLong(off));
PyTuple_SET_ITEM(arglist, 1, PyInt_FromLong(mode));
PyObject* result = PyEval_CallObject(m_seek, arglist);
Py_DECREF(arglist);
Py_XDECREF(result);
wxPyEndBlockThreads(blocked);
return OnSysTell();
}
wxFileOffset wxPyCBOutputStream::OnSysTell() const {
wxPyBlock_t blocked = wxPyBeginBlockThreads();
PyObject* arglist = Py_BuildValue("()");
PyObject* result = PyEval_CallObject(m_tell, arglist);
Py_DECREF(arglist);
wxFileOffset o = 0;
if (result != NULL) {
if (PyLong_Check(result))
o = PyLong_AsLongLong(result);
else
o = PyInt_AsLong(result);
Py_DECREF(result);
};
wxPyEndBlockThreads(blocked);
return o;
}
//----------------------------------------------------------------------
IMPLEMENT_ABSTRACT_CLASS(wxPyCallback, wxObject);

View File

@ -173,6 +173,10 @@ MAKE_INT_ARRAY_TYPEMAPS(styles, styles_field)
}
%apply wxRect& { wxRect* };
%typemap(in) wxPoint2D& (wxPoint2D temp) {
$1 = &temp;
if ( ! wxPoint2D_helper($input, &$1)) SWIG_fail;

File diff suppressed because it is too large Load Diff

View File

@ -974,8 +974,11 @@ class ButtonInfo(Control):
self._shortHelp = shortHelp
self._longHelp = longHelp
disabledbmp = GrayOut(bmp)
if bmp:
disabledbmp = GrayOut(bmp)
else:
disabledbmp = wx.NullBitmap
self._bitmaps = {"Normal": bmp, "Toggled": None, "Disabled": disabledbmp,
"Hover": None, "Pressed": None}

View File

@ -140,10 +140,10 @@ class ColourSelect(wx.BitmapButton):
def SetBitmap(self, bmp):
self.SetBitmapLabel(bmp)
self.SetBitmapSelected(bmp)
self.SetBitmapDisabled(bmp)
self.SetBitmapFocus(bmp)
self.SetBitmapSelected(bmp)
#self.SetBitmapSelected(bmp)
#self.SetBitmapDisabled(bmp)
#self.SetBitmapFocus(bmp)
#self.SetBitmapSelected(bmp)
self.Refresh()

View File

@ -1459,7 +1459,7 @@ class FNBRenderer:
# erase old bitmap
posx = self.GetDropArrowButtonPos(pc)
dc.DrawBitmap(self._xBgBmp, posx, 6)
dc.DrawBitmap(self._rightBgBmp, posx, 6)
# Draw the new bitmap
dc.DrawBitmap(downBmp, posx, 6, True)
@ -3353,6 +3353,7 @@ class FlatNotebook(wx.Panel):
self._pages.DoDeletePage(page)
self.Refresh()
self.Update()
# Fire a closed event
closedEvent = FlatNotebookEvent(wxEVT_FLATNOTEBOOK_PAGE_CLOSED, self.GetId())
@ -4733,12 +4734,13 @@ class PageContainer(wx.Panel):
for i in xrange(len(self._pagesInfoVec)):
pi = self._pagesInfoVec[i]
item = wx.MenuItem(popupMenu, i, pi.GetCaption(), pi.GetCaption(), wx.ITEM_NORMAL)
item = wx.MenuItem(popupMenu, i+1, pi.GetCaption(), pi.GetCaption(), wx.ITEM_NORMAL)
self.Bind(wx.EVT_MENU, self.OnTabMenuSelection, item)
# This code is commented, since there is an alignment problem with wx2.6.3 & Menus
# if self.TabHasImage(ii):
# item.SetBitmaps( (*m_ImageList)[pi.GetImageIndex()] );
# There is an alignment problem with wx2.6.3 & Menus so only use
# images for versions above 2.6.3
if wx.VERSION > (2, 6, 3, 0) and self.TabHasImage(i):
item.SetBitmap(self.GetImageList().GetBitmap(pi.GetImageIndex()))
popupMenu.AppendItem(item)
item.Enable(pi.GetEnabled())
@ -4749,7 +4751,7 @@ class PageContainer(wx.Panel):
def OnTabMenuSelection(self, event):
""" Handles the wx.EVT_MENU event for L{PageContainer}. """
selection = event.GetId()
selection = event.GetId() - 1
self.FireEvent(selection)

View File

@ -2,18 +2,28 @@
# Name: BrowseImage.py
# Purpose: Display and Select Image Files
#
# Author: Lorne White
# Original Author: Lorne White
#
# Version: 1.0
# Date: January 29, 2002
# Version: 2.0
# Date: June 16, 2007
# Licence: wxWindows license
#----------------------------------------------------------------------------
# 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
#
# 2.0 Release - Bill Baxter (wbaxter@gmail.com)
# Date: June 16, 2007
# o Changed to use sizers instead of fixed placement.
# o Made dialog resizeable
# o Added a splitter between file list and view pane
# o Made directory path editable
# o Added an "up" button" to go to the parent dir
# o Changed to show directories in file list
# o Don't select images on double click any more
# o Added a 'broken image' display for files that wx fails to identify
# o Redesigned appearance -- using bitmap buttons now, and rearranged things
# o Fixed display of masked gifs
# o Fixed zooming logic to show shrunken images at correct aspect ratio
# o Added different background modes for preview (white/grey/dark/checkered)
# o Added framing modes for preview (no frame/box frame/tinted border)
#
#----------------------------------------------------------------------------
#
# 12/08/2003 - Jeff Grimmett (grimmtooth@softhome.net)
@ -22,18 +32,32 @@
# o Corrected a nasty bug or two - see comments below.
# o There was a duplicate ImageView.DrawImage() method. Que?
#
#----------------------------------------------------------------------------
# 1.0 Release - Lorne White
# Date: January 29, 2002
# 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 os
import sys
import wx
dir_path = os.getcwd()
#---------------------------------------------------------------------------
BAD_IMAGE = -1
ID_WHITE_BG = wx.NewId()
ID_BLACK_BG = wx.NewId()
ID_GREY_BG = wx.NewId()
ID_CHECK_BG = wx.NewId()
ID_NO_FRAME = wx.NewId()
ID_BOX_FRAME = wx.NewId()
ID_CROP_FRAME = wx.NewId()
def ConvertBMP(file_nm):
if file_nm is None:
return None
@ -42,92 +66,326 @@ def ConvertBMP(file_nm):
ext = fl_fld[1]
ext = ext[1:].lower()
image = wx.Image(file_nm, wx.BITMAP_TYPE_ANY)
return image
# Don't try to create it directly because wx throws up
# an annoying messasge dialog if the type isn't supported.
if wx.Image.CanRead(file_nm):
image = wx.Image(file_nm, wx.BITMAP_TYPE_ANY)
return image
# BAD_IMAGE means a bad image, None just means no image (i.e. directory)
return BAD_IMAGE
def GetSize(file_nm): # for scaling image values
image = ConvertBMP(file_nm)
bmp = image.ConvertToBitmap()
size = bmp.GetWidth(), bmp.GetHeight()
return size
def GetCheckeredBitmap(blocksize=8,ntiles=4,rgb0='\xFF', rgb1='\xCC'):
"""Creates a square RGB checkered bitmap using the two specified colors.
Inputs:
- blocksize: the number of pixels in each solid color square
- ntiles: the number of tiles along width and height. Each tile is 2x2 blocks.
- rbg0,rgb1: the first and second colors, as 3-byte strings.
If only 1 byte is provided, it is treated as a grey value.
The bitmap returned will have width = height = blocksize*ntiles*2
"""
size = blocksize*ntiles*2
if len(rgb0)==1:
rgb0 = rgb0 * 3
if len(rgb1)==1:
rgb1 = rgb1 * 3
strip0 = (rgb0*blocksize + rgb1*blocksize)*(ntiles*blocksize)
strip1 = (rgb1*blocksize + rgb0*blocksize)*(ntiles*blocksize)
band = strip0 + strip1
data = band * ntiles
return wx.BitmapFromBuffer(size, size, data)
def GetNamedBitmap(name):
return IMG_CATALOG[name].getBitmap()
class ImageView(wx.Window):
def __init__(self, parent, id=-1, pos=wx.DefaultPosition, size=wx.DefaultSize):
wx.Window.__init__(self, parent, id, pos, size)
self.win = parent
def __init__(self, parent, id=-1, pos=wx.DefaultPosition, size=wx.DefaultSize,
style=wx.BORDER_SUNKEN
):
wx.Window.__init__(self, parent, id, pos, size, style=style)
self.image = None
self.back_color = 'WHITE'
self.border_color = 'BLACK'
self.check_bmp = None
self.check_dim_bmp = None
# dark_bg is the brush/bitmap to use for painting in the whole background
# lite_bg is the brush/bitmap/pen to use for painting the image rectangle
self.dark_bg = None
self.lite_bg = None
self.border_mode = ID_CROP_FRAME
self.SetBackgroundMode( ID_WHITE_BG )
self.SetBorderMode( ID_NO_FRAME )
# Changed API of wx uses tuples for size and pos now.
self.image_sizex = size[0]
self.image_sizey = size[1]
self.image_posx = pos[0]
self.image_posy = pos[1]
self.Bind(wx.EVT_PAINT, self.OnPaint)
def OnPaint(self, event):
dc = wx.PaintDC(self)
self.DrawImage(dc)
self.Bind(wx.EVT_ERASE_BACKGROUND, self.OnEraseBackground)
self.Bind(wx.EVT_SIZE, self.OnSize)
def SetValue(self, file_nm): # display the selected file in the panel
image = ConvertBMP(file_nm)
self.image = image
self.Refresh()
def SetBackgroundMode(self, mode):
self.bg_mode = mode
self._updateBGInfo()
def DrawBorder(self, dc):
brush = wx.Brush(wx.NamedColour(self.back_color), wx.SOLID)
dc.SetBrush(brush)
dc.SetPen(wx.Pen(wx.NamedColour(self.border_color), 1))
dc.DrawRectangle(0, 0, self.image_sizex, self.image_sizey)
def _updateBGInfo(self):
bg = self.bg_mode
border = self.border_mode
self.dark_bg = None
self.lite_bg = None
if border == ID_BOX_FRAME:
self.lite_bg = wx.BLACK_PEN
if bg == ID_WHITE_BG:
if border == ID_CROP_FRAME:
self.SetBackgroundColour('LIGHT GREY')
self.lite_bg = wx.WHITE_BRUSH
else:
self.SetBackgroundColour('WHITE')
elif bg == ID_GREY_BG:
if border == ID_CROP_FRAME:
self.SetBackgroundColour('GREY')
self.lite_bg = wx.LIGHT_GREY_BRUSH
else:
self.SetBackgroundColour('LIGHT GREY')
elif bg == ID_BLACK_BG:
if border == ID_BOX_FRAME:
self.lite_bg = wx.WHITE_PEN
if border == ID_CROP_FRAME:
self.SetBackgroundColour('GREY')
self.lite_bg = wx.BLACK_BRUSH
else:
self.SetBackgroundColour('BLACK')
else:
if self.check_bmp is None:
self.check_bmp = GetCheckeredBitmap()
self.check_dim_bmp = GetCheckeredBitmap(rgb0='\x7F', rgb1='\x66')
if border == ID_CROP_FRAME:
self.dark_bg = self.check_dim_bmp
self.lite_bg = self.check_bmp
else:
self.dark_bg = self.check_bmp
self.Refresh()
def SetBorderMode(self, mode):
self.border_mode = mode
self._updateBGInfo()
def OnSize(self, event):
event.Skip()
self.Refresh()
def OnPaint(self, event):
dc = wx.PaintDC(self)
self.DrawImage(dc)
def OnEraseBackground(self, evt):
if self.bg_mode != ID_CHECK_BG:
evt.Skip()
return
dc = evt.GetDC()
if not dc:
dc = wx.ClientDC(self)
rect = self.GetUpdateRegion().GetBox()
dc.SetClippingRect(rect)
self.PaintBackground(dc, self.dark_bg)
def PaintBackground(self, dc, painter, rect=None):
if painter is None:
return
if rect is None:
pos = self.GetPosition()
sz = self.GetSize()
else:
pos = rect.Position
sz = rect.Size
if type(painter)==wx.Brush:
dc.SetPen(wx.TRANSPARENT_PEN)
dc.SetBrush(painter)
dc.DrawRectangle(pos.x,pos.y,sz.width,sz.height)
elif type(painter)==wx.Pen:
dc.SetPen(painter)
dc.SetBrush(wx.TRANSPARENT_BRUSH)
dc.DrawRectangle(pos.x-1,pos.y-1,sz.width+2,sz.height+2)
else:
self.TileBackground(dc, painter, pos.x,pos.y,sz.width,sz.height)
def TileBackground(self, dc, bmp, x,y,w,h):
"""Tile bmp into the specified rectangle"""
bw = bmp.GetWidth()
bh = bmp.GetHeight()
dc.SetClippingRegion(x,y,w,h)
# adjust so 0,0 so we always match with a tiling starting at 0,0
dx = x % bw
x = x - dx
w = w + dx
dy = y % bh
y = y - dy
h = h + dy
tx = x
x2 = x+w
y2 = y+h
while tx < x2:
ty = y
while ty < y2:
dc.DrawBitmap(bmp, tx, ty)
ty += bh
tx += bw
def DrawImage(self, dc):
try:
image = self.image
except:
if not hasattr(self,'image') or self.image is None:
return
self.DrawBorder(dc)
wwidth,wheight = self.GetSize()
image = self.image
bmp = None
if image != BAD_IMAGE and image.IsOk():
iwidth = image.GetWidth() # dimensions of image file
iheight = image.GetHeight()
else:
bmp = wx.ArtProvider.GetBitmap(wx.ART_MISSING_IMAGE, wx.ART_MESSAGE_BOX, (64,64))
iwidth = bmp.GetWidth()
iheight = bmp.GetHeight()
if image is None:
return
# squeeze iwidth x iheight image into window, preserving aspect ratio
try:
bmp = image.ConvertToBitmap()
except:
return
xfactor = float(wwidth) / iwidth
yfactor = float(wheight) / iheight
iwidth = bmp.GetWidth() # dimensions of image file
iheight = bmp.GetHeight()
if xfactor < 1.0 and xfactor < yfactor:
scale = xfactor
elif yfactor < 1.0 and yfactor < xfactor:
scale = yfactor
else:
scale = 1.0
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
owidth = int(scale*iwidth)
oheight = int(scale*iheight)
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
diffx = (wwidth - owidth)/2 # center calc
diffy = (wheight - oheight)/2 # center calc
if not bmp:
if owidth!=iwidth or oheight!=iheight:
sc_image = sc_image = image.Scale(owidth,oheight)
else:
sc_image = image
bmp = sc_image.ConvertToBitmap()
if image != BAD_IMAGE and image.IsOk():
self.PaintBackground(dc, self.lite_bg, wx.Rect(diffx,diffy,owidth,oheight))
dc.DrawBitmap(bmp, diffx, diffy, useMask=True) # draw the image to window
class ImagePanel(wx.Panel):
def __init__(self, parent, id=-1, pos=wx.DefaultPosition, size=wx.DefaultSize,
style=wx.NO_BORDER
):
wx.Panel.__init__(self, parent, id, pos, size, style=style)
vbox = wx.BoxSizer(wx.VERTICAL)
self.SetSizer(vbox)
self.view = ImageView(self)
vbox.Add(self.view, 1, wx.GROW|wx.ALL, 0)
hbox_ctrls = wx.BoxSizer(wx.HORIZONTAL)
vbox.Add(hbox_ctrls, 0, wx.ALIGN_RIGHT|wx.TOP, 4)
bmp = GetNamedBitmap('White')
btn = wx.BitmapButton(self, ID_WHITE_BG, bmp, style=wx.BU_EXACTFIT)
self.Bind(wx.EVT_BUTTON, self.OnSetImgBackground, btn)
btn.SetToolTipString("Set background to white")
hbox_ctrls.Add(btn, 0, wx.ALIGN_LEFT|wx.LEFT, 4)
bmp = GetNamedBitmap('Grey')
btn = wx.BitmapButton(self, ID_GREY_BG, bmp, style=wx.BU_EXACTFIT)
self.Bind(wx.EVT_BUTTON, self.OnSetImgBackground, btn)
btn.SetToolTipString("Set background to grey")
hbox_ctrls.Add(btn, 0, wx.ALIGN_LEFT|wx.LEFT, 4)
bmp = GetNamedBitmap('Black')
btn = wx.BitmapButton(self, ID_BLACK_BG, bmp, style=wx.BU_EXACTFIT)
self.Bind(wx.EVT_BUTTON, self.OnSetImgBackground, btn)
btn.SetToolTipString("Set background to black")
hbox_ctrls.Add(btn, 0, wx.ALIGN_LEFT|wx.LEFT, 4)
bmp = GetNamedBitmap('Checked')
btn = wx.BitmapButton(self, ID_CHECK_BG, bmp, style=wx.BU_EXACTFIT)
self.Bind(wx.EVT_BUTTON, self.OnSetImgBackground, btn)
btn.SetToolTipString("Set background to chekered pattern")
hbox_ctrls.Add(btn, 0, wx.ALIGN_LEFT|wx.LEFT, 4)
hbox_ctrls.AddSpacer(7)
bmp = GetNamedBitmap('NoFrame')
btn = wx.BitmapButton(self, ID_NO_FRAME, bmp, style=wx.BU_EXACTFIT)
self.Bind(wx.EVT_BUTTON, self.OnSetBorderMode, btn)
btn.SetToolTipString("No framing around image")
hbox_ctrls.Add(btn, 0, wx.ALIGN_LEFT|wx.LEFT, 4)
bmp = GetNamedBitmap('BoxFrame')
btn = wx.BitmapButton(self, ID_BOX_FRAME, bmp, style=wx.BU_EXACTFIT)
self.Bind(wx.EVT_BUTTON, self.OnSetBorderMode, btn)
btn.SetToolTipString("Frame image with a box")
hbox_ctrls.Add(btn, 0, wx.ALIGN_LEFT|wx.LEFT, 4)
bmp = GetNamedBitmap('CropFrame')
btn = wx.BitmapButton(self, ID_CROP_FRAME, bmp, style=wx.BU_EXACTFIT|wx.BORDER_SIMPLE)
self.Bind(wx.EVT_BUTTON, self.OnSetBorderMode, btn)
btn.SetToolTipString("Frame image with a dimmed background")
hbox_ctrls.Add(btn, 0, wx.ALIGN_LEFT|wx.LEFT, 4)
def SetValue(self, file_nm): # display the selected file in the panel
self.view.SetValue(file_nm)
def SetBackgroundMode(self, mode):
self.view.SetBackgroundMode(mode)
def SetBorderMode(self, mode):
self.view.SetBorderMode(mode)
def OnSetImgBackground(self, event):
mode = event.GetId()
self.SetBackgroundMode(mode)
def OnSetBorderMode(self, event):
mode = event.GetId()
self.SetBorderMode(mode)
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(wx.Dialog):
def __init__(self, parent, set_dir = None):
wx.Dialog.__init__(self, parent, -1, "Image Browser", wx.DefaultPosition, (400, 400))
self.x_pos = 30 # initial display positions
self.y_pos = 20
self.delta = 20
size = wx.Size(80, -1)
wx.Dialog.__init__(self, parent, -1, "Image Browser", wx.DefaultPosition, (400, 400),style=wx.DEFAULT_DIALOG_STYLE|wx.RESIZE_BORDER)
self.set_dir = os.getcwd()
self.set_file = None
@ -136,77 +394,110 @@ class ImageDialog(wx.Dialog):
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.dir = wx.StaticText(self, -1, self.set_dir, (self.dir_x, self.dir_y), (250, -1))
vbox_top = wx.BoxSizer(wx.VERTICAL)
self.SetSizer(vbox_top)
self.y_pos = self.y_pos + self.delta
hbox_loc = wx.BoxSizer(wx.HORIZONTAL)
vbox_top.Add(hbox_loc, 0, wx.GROW|wx.ALIGN_LEFT|wx.ALL, 0)
btn = wx.Button(self, 12331, ' Set Directory ', (self.x_pos, self.y_pos))
self.Bind(wx.EVT_BUTTON, self.SetDirect, btn)
loc_label = wx.StaticText( self, -1, "Folder:")
hbox_loc.Add(loc_label, 0, wx.ALIGN_LEFT|wx.ALIGN_CENTER_VERTICAL|wx.ALL|wx.ADJUST_MINSIZE, 5)
self.type_posy = self.y_pos # save the y position for the image type combo
self.dir = wx.TextCtrl( self, -1, self.set_dir, style=wx.TE_RICH|wx.TE_PROCESS_ENTER)
self.Bind(wx.EVT_TEXT_ENTER, self.OnDirectoryTextSet, self.dir)
hbox_loc.Add(self.dir, 1, wx.GROW|wx.ALIGN_LEFT|wx.ALL, 5)
up_bmp = wx.ArtProvider.GetBitmap(wx.ART_GO_DIR_UP, wx.ART_BUTTON, (16,16))
btn = wx.BitmapButton(self, -1, up_bmp)
btn.SetHelpText("Up one level")
btn.SetToolTipString("Up one level")
self.Bind(wx.EVT_BUTTON, self.OnUpDirectory, btn)
hbox_loc.Add(btn, 0, wx.ALIGN_CENTER_VERTICAL|wx.RIGHT, 2)
folder_bmp = wx.ArtProvider.GetBitmap(wx.ART_FOLDER_OPEN, wx.ART_BUTTON, (16,16))
btn = wx.BitmapButton(self, -1, folder_bmp)
btn.SetHelpText("Browse for a &folder...")
btn.SetToolTipString("Browse for a folder...")
self.Bind(wx.EVT_BUTTON, self.OnChooseDirectory, btn)
hbox_loc.Add(btn, 0, wx.ALIGN_CENTER_VERTICAL|wx.RIGHT, 5)
hbox_nav = wx.BoxSizer(wx.HORIZONTAL)
vbox_top.Add(hbox_nav, 0, wx.ALIGN_LEFT|wx.ALL, 0)
label = wx.StaticText( self, -1, "Files of type:")
hbox_nav.Add(label, 0, wx.ALIGN_CENTER_VERTICAL|wx.LEFT, 5)
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
self.fl_ext_types = (
# display, filter
("All supported formats", "All"),
("BMP (*.bmp)", "*.bmp"),
("GIF (*.gif)", "*.gif"),
("PNG (*.png)", "*.png"),
("JPEG (*.jpg)", "*.jpg"),
("ICO (*.ico)", "*.ico"),
("PNM (*.pnm)", "*.pnm"),
("PCX (*.pcx)", "*.pcx"),
("TIFF (*.tif)", "*.tif"),
("All Files", "*.*"),
)
self.set_type,self.fl_ext = self.fl_ext_types[0] # initial file filter setting
self.fl_types = [ x[0] for x in self.fl_ext_types ]
self.sel_type = wx.ComboBox( self, -1, self.set_type,
wx.DefaultPosition, wx.DefaultSize, self.fl_types,
wx.CB_DROPDOWN )
# after this we don't care about the order any more
self.fl_ext_types = dict(self.fl_ext_types)
# List of Labels
self.tb = tb = wx.ListBox(self, -1, (self.x_pos, self.y_pos),
(160, self.list_height), self.fl_list,
wx.LB_SINGLE )
self.Bind(wx.EVT_COMBOBOX, self.OnSetType, self.sel_type)
hbox_nav.Add(self.sel_type, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5)
splitter = wx.SplitterWindow( self, -1, wx.DefaultPosition, wx.Size(100, 100), 0 )
splitter.SetMinimumPaneSize(100)
split_left = wx.Panel( splitter, -1, wx.DefaultPosition, wx.DefaultSize,
wx.NO_BORDER|wx.TAB_TRAVERSAL )
vbox_left = wx.BoxSizer(wx.VERTICAL)
split_left.SetSizer(vbox_left)
self.tb = tb = wx.ListBox( split_left, -1, wx.DefaultPosition, wx.DefaultSize,
self.fl_list, wx.LB_SINGLE )
self.Bind(wx.EVT_LISTBOX, self.OnListClick, tb)
self.Bind(wx.EVT_LISTBOX_DCLICK, self.OnListDClick, tb)
vbox_left.Add(self.tb, 1, wx.GROW|wx.ALL, 0)
width, height = self.tb.GetSize()
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"
]
split_right = wx.Panel( splitter, -1, wx.DefaultPosition, wx.DefaultSize,
wx.NO_BORDER|wx.TAB_TRAVERSAL )
vbox_right = wx.BoxSizer(wx.VERTICAL)
split_right.SetSizer(vbox_right)
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.image_view = ImagePanel( split_right )
vbox_right.Add(self.image_view, 1, wx.GROW|wx.ALL, 0)
self.set_type = self.fl_types[0] # initial file filter setting
self.fl_ext = self.fl_ext_types[self.set_type]
splitter.SplitVertically(split_left, split_right, 150)
vbox_top.Add(splitter, 1, wx.GROW|wx.ALL, 5)
self.sel_type = wx.ComboBox(self, -1, self.set_type, (image_posx , self.type_posy),
(150, -1), self.fl_types, wx.CB_DROPDOWN)
self.Bind(wx.EVT_COMBOBOX, self.OnSetType, self.sel_type)
hbox_btns = wx.BoxSizer(wx.HORIZONTAL)
vbox_top.Add(hbox_btns, 0, wx.ALIGN_RIGHT|wx.ALL, 5)
self.image_view = ImageView( self, pos=(image_posx, image_posy),
size=(image_sizex, image_sizey))
ok_btn = wx.Button( self, wx.ID_OPEN, "", wx.DefaultPosition, wx.DefaultSize, 0 )
self.Bind(wx.EVT_BUTTON, self.OnOk, ok_btn)
#ok_btn.SetDefault()
hbox_btns.Add(ok_btn, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5)
self.y_pos = self.y_pos + height + 20
btn = wx.Button(self, -1, ' Select ', (100, self.y_pos), size)
self.Bind(wx.EVT_BUTTON, self.OnOk, btn)
wx.Button(self, wx.ID_CANCEL, 'Cancel', (250, self.y_pos), size)
self.y_pos = self.y_pos + self.delta
fsize = (400, self.y_pos + 50) # resize dialog for final vertical position
self.SetSize(fsize)
cancel_btn = wx.Button( self, wx.ID_CANCEL, "",
wx.DefaultPosition, wx.DefaultSize, 0 )
hbox_btns.Add(cancel_btn, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5)
self.ResetFiles()
def GetFiles(self): # get the file list using directory and extension values
if self.fl_ext == "All":
all_files = []
@ -222,11 +513,17 @@ class ImageDialog(wx.Dialog):
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
# prepend the directories
self.fl_ndirs = len(self.fl_val.dirs)
self.fl_list = sorted(self.fl_val.dirs) + self.fl_list
def DisplayDir(self): # display the working directory
if self.dir:
self.dir.SetLabel(self.set_dir)
ipt = self.dir.GetInsertionPoint()
self.dir.SetValue(self.set_dir)
self.dir.SetInsertionPoint(ipt)
def OnSetType(self, event):
val = event.GetString() # get file type value
@ -234,7 +531,7 @@ class ImageDialog(wx.Dialog):
self.ResetFiles()
def OnListDClick(self, event):
self.OnOk(0)
self.OnOk('dclick')
def OnListClick(self, event):
val = event.GetSelection()
@ -243,9 +540,40 @@ class ImageDialog(wx.Dialog):
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)
if val>=self.fl_ndirs:
self.image_view.SetValue(file_val)
else:
self.image_view.SetValue(None)
def SetDirect(self, event): # set the new directory
def OnDirectoryTextSet(self,event):
event.Skip()
path = event.GetString()
if os.path.isdir(path):
self.set_dir = path
self.ResetFiles()
return
if os.path.isfile(path):
dname,fname = os.path.split(path)
if os.path.isdir(dname):
self.ResetFiles()
# try to select fname in list
try:
idx = self.fl_list.index(fname)
self.tb.SetSelection(idx)
self.SetListValue(idx)
return
except ValueError:
pass
wx.Bell()
def OnUpDirectory(self, event):
sdir = os.path.split(self.set_dir)[0]
self.set_dir = sdir
self.ResetFiles()
def OnChooseDirectory(self, event): # set the new directory
dlg = wx.DirDialog(self)
dlg.SetPath(self.set_dir)
@ -278,6 +606,12 @@ class ImageDialog(wx.Dialog):
if len(self.fl_list):
self.tb.Set(self.fl_list)
for idir in xrange(self.fl_ndirs):
d = self.fl_list[idir]
# mark directories as 'True' with client data
self.tb.SetClientData(idir, True)
self.tb.SetString(idir,'['+d+']')
try:
self.tb.SetSelection(0)
self.SetListValue(0)
@ -297,24 +631,24 @@ class ImageDialog(wx.Dialog):
self.EndModal(wx.ID_CANCEL)
def OnOk(self, event):
self.result = self.set_file
self.EndModal(wx.ID_OK)
if os.path.isdir(self.set_file):
sdir = os.path.split(self.set_file)
#os.path.normapth?
if sdir and sdir[-1]=='..':
sdir = os.path.split(sdir[0])[0]
sdir = os.path.split(sdir)
self.set_dir = os.path.join(*sdir)
self.set_file = None
self.ResetFiles()
elif event != 'dclick':
self.result = self.set_file
self.EndModal(wx.ID_OK)
def OnFileDlg(self):
dlg = wx.FileDialog(self, "Choose an Image File", ".", "",
"Bmp (*.bmp)|*.bmp|JPEG (*.jpg)|*.jpg", wx.OPEN)
if dlg.ShowModal() == wx.ID_OK:
path = dlg.GetPath()
else:
path = None
dlg.Destroy()
return path
class FindFiles:
def __init__(self, parent, dir, mask):
def __init__(self, parent, dir, mask, with_dirs=True):
filelist = []
dirlist = [".."]
self.dir = dir
@ -327,13 +661,21 @@ class FindFiles:
continue
path = os.path.join(dir, i)
if os.path.isdir(path):
dirlist.append(i)
continue
path = path.upper()
value = i.upper()
if pattern.match(value) != None:
filelist.append(i)
self.files = filelist
if with_dirs:
self.dirs = dirlist
def MakeRegex(self, pattern):
import re
@ -356,3 +698,166 @@ class FindFiles:
fl_name = fl_fld[0]
ext = fl_fld[1]
return ext[1:]
#----------------------------------------------------------------------
# This part of the file was generated by C:\Python25\Scripts\img2py
# then edited slightly.
import cStringIO, zlib
IMG_CATALOG = {}
class ImageClass: pass
def getWhiteData():
return zlib.decompress(
'x\xda\xeb\x0c\xf0s\xe7\xe5\x92\xe2b``\xe0\xf5\xf4p\t\x02\xd2< \xcc\xc1\x04$\
o\x8a\x9f\xde\x00\xa4\x98\x8b\x9d<C888n?\xf4\x7f\x00\xe4*z\xba8\x86HLMNP`202\
0\xf8\xf3\xff\xbf\xfc|.77\xb5$\x1f\xa9P\x979J\x8b\x18\x18N\\d\x16\t\xfd\xfc\
\xce\x07\xa8\x98\xc1\xd3\xd5\xcfe\x9dSB\x13\x00\xcc1\x1b\xb3' )
def getWhiteBitmap():
return wx.BitmapFromImage(getWhiteImage())
def getWhiteImage():
stream = cStringIO.StringIO(getWhiteData())
return wx.ImageFromStream(stream)
IMG_CATALOG['White'] = ImageClass()
IMG_CATALOG['White'].getData = getWhiteData
IMG_CATALOG['White'].getImage = getWhiteImage
IMG_CATALOG['White'].getBitmap = getWhiteBitmap
#----------------------------------------------------------------------
def getGreyData():
return zlib.decompress(
'x\xda\xeb\x0c\xf0s\xe7\xe5\x92\xe2b``\xe0\xf5\xf4p\t\x02\xd2< \xcc\xc1\x04$\
o\x8a\x9f\xde\x00\xa4\x98\x8b\x9d<C888n?\xf4\x7f\x00\xe4*y\xba8\x86HLMNP`202\
0\x98cY\xcc\xd6\xcf%,,\xac\x96\xe4#\x15\xea2Gi\x11\x03\xc3\xb6\xc7\xcc":A7%\
\x80\xaa\x19<]\xfd\\\xd69%4\x01\x00{m\x18s' )
def getGreyBitmap():
return wx.BitmapFromImage(getGreyImage())
def getGreyImage():
stream = cStringIO.StringIO(getGreyData())
return wx.ImageFromStream(stream)
IMG_CATALOG['Grey'] = ImageClass()
IMG_CATALOG['Grey'].getData = getGreyData
IMG_CATALOG['Grey'].getImage = getGreyImage
IMG_CATALOG['Grey'].getBitmap = getGreyBitmap
#----------------------------------------------------------------------
def getBlackData():
return zlib.decompress(
'x\xda\xeb\x0c\xf0s\xe7\xe5\x92\xe2b``\xe0\xf5\xf4p\t\x02\xd2< \xcc\xc1\x04$\
o\x8a\x9f\xde\x00\xa4\x98\x8b\x9d<C888n?\xf4\x7f\x00\xe4\xf2y\xba8\x86HLMN\
\x90`u\x16e``\xdc\xc3\xc0h\\3\xdb\x0c(\xc3\xe0\xe9\xea\xe7\xb2\xce)\xa1\t\
\x00\xb6`\x12\x08' )
def getBlackBitmap():
return wx.BitmapFromImage(getBlackImage())
def getBlackImage():
stream = cStringIO.StringIO(getBlackData())
return wx.ImageFromStream(stream)
IMG_CATALOG['Black'] = ImageClass()
IMG_CATALOG['Black'].getData = getBlackData
IMG_CATALOG['Black'].getImage = getBlackImage
IMG_CATALOG['Black'].getBitmap = getBlackBitmap
#----------------------------------------------------------------------
def getCheckedData():
return zlib.decompress(
'x\xda\xeb\x0c\xf0s\xe7\xe5\x92\xe2b``\xe0\xf5\xf4p\t\x02\xd2< \xcc\xc1\x04$\
o\x8a\x9f\xde\x00\xa4\x98\x8b\x9d<C888n?\xf4\x7f\x00\xe4\x1az\xba8\x86HLMNP`\
2020\x98cY\xcc\x16y\xe2\xc6\r\tWVeeaC\xb5\x8b\x91\x82\xdc\xccm\xde\xe7\xe7\
\xd9Zo\xc8S\xf2\x12\x0cd`\xd0\xd8\xc5&\xf6\xeb\xd5\xe5t\xa0f\x06OW?\x97uN\tM\
\x00qL\x1f\x94' )
def getCheckedBitmap():
return wx.BitmapFromImage(getCheckedImage())
def getCheckedImage():
stream = cStringIO.StringIO(getCheckedData())
return wx.ImageFromStream(stream)
IMG_CATALOG['Checked'] = ImageClass()
IMG_CATALOG['Checked'].getData = getCheckedData
IMG_CATALOG['Checked'].getImage = getCheckedImage
IMG_CATALOG['Checked'].getBitmap = getCheckedBitmap
#----------------------------------------------------------------------
def getNoFrameData():
return zlib.decompress(
"x\xda\xeb\x0c\xf0s\xe7\xe5\x92\xe2b``\xe0\xf5\xf4p\t\x02\xd2< \xcc\xc1\x04$\
o\x8a\x9f\xde\x00\xa4\x98\x8b\x9d<C888n?\xf4\x7f\x00\xe4\x9ay\xba8\x86HL]\
\xdb\xef\xc8\xc5\xa0 \xc04\xf7\xc5\xff\xf8m\xd1\x01.\xba\x93\x9e'\x86\xac\
\x14P\xb9\xb9O\xf0\x82\xd62\x0e\xa6\x06\xf9e\x8f;Yg\xc5F'\xd7g]\xf2\xadd;=\
\x87S\xfe\xf3\xc7\x15\x8f\x80&0x\xba\xfa\xb9\xacsJh\x02\x00\x07\xac't" )
def getNoFrameBitmap():
return wx.BitmapFromImage(getNoFrameImage())
def getNoFrameImage():
stream = cStringIO.StringIO(getNoFrameData())
return wx.ImageFromStream(stream)
IMG_CATALOG['NoFrame'] = ImageClass()
IMG_CATALOG['NoFrame'].getData = getNoFrameData
IMG_CATALOG['NoFrame'].getImage = getNoFrameImage
IMG_CATALOG['NoFrame'].getBitmap = getNoFrameBitmap
#----------------------------------------------------------------------
def getBoxFrameData():
return zlib.decompress(
"x\xda\xeb\x0c\xf0s\xe7\xe5\x92\xe2b``\xe0\xf5\xf4p\t\x02\xd2< \xcc\xc1\x04$\
o\x8a\x9f\xde\x00\xa4\x98\x8b\x9d<C888n?\xf4\x7f\x00\xe4:{\xba8\x86HL\x9d\
\xdbw\x91\x8bA\x81\x83\xb9\xfc\xd2\xff\xff\x9bl9\x02\x15\xd5\xdefnJ\xf6\xcb\
\xe2\xf0|\x17'\x980W\xed\xaa\xaf\xe0\xcd:\xfd\xaa\xef\xec!/\xda.]ggaH\xfcT\
\xbaRI\xca_\xef\xe6\x97\xf5\x9c;\xa2\x15\xfe\xbe^S\xbe\th\x1c\x83\xa7\xab\
\x9f\xcb:\xa7\x84&\x00k\xdd.\x08" )
def getBoxFrameBitmap():
return wx.BitmapFromImage(getBoxFrameImage())
def getBoxFrameImage():
stream = cStringIO.StringIO(getBoxFrameData())
return wx.ImageFromStream(stream)
IMG_CATALOG['BoxFrame'] = ImageClass()
IMG_CATALOG['BoxFrame'].getData = getBoxFrameData
IMG_CATALOG['BoxFrame'].getImage = getBoxFrameImage
IMG_CATALOG['BoxFrame'].getBitmap = getBoxFrameBitmap
#----------------------------------------------------------------------
def getCropFrameData():
return zlib.decompress(
"x\xda\xeb\x0c\xf0s\xe7\xe5\x92\xe2b``\xe0\xf5\xf4p\t\x02\xd2< \xcc\xc1\x04$\
o\x8a\x9f\xde\x00\xa4\x98\x8b\x9d<C888n?\xf4\x7f\x00\xe4zz\xba8\x86HL\xdd;\
\xc1\x90\xeb\x80\x03\x07K\xba\xf3\xbf\xd5\xfe\x17\xc5g;\xedh\x16i\xcf\xdc\
\xd4z\xc2\xa8G\x81GIA\x89\xafew\xbc\xf0e\x8e]\xd7\xd3\xd2\x1aT\x16\xacj8\xf3\
'\xa1\xca\xf9\xad\x85\xe3\xa4_1\xe7\xef~~\xcd\xedV\xc9\xf0\x7f#\xbftm\xb5\
\x8d\t\x03\xc8TW?\x97uN\tM\x00\x9c@0\x82" )
def getCropFrameBitmap():
return wx.BitmapFromImage(getCropFrameImage())
def getCropFrameImage():
stream = cStringIO.StringIO(getCropFrameData())
return wx.ImageFromStream(stream)
IMG_CATALOG['CropFrame'] = ImageClass()
IMG_CATALOG['CropFrame'].getData = getCropFrameData
IMG_CATALOG['CropFrame'].getImage = getCropFrameImage
IMG_CATALOG['CropFrame'].getBitmap = getCropFrameBitmap

View File

@ -511,6 +511,8 @@ class InspectionInfoPanel(wx.stc.StyledTextCtrl):
st.append(self.Fmt('name', obj.GetName()))
st.append(self.Fmt('class', obj.__class__))
st.append(self.Fmt('bases', obj.__class__.__bases__))
if hasattr(obj, 'this'):
st.append(self.Fmt('this', repr(obj.this)))
st.append(self.Fmt('id', obj.GetId()))
st.append(self.Fmt('style', obj.GetWindowStyle()))
st.append(self.Fmt('pos', obj.GetPosition()))
@ -561,6 +563,8 @@ class InspectionInfoPanel(wx.stc.StyledTextCtrl):
def FmtSizer(self, obj):
st = ['Sizer:']
st.append(self.Fmt('class', obj.__class__))
if hasattr(obj, 'this'):
st.append(self.Fmt('this', repr(obj.this)))
st.append(self.Fmt('pos', obj.GetPosition()))
st.append(self.Fmt('size', obj.GetSize()))
st.append(self.Fmt('minsize', obj.GetMinSize()))

View File

@ -22,19 +22,24 @@ def get_acroversion():
global _acroversion
if _acroversion == None:
import _winreg
acrosoft = [r'SOFTWARE\Adobe\Acrobat Reader\%version%\InstallPath',
r'SOFTWARE\Adobe\Adobe Acrobat\%version%\InstallPath',]
for regkey in acrosoft:
for version in ('7.0', '6.0', '5.0', '4.0'):
adobesoft = _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE, r'Software\Adobe')
acrokeys, acroversions = [], []
for index in range(_winreg.QueryInfoKey(adobesoft)[0]):
key = _winreg.EnumKey(adobesoft, index)
if "acrobat" in key.lower():
acrokeys.append(_winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE, 'Software\\Adobe\\%s' % key))
for acrokey in acrokeys:
for index in range(_winreg.QueryInfoKey(acrokey)[0]):
key = _winreg.EnumKey(acrokey, index)
try:
path = _winreg.QueryValue(_winreg.HKEY_LOCAL_MACHINE,
regkey.replace('%version%', version))
_acroversion = version
break
acroversions.append(float(key))
except:
continue
pass
acroversions.sort(reverse=True)
if acroversions:
_acroversion = acroversions[0]
return _acroversion
#----------------------------------------------------------------------
@ -54,7 +59,7 @@ def get_acroversion():
# Co-ordinates passed as parameters are in points (1/72 inch).
if get_acroversion() >= '7.0':
if get_acroversion() >= 7.0:
from wx.lib.activexwrapper import MakeActiveXClass
import win32com.client.gencache

View File

@ -292,6 +292,22 @@ class Shell(editwindow.EditWindow):
self.Bind(wx.EVT_CHAR, self.OnChar)
self.Bind(wx.EVT_KEY_DOWN, self.OnKeyDown)
# Assign handler for the context menu
self.Bind(wx.EVT_CONTEXT_MENU, self.OnContextMenu)
self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateUI)
# Assign handlers for edit events
self.Bind(wx.EVT_MENU, lambda evt: self.Cut(), id=wx.ID_CUT)
self.Bind(wx.EVT_MENU, lambda evt: self.Copy(), id=wx.ID_COPY)
self.Bind(wx.EVT_MENU, lambda evt: self.CopyWithPrompts(), id=frame.ID_COPY_PLUS)
self.Bind(wx.EVT_MENU, lambda evt: self.Paste(), id=wx.ID_PASTE)
self.Bind(wx.EVT_MENU, lambda evt: self.PasteAndRun(), id=frame.ID_PASTE_PLUS)
self.Bind(wx.EVT_MENU, lambda evt: self.SelectAll(), id=wx.ID_SELECTALL)
self.Bind(wx.EVT_MENU, lambda evt: self.Clear(), id=wx.ID_CLEAR)
self.Bind(wx.EVT_MENU, lambda evt: self.Undo(), id=wx.ID_UNDO)
self.Bind(wx.EVT_MENU, lambda evt: self.Redo(), id=wx.ID_REDO)
# Assign handler for idle time.
self.waiting = False
self.Bind(wx.EVT_IDLE, self.OnIdle)
@ -1367,6 +1383,48 @@ Platform: %s""" % \
config.WriteBool('View/ShowLineNumbers', self.lineNumbers)
config.WriteInt('View/Zoom/Shell', self.GetZoom())
def GetContextMenu(self):
"""
Create and return a context menu for the shell.
This is used instead of the scintilla default menu
in order to correctly respect our immutable buffer.
"""
menu = wx.Menu()
menu.Append(wx.ID_UNDO, "Undo")
menu.Append(wx.ID_REDO, "Redo")
menu.AppendSeparator()
menu.Append(wx.ID_CUT, "Cut")
menu.Append(wx.ID_COPY, "Copy")
menu.Append(frame.ID_COPY_PLUS, "Copy Plus")
menu.Append(wx.ID_PASTE, "Paste")
menu.Append(frame.ID_PASTE_PLUS, "Paste Plus")
menu.Append(wx.ID_CLEAR, "Clear")
menu.AppendSeparator()
menu.Append(wx.ID_SELECTALL, "Select All")
return menu
def OnContextMenu(self, evt):
menu = self.GetContextMenu()
self.PopupMenu(menu)
def OnUpdateUI(self, evt):
id = evt.Id
if id in (wx.ID_CUT, wx.ID_CLEAR):
evt.Enable(self.CanCut())
elif id in (wx.ID_COPY, frame.ID_COPY_PLUS):
evt.Enable(self.CanCopy())
elif id in (wx.ID_PASTE, frame.ID_PASTE_PLUS):
evt.Enable(self.CanPaste())
elif id == wx.ID_UNDO:
evt.Enable(self.CanUndo())
elif id == wx.ID_REDO:
evt.Enable(self.CanRedo())
## NOTE: The DnD of file names is disabled until I can figure out how

View File

@ -304,7 +304,7 @@ class ParamFont(PPanel):
except KeyError: error = True; wx.LogError('Invalid style specification')
try: weight = fontWeightsXml2wx[self.value[3]]
except KeyError: error = True; wx.LogError('Invalid weight specification')
try: underlined = bool(self.value[4])
try: underlined = bool(int(self.value[4]))
except ValueError: error = True; wx.LogError('Invalid underlined flag specification')
face = self.value[5]
except IndexError:

View File

@ -197,7 +197,7 @@ class xxxObject:
# Special parameters
specials = []
# Bitmap tags
bitmapTags = ['bitmap', 'bitmap2', 'icon']
bitmapTags = ['bitmap', 'bitmap2', 'icon', 'selected', 'focus', 'disabled']
# Required paremeters: none by default
required = []
# Default parameters with default values

View File

@ -148,7 +148,8 @@ wxID_HTML_SEARCHCHOICE = wx.html.ID_HTML_SEARCHCHOICE
wxID_HTML_COUNTINFO = wx.html.ID_HTML_COUNTINFO
wxHtmlHelpWindow = wx.html.HtmlHelpWindow
wxPreHtmlHelpWindow = wx.html.PreHtmlHelpWindow
wxHtmlWindowEvent = wx.html.HtmlWindowEvent
wxHtmlCellEvent = wx.html.HtmlCellEvent
wxHtmlLinkEvent = wx.html.HtmlLinkEvent
wxHtmlHelpFrame = wx.html.HtmlHelpFrame
wxPreHtmlHelpFrame = wx.html.PreHtmlHelpFrame
wxHtmlHelpDialog = wx.html.HtmlHelpDialog