From fe45b493dcc42fea4ad4f781a4fb7844d2e95fd0 Mon Sep 17 00:00:00 2001 From: Robin Dunn Date: Sat, 23 Jun 2007 20:50:39 +0000 Subject: [PATCH] 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 --- wxPython/config.py | 25 +- wxPython/demo/Main.py | 10 +- wxPython/demo/RichTextCtrl.py | 80 +- wxPython/demo/StandardPaths.py | 6 +- wxPython/demo/Threads.py | 7 +- wxPython/distrib/build_packages.sh | 4 +- wxPython/distrib/mac/wxPythonOSX/build | 85 +- wxPython/include/wx/wxPython/pyistream.h | 99 +- wxPython/include/wx/wxPython/wxPython.h | 2 + wxPython/include/wx/wxPython/wxPython_int.h | 6 + wxPython/samples/pySketch/pySketch.py | 3308 ++++++++++++------- wxPython/samples/pydocview/TextEditor.py | 11 +- wxPython/samples/roses/clroses.py | 372 +++ wxPython/samples/roses/wxroses.py | 544 +++ wxPython/setup.py | 12 +- wxPython/src/_bitmap.i | 16 +- wxPython/src/_colour.i | 8 +- wxPython/src/_core_api.i | 2 + wxPython/src/_defs.i | 212 ++ wxPython/src/_filesys.i | 22 +- wxPython/src/_functions.i | 2 +- wxPython/src/_gdicmn.i | 6 + wxPython/src/_graphics.i | 3 - wxPython/src/_image.i | 11 + wxPython/src/_log.i | 3 +- wxPython/src/_menu.i | 10 +- wxPython/src/_panel.i | 2 +- wxPython/src/_richtextbuffer.i | 1968 +++++++++++ wxPython/src/_richtextctrl.i | 1237 +++++++ wxPython/src/_richtexthtml.i | 102 + wxPython/src/_richtextxml.i | 67 + wxPython/src/_sizers.i | 22 +- wxPython/src/_stdpaths.i | 16 +- wxPython/src/_streams.i | 97 +- wxPython/src/_window.i | 41 +- wxPython/src/aui.i | 2 +- wxPython/src/combo.i | 2 +- wxPython/src/helpers.cpp | 224 +- wxPython/src/my_typemaps.i | 4 + wxPython/src/richtext.i | 1514 +-------- wxPython/wx/lib/buttonpanel.py | 7 +- wxPython/wx/lib/colourselect.py | 8 +- wxPython/wx/lib/flatnotebook.py | 14 +- wxPython/wx/lib/imagebrowser.py | 779 ++++- wxPython/wx/lib/inspection.py | 4 + wxPython/wx/lib/pdfwin.py | 27 +- wxPython/wx/py/shell.py | 58 + wxPython/wx/tools/XRCed/params.py | 2 +- wxPython/wx/tools/XRCed/xxx.py | 2 +- wxPython/wxPython/html.py | 3 +- 50 files changed, 8030 insertions(+), 3038 deletions(-) create mode 100644 wxPython/samples/roses/clroses.py create mode 100644 wxPython/samples/roses/wxroses.py create mode 100644 wxPython/src/_richtextbuffer.i create mode 100644 wxPython/src/_richtextctrl.i create mode 100644 wxPython/src/_richtexthtml.i create mode 100644 wxPython/src/_richtextxml.i diff --git a/wxPython/config.py b/wxPython/config.py index 2232b65deb..21a8129f71 100644 --- a/wxPython/config.py +++ b/wxPython/config.py @@ -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: diff --git a/wxPython/demo/Main.py b/wxPython/demo/Main.py index 495acedf76..56793f1ced 100644 --- a/wxPython/demo/Main.py +++ b/wxPython/demo/Main.py @@ -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()) diff --git a/wxPython/demo/RichTextCtrl.py b/wxPython/demo/RichTextCtrl.py index 5cf36b7f4d..a913bea699 100644 --- a/wxPython/demo/RichTextCtrl.py +++ b/wxPython/demo/RichTextCtrl.py @@ -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): diff --git a/wxPython/demo/StandardPaths.py b/wxPython/demo/StandardPaths.py index 11491eb126..5f64130c4c 100644 --- a/wxPython/demo/StandardPaths.py +++ b/wxPython/demo/StandardPaths.py @@ -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) diff --git a/wxPython/demo/Threads.py b/wxPython/demo/Threads.py index ceb2fdc78b..96ef2afd42 100644 --- a/wxPython/demo/Threads.py +++ b/wxPython/demo/Threads.py @@ -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() + #--------------------------------------------------------------------------- diff --git a/wxPython/distrib/build_packages.sh b/wxPython/distrib/build_packages.sh index 24f6d226ca..10e9308b78 100755 --- a/wxPython/distrib/build_packages.sh +++ b/wxPython/distrib/build_packages.sh @@ -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 diff --git a/wxPython/distrib/mac/wxPythonOSX/build b/wxPython/distrib/mac/wxPythonOSX/build index 2f3becd3c7..3ea302de45 100755 --- a/wxPython/distrib/mac/wxPythonOSX/build +++ b/wxPython/distrib/mac/wxPythonOSX/build @@ -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 diff --git a/wxPython/include/wx/wxPython/pyistream.h b/wxPython/include/wx/wxPython/pyistream.h index 0ca2da80a4..36a4b162b2 100644 --- a/wxPython/include/wx/wxPython/pyistream.h +++ b/wxPython/include/wx/wxPython/pyistream.h @@ -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(); + void seek(int offset, int whence=0); + int tell(); + 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); - */ + // 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 diff --git a/wxPython/include/wx/wxPython/wxPython.h b/wxPython/include/wx/wxPython/wxPython.h index e6868887b8..12b2b38e03 100644 --- a/wxPython/include/wx/wxPython/wxPython.h +++ b/wxPython/include/wx/wxPython/wxPython.h @@ -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 diff --git a/wxPython/include/wx/wxPython/wxPython_int.h b/wxPython/include/wx/wxPython/wxPython_int.h index 6cc85dd8ce..c67de2f9c2 100644 --- a/wxPython/include/wx/wxPython/wxPython_int.h +++ b/wxPython/include/wx/wxPython/wxPython_int.h @@ -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); }; diff --git a/wxPython/samples/pySketch/pySketch.py b/wxPython/samples/pySketch/pySketch.py index cf580fa500..1e5aac2984 100644 --- a/wxPython/samples/pySketch/pySketch.py +++ b/wxPython/samples/pySketch/pySketch.py @@ -5,7 +5,9 @@ This is completely free software; please feel free to adapt or use this in any way you like. - Author: Erik Westra (ewestra@wave.co.nz) + Original Author: Erik Westra (ewestra@wave.co.nz) + + Other contributors: Bill Baxter (wbaxter@gmail.com) ######################################################################### @@ -41,11 +43,14 @@ * I suspect that the reference counting for some wxPoint objects is getting mucked up; when the user quits, we get errors about being unable to call del on a 'None' object. + + * Saving files via pickling is not a robust cross-platform solution. """ import sys import cPickle, os.path +import copy import wx -from wx.lib.buttons import GenBitmapButton +from wx.lib.buttons import GenBitmapButton,GenBitmapToggleButton import traceback, types @@ -56,80 +61,48 @@ import traceback, types # Our menu item IDs: -menu_UNDO = 10001 # Edit menu items. -menu_SELECT_ALL = 10002 -menu_DUPLICATE = 10003 -menu_EDIT_TEXT = 10004 -menu_DELETE = 10005 +menu_DUPLICATE = wx.NewId() # Edit menu items. +menu_EDIT_PROPS = wx.NewId() -menu_SELECT = 10101 # Tools menu items. -menu_LINE = 10102 -menu_RECT = 10103 -menu_ELLIPSE = 10104 -menu_TEXT = 10105 +menu_SELECT = wx.NewId() # Tools menu items. +menu_LINE = wx.NewId() +menu_POLYGON = wx.NewId() +menu_RECT = wx.NewId() +menu_ELLIPSE = wx.NewId() +menu_TEXT = wx.NewId() -menu_MOVE_FORWARD = 10201 # Object menu items. -menu_MOVE_TO_FRONT = 10202 -menu_MOVE_BACKWARD = 10203 -menu_MOVE_TO_BACK = 10204 +menu_DC = wx.NewId() # View menu items. +menu_GCDC = wx.NewId() -menu_ABOUT = 10205 # Help menu items. +menu_MOVE_FORWARD = wx.NewId() # Object menu items. +menu_MOVE_TO_FRONT = wx.NewId() +menu_MOVE_BACKWARD = wx.NewId() +menu_MOVE_TO_BACK = wx.NewId() + +menu_ABOUT = wx.NewId() # Help menu items. # Our tool IDs: -id_SELECT = 11001 -id_LINE = 11002 -id_RECT = 11003 -id_ELLIPSE = 11004 -id_TEXT = 11005 +id_SELECT = wx.NewId() +id_LINE = wx.NewId() +id_POLYGON = wx.NewId() +id_SCRIBBLE = wx.NewId() +id_RECT = wx.NewId() +id_ELLIPSE = wx.NewId() +id_TEXT = wx.NewId() # Our tool option IDs: -id_FILL_OPT = 12001 -id_PEN_OPT = 12002 -id_LINE_OPT = 12003 - -id_LINESIZE_0 = 13001 -id_LINESIZE_1 = 13002 -id_LINESIZE_2 = 13003 -id_LINESIZE_3 = 13004 -id_LINESIZE_4 = 13005 -id_LINESIZE_5 = 13006 - -# DrawObject type IDs: - -obj_LINE = 1 -obj_RECT = 2 -obj_ELLIPSE = 3 -obj_TEXT = 4 - -# Selection handle IDs: - -handle_NONE = 1 -handle_TOP_LEFT = 2 -handle_TOP_RIGHT = 3 -handle_BOTTOM_LEFT = 4 -handle_BOTTOM_RIGHT = 5 -handle_START_POINT = 6 -handle_END_POINT = 7 +id_FILL_OPT = wx.NewId() +id_PEN_OPT = wx.NewId() +id_LINE_OPT = wx.NewId() -# Dragging operations: - -drag_NONE = 1 -drag_RESIZE = 2 -drag_MOVE = 3 -drag_DRAG = 4 - -# Visual Feedback types: - -feedback_LINE = 1 -feedback_RECT = 2 -feedback_ELLIPSE = 3 - -# Mouse-event action parameter types: - -param_RECT = 1 -param_LINE = 2 +id_LINESIZE_0 = wx.NewId() +id_LINESIZE_1 = wx.NewId() +id_LINESIZE_2 = wx.NewId() +id_LINESIZE_3 = wx.NewId() +id_LINESIZE_4 = wx.NewId() +id_LINESIZE_5 = wx.NewId() # Size of the drawing page, in pixels. @@ -157,47 +130,59 @@ class DrawingFrame(wx.Frame): wx.NO_FULL_REPAINT_ON_RESIZE) # Setup our menu bar. - menuBar = wx.MenuBar() self.fileMenu = wx.Menu() - self.fileMenu.Append(wx.ID_NEW, "New\tCTRL-N") - self.fileMenu.Append(wx.ID_OPEN, "Open...\tCTRL-O") - self.fileMenu.Append(wx.ID_CLOSE, "Close\tCTRL-W") + self.fileMenu.Append(wx.ID_NEW, "New\tCtrl-N", "Create a new document") + self.fileMenu.Append(wx.ID_OPEN, "Open...\tCtrl-O", "Open an existing document") + self.fileMenu.Append(wx.ID_CLOSE, "Close\tCtrl-W") self.fileMenu.AppendSeparator() - self.fileMenu.Append(wx.ID_SAVE, "Save\tCTRL-S") + self.fileMenu.Append(wx.ID_SAVE, "Save\tCtrl-S") self.fileMenu.Append(wx.ID_SAVEAS, "Save As...") self.fileMenu.Append(wx.ID_REVERT, "Revert...") self.fileMenu.AppendSeparator() - self.fileMenu.Append(wx.ID_EXIT, "Quit\tCTRL-Q") + self.fileMenu.Append(wx.ID_EXIT, "Quit\tCtrl-Q") menuBar.Append(self.fileMenu, "File") self.editMenu = wx.Menu() - self.editMenu.Append(menu_UNDO, "Undo\tCTRL-Z") + self.editMenu.Append(wx.ID_UNDO, "Undo\tCtrl-Z") + self.editMenu.Append(wx.ID_REDO, "Redo\tCtrl-Y") self.editMenu.AppendSeparator() - self.editMenu.Append(menu_SELECT_ALL, "Select All\tCTRL-A") + self.editMenu.Append(wx.ID_SELECTALL, "Select All\tCtrl-A") self.editMenu.AppendSeparator() - self.editMenu.Append(menu_DUPLICATE, "Duplicate\tCTRL-D") - self.editMenu.Append(menu_EDIT_TEXT, "Edit...\tCTRL-E") - self.editMenu.Append(menu_DELETE, "Delete\tDEL") + self.editMenu.Append(menu_DUPLICATE, "Duplicate\tCtrl-D") + self.editMenu.Append(menu_EDIT_PROPS,"Edit...\tCtrl-E", "Edit object properties") + self.editMenu.Append(wx.ID_CLEAR, "Delete\tDel") menuBar.Append(self.editMenu, "Edit") + self.viewMenu = wx.Menu() + self.viewMenu.Append(menu_DC, "Normal quality", + "Normal rendering using wx.DC", + kind=wx.ITEM_RADIO) + self.viewMenu.Append(menu_GCDC,"High quality", + "Anti-aliased rendering using wx.GCDC", + kind=wx.ITEM_RADIO) + + menuBar.Append(self.viewMenu, "View") + self.toolsMenu = wx.Menu() - self.toolsMenu.Append(menu_SELECT, "Selection", kind=wx.ITEM_CHECK) - self.toolsMenu.Append(menu_LINE, "Line", kind=wx.ITEM_CHECK) - self.toolsMenu.Append(menu_RECT, "Rectangle", kind=wx.ITEM_CHECK) - self.toolsMenu.Append(menu_ELLIPSE, "Ellipse", kind=wx.ITEM_CHECK) - self.toolsMenu.Append(menu_TEXT, "Text", kind=wx.ITEM_CHECK) + self.toolsMenu.Append(id_SELECT, "Selection", kind=wx.ITEM_RADIO) + self.toolsMenu.Append(id_LINE, "Line", kind=wx.ITEM_RADIO) + self.toolsMenu.Append(id_POLYGON, "Polygon", kind=wx.ITEM_RADIO) + self.toolsMenu.Append(id_SCRIBBLE,"Scribble", kind=wx.ITEM_RADIO) + self.toolsMenu.Append(id_RECT, "Rectangle", kind=wx.ITEM_RADIO) + self.toolsMenu.Append(id_ELLIPSE, "Ellipse", kind=wx.ITEM_RADIO) + self.toolsMenu.Append(id_TEXT, "Text", kind=wx.ITEM_RADIO) menuBar.Append(self.toolsMenu, "Tools") self.objectMenu = wx.Menu() self.objectMenu.Append(menu_MOVE_FORWARD, "Move Forward") - self.objectMenu.Append(menu_MOVE_TO_FRONT, "Move to Front\tCTRL-F") + self.objectMenu.Append(menu_MOVE_TO_FRONT, "Move to Front\tCtrl-F") self.objectMenu.Append(menu_MOVE_BACKWARD, "Move Backward") - self.objectMenu.Append(menu_MOVE_TO_BACK, "Move to Back\tCTRL-B") + self.objectMenu.Append(menu_MOVE_TO_BACK, "Move to Back\tCtrl-B") menuBar.Append(self.objectMenu, "Object") @@ -208,44 +193,47 @@ class DrawingFrame(wx.Frame): self.SetMenuBar(menuBar) + # Create our statusbar + + self.CreateStatusBar() + # Create our toolbar. - tsize = (16,16) - self.toolbar = self.CreateToolBar(wx.TB_HORIZONTAL | - wx.NO_BORDER | wx.TB_FLAT) - - self.toolbar.AddSimpleTool(wx.ID_NEW, - wx.ArtProvider.GetBitmap(wx.ART_NEW, wx.ART_TOOLBAR, tsize), - "New") - self.toolbar.AddSimpleTool(wx.ID_OPEN, - wx.ArtProvider.GetBitmap(wx.ART_FILE_OPEN, wx.ART_TOOLBAR, tsize), - "Open") - self.toolbar.AddSimpleTool(wx.ID_SAVE, - wx.ArtProvider.GetBitmap(wx.ART_FILE_SAVE, wx.ART_TOOLBAR, tsize), - "Save") + tsize = (15,15) + self.toolbar = self.CreateToolBar(wx.TB_HORIZONTAL | wx.NO_BORDER | wx.TB_FLAT) + + artBmp = wx.ArtProvider.GetBitmap + self.toolbar.AddSimpleTool( + wx.ID_NEW, artBmp(wx.ART_NEW, wx.ART_TOOLBAR, tsize), "New") + self.toolbar.AddSimpleTool( + wx.ID_OPEN, artBmp(wx.ART_FILE_OPEN, wx.ART_TOOLBAR, tsize), "Open") + self.toolbar.AddSimpleTool( + wx.ID_SAVE, artBmp(wx.ART_FILE_SAVE, wx.ART_TOOLBAR, tsize), "Save") + self.toolbar.AddSimpleTool( + wx.ID_SAVEAS, artBmp(wx.ART_FILE_SAVE_AS, wx.ART_TOOLBAR, tsize), + "Save As...") + #------- self.toolbar.AddSeparator() - self.toolbar.AddSimpleTool(menu_UNDO, - wx.ArtProvider.GetBitmap(wx.ART_UNDO, wx.ART_TOOLBAR, tsize), - "Undo") + self.toolbar.AddSimpleTool( + wx.ID_UNDO, artBmp(wx.ART_UNDO, wx.ART_TOOLBAR, tsize), "Undo") + self.toolbar.AddSimpleTool( + wx.ID_REDO, artBmp(wx.ART_REDO, wx.ART_TOOLBAR, tsize), "Redo") self.toolbar.AddSeparator() - self.toolbar.AddSimpleTool(menu_DUPLICATE, - wx.Bitmap("images/duplicate.bmp", - wx.BITMAP_TYPE_BMP), - "Duplicate") + self.toolbar.AddSimpleTool( + menu_DUPLICATE, wx.Bitmap("images/duplicate.bmp", wx.BITMAP_TYPE_BMP), + "Duplicate") + #------- self.toolbar.AddSeparator() - self.toolbar.AddSimpleTool(menu_MOVE_FORWARD, - wx.Bitmap("images/moveForward.bmp", - wx.BITMAP_TYPE_BMP), - "Move Forward") - self.toolbar.AddSimpleTool(menu_MOVE_BACKWARD, - wx.Bitmap("images/moveBack.bmp", - wx.BITMAP_TYPE_BMP), - "Move Backward") + self.toolbar.AddSimpleTool( + menu_MOVE_FORWARD, wx.Bitmap("images/moveForward.bmp", wx.BITMAP_TYPE_BMP), + "Move Forward") + self.toolbar.AddSimpleTool( + menu_MOVE_BACKWARD, wx.Bitmap("images/moveBack.bmp", wx.BITMAP_TYPE_BMP), + "Move Backward") self.toolbar.Realize() - # Associate each menu/toolbar item with the method that handles that - # item. + # Associate menu/toolbar items with their handlers. menuHandlers = [ (wx.ID_NEW, self.doNew), (wx.ID_OPEN, self.doOpen), @@ -255,17 +243,23 @@ class DrawingFrame(wx.Frame): (wx.ID_REVERT, self.doRevert), (wx.ID_EXIT, self.doExit), - (menu_UNDO, self.doUndo), - (menu_SELECT_ALL, self.doSelectAll), + (wx.ID_UNDO, self.doUndo), + (wx.ID_REDO, self.doRedo), + (wx.ID_SELECTALL, self.doSelectAll), (menu_DUPLICATE, self.doDuplicate), - (menu_EDIT_TEXT, self.doEditText), - (menu_DELETE, self.doDelete), + (menu_EDIT_PROPS, self.doEditObject), + (wx.ID_CLEAR, self.doDelete), - (menu_SELECT, self.doChooseSelectTool), - (menu_LINE, self.doChooseLineTool), - (menu_RECT, self.doChooseRectTool), - (menu_ELLIPSE, self.doChooseEllipseTool), - (menu_TEXT, self.doChooseTextTool), + (id_SELECT, self.onChooseTool, self.updChooseTool), + (id_LINE, self.onChooseTool, self.updChooseTool), + (id_POLYGON, self.onChooseTool, self.updChooseTool), + (id_SCRIBBLE,self.onChooseTool, self.updChooseTool), + (id_RECT, self.onChooseTool, self.updChooseTool), + (id_ELLIPSE, self.onChooseTool, self.updChooseTool), + (id_TEXT, self.onChooseTool, self.updChooseTool), + + (menu_DC, self.doChooseQuality), + (menu_GCDC, self.doChooseQuality), (menu_MOVE_FORWARD, self.doMoveForward), (menu_MOVE_TO_FRONT, self.doMoveToFront), @@ -274,10 +268,11 @@ class DrawingFrame(wx.Frame): (menu_ABOUT, self.doShowAbout)] for combo in menuHandlers: - id, handler = combo - self.Bind(wx.EVT_MENU, handler, id = id) + id, handler = combo[:2] + self.Bind(wx.EVT_MENU, handler, id = id) + if len(combo)>2: + self.Bind(wx.EVT_UPDATE_UI, combo[2], id = id) - # Install our own method to handle closing the window. This allows us # to ask the user if he/she wants to save before closing the window, as # well as keeping track of which windows are currently open. @@ -298,23 +293,40 @@ class DrawingFrame(wx.Frame): self.toolPalette = wx.BoxSizer(wx.VERTICAL) - self.selectIcon = ToolPaletteIcon(self.topPanel, id_SELECT, - "select", "Selection Tool") - self.lineIcon = ToolPaletteIcon(self.topPanel, id_LINE, - "line", "Line Tool") - self.rectIcon = ToolPaletteIcon(self.topPanel, id_RECT, - "rect", "Rectangle Tool") - self.ellipseIcon = ToolPaletteIcon(self.topPanel, id_ELLIPSE, - "ellipse", "Ellipse Tool") - self.textIcon = ToolPaletteIcon(self.topPanel, id_TEXT, - "text", "Text Tool") + self.selectIcon = ToolPaletteToggle(self.topPanel, id_SELECT, + "select", "Selection Tool", mode=wx.ITEM_RADIO) + self.lineIcon = ToolPaletteToggle(self.topPanel, id_LINE, + "line", "Line Tool", mode=wx.ITEM_RADIO) + self.polygonIcon = ToolPaletteToggle(self.topPanel, id_POLYGON, + "polygon", "Polygon Tool", mode=wx.ITEM_RADIO) + self.scribbleIcon = ToolPaletteToggle(self.topPanel, id_SCRIBBLE, + "scribble", "Scribble Tool", mode=wx.ITEM_RADIO) + self.rectIcon = ToolPaletteToggle(self.topPanel, id_RECT, + "rect", "Rectangle Tool", mode=wx.ITEM_RADIO) + self.ellipseIcon = ToolPaletteToggle(self.topPanel, id_ELLIPSE, + "ellipse", "Ellipse Tool", mode=wx.ITEM_RADIO) + self.textIcon = ToolPaletteToggle(self.topPanel, id_TEXT, + "text", "Text Tool", mode=wx.ITEM_RADIO) + + # Create the tools + self.tools = { + 'select' : (self.selectIcon, SelectDrawingTool()), + 'line' : (self.lineIcon, LineDrawingTool()), + 'polygon' : (self.polygonIcon, PolygonDrawingTool()), + 'scribble': (self.scribbleIcon, ScribbleDrawingTool()), + 'rect' : (self.rectIcon, RectDrawingTool()), + 'ellipse' : (self.ellipseIcon, EllipseDrawingTool()), + 'text' : (self.textIcon, TextDrawingTool()) + } + toolSizer = wx.GridSizer(0, 2, 5, 5) toolSizer.Add(self.selectIcon) - toolSizer.Add((0, 0)) # Gap to make tool icons line up nicely. toolSizer.Add(self.lineIcon) toolSizer.Add(self.rectIcon) toolSizer.Add(self.ellipseIcon) + toolSizer.Add(self.polygonIcon) + toolSizer.Add(self.scribbleIcon) toolSizer.Add(self.textIcon) self.optionIndicator = ToolOptionIndicator(self.topPanel) @@ -323,12 +335,12 @@ class DrawingFrame(wx.Frame): optionSizer = wx.BoxSizer(wx.HORIZONTAL) - self.penOptIcon = ToolPaletteIcon(self.topPanel, id_PEN_OPT, - "penOpt", "Set Pen Colour") - self.fillOptIcon = ToolPaletteIcon(self.topPanel, id_FILL_OPT, - "fillOpt", "Set Fill Colour") - self.lineOptIcon = ToolPaletteIcon(self.topPanel, id_LINE_OPT, - "lineOpt", "Set Line Size") + self.penOptIcon = ToolPaletteButton(self.topPanel, id_PEN_OPT, + "penOpt", "Set Pen Colour",) + self.fillOptIcon = ToolPaletteButton(self.topPanel, id_FILL_OPT, + "fillOpt", "Set Fill Colour") + self.lineOptIcon = ToolPaletteButton(self.topPanel, id_LINE_OPT, + "lineOpt", "Set Line Size") margin = wx.LEFT | wx.RIGHT optionSizer.Add(self.penOptIcon, 0, margin, 1) @@ -343,11 +355,13 @@ class DrawingFrame(wx.Frame): # Make the tool palette icons respond when the user clicks on them. - self.selectIcon.Bind(wx.EVT_BUTTON, self.onToolIconClick) - self.lineIcon.Bind(wx.EVT_BUTTON, self.onToolIconClick) - self.rectIcon.Bind(wx.EVT_BUTTON, self.onToolIconClick) - self.ellipseIcon.Bind(wx.EVT_BUTTON, self.onToolIconClick) - self.textIcon.Bind(wx.EVT_BUTTON, self.onToolIconClick) + for tool in self.tools.itervalues(): + tool[0].Bind(wx.EVT_BUTTON, self.onChooseTool) + + self.selectIcon.Bind(wx.EVT_BUTTON, self.onChooseTool) + self.lineIcon.Bind(wx.EVT_BUTTON, self.onChooseTool) + + self.penOptIcon.Bind(wx.EVT_BUTTON, self.onPenOptionIconClick) self.fillOptIcon.Bind(wx.EVT_BUTTON, self.onFillOptionIconClick) self.lineOptIcon.Bind(wx.EVT_BUTTON, self.onLineOptionIconClick) @@ -355,18 +369,22 @@ class DrawingFrame(wx.Frame): # Setup the main drawing area. self.drawPanel = wx.ScrolledWindow(self.topPanel, -1, - style=wx.SUNKEN_BORDER) + style=wx.SUNKEN_BORDER|wx.NO_FULL_REPAINT_ON_RESIZE) self.drawPanel.SetBackgroundColour(wx.WHITE) self.drawPanel.EnableScrolling(True, True) self.drawPanel.SetScrollbars(20, 20, PAGE_WIDTH / 20, PAGE_HEIGHT / 20) - self.drawPanel.Bind(wx.EVT_LEFT_DOWN, self.onMouseEvent) - self.drawPanel.Bind(wx.EVT_LEFT_DCLICK, self.onDoubleClickEvent) - self.drawPanel.Bind(wx.EVT_RIGHT_DOWN, self.onRightClick) - self.drawPanel.Bind(wx.EVT_MOTION, self.onMouseEvent) - self.drawPanel.Bind(wx.EVT_LEFT_UP, self.onMouseEvent) - self.drawPanel.Bind(wx.EVT_PAINT, self.onPaintEvent) + self.drawPanel.Bind(wx.EVT_MOUSE_EVENTS, self.onMouseEvent) + + self.drawPanel.Bind(wx.EVT_IDLE, self.onIdle) + self.drawPanel.Bind(wx.EVT_SIZE, self.onSize) + self.drawPanel.Bind(wx.EVT_PAINT, self.onPaint) + self.drawPanel.Bind(wx.EVT_ERASE_BACKGROUND, self.onEraseBackground) + self.drawPanel.Bind(wx.EVT_SCROLLWIN, self.onPanelScroll) + + self.Bind(wx.EVT_TIMER, self.onIdle) + # Position everything in the window. @@ -382,8 +400,13 @@ class DrawingFrame(wx.Frame): # Select an initial tool. + self.curToolName = None + self.curToolIcon = None self.curTool = None - self._setCurrentTool(self.selectIcon) + self.setCurrentTool("select") + + # Set initial dc mode to fast + self.wrapDC = lambda dc: dc # Setup our frame to hold the contents of a sketch document. @@ -391,35 +414,36 @@ class DrawingFrame(wx.Frame): self.fileName = fileName self.contents = [] # front-to-back ordered list of DrawingObjects. self.selection = [] # List of selected DrawingObjects. - self.undoInfo = None # Saved contents for undo. - self.dragMode = drag_NONE # Current mouse-drag mode. + self.undoStack = [] # Stack of saved contents for undo. + self.redoStack = [] # Stack of saved contents for redo. if self.fileName != None: self.loadContents() + self._initBuffer() + self._adjustMenus() # Finally, set our initial pen, fill and line options. - self.penColour = wx.BLACK - self.fillColour = wx.WHITE - self.lineSize = 1 + self._setPenColour(wx.BLACK) + self._setFillColour(wx.Colour(215,253,254)) + self._setLineSize(2) + + self.backgroundFillBrush = None # create on demand + + # Start the background redraw timer + # This is optional, but it gives the double-buffered contents a + # chance to redraw even when idle events are disabled (like during + # resize and scrolling) + self.redrawTimer = wx.Timer(self) + self.redrawTimer.Start(700) + # ============================ # == Event Handling Methods == # ============================ - def onToolIconClick(self, event): - """ Respond to the user clicking on one of our tool icons. - """ - iconID = event.GetEventObject().GetId() - if iconID == id_SELECT: self.doChooseSelectTool() - elif iconID == id_LINE: self.doChooseLineTool() - elif iconID == id_RECT: self.doChooseRectTool() - elif iconID == id_ELLIPSE: self.doChooseEllipseTool() - elif iconID == id_TEXT: self.doChooseTextTool() - else: wx.Bell(); print "1" - def onPenOptionIconClick(self, event): """ Respond to the user clicking on the "Pen Options" icon. @@ -431,6 +455,7 @@ class DrawingFrame(wx.Frame): data.SetColour(self.penColour) dialog = wx.ColourDialog(self, data) + dialog.SetTitle('Choose line colour') if dialog.ShowModal() == wx.ID_OK: c = dialog.GetColourData().GetColour() self._setPenColour(wx.Colour(c.Red(), c.Green(), c.Blue())) @@ -447,6 +472,7 @@ class DrawingFrame(wx.Frame): data.SetColour(self.fillColour) dialog = wx.ColourDialog(self, data) + dialog.SetTitle('Choose fill colour') if dialog.ShowModal() == wx.ID_OK: c = dialog.GetColourData().GetColour() self._setFillColour(wx.Colour(c.Red(), c.Green(), c.Blue())) @@ -472,294 +498,46 @@ class DrawingFrame(wx.Frame): We make the arrow keys move the selected object(s) by one pixel in the given direction. """ + step = 1 + if event.ShiftDown(): + step = 20 + if event.GetKeyCode() == wx.WXK_UP: - self._moveObject(0, -1) + self._moveObject(0, -step) elif event.GetKeyCode() == wx.WXK_DOWN: - self._moveObject(0, 1) + self._moveObject(0, step) elif event.GetKeyCode() == wx.WXK_LEFT: - self._moveObject(-1, 0) + self._moveObject(-step, 0) elif event.GetKeyCode() == wx.WXK_RIGHT: - self._moveObject(1, 0) + self._moveObject(step, 0) else: event.Skip() def onMouseEvent(self, event): - """ Respond to the user clicking on our main drawing panel. + """ Respond to mouse events in the main drawing panel How we respond depends on the currently selected tool. """ - if not (event.LeftDown() or event.Dragging() or event.LeftUp()): - return # Ignore mouse movement without click/drag. - - if self.curTool == self.selectIcon: - feedbackType = feedback_RECT - action = self.selectByRectangle - actionParam = param_RECT - selecting = True - dashedLine = True - elif self.curTool == self.lineIcon: - feedbackType = feedback_LINE - action = self.createLine - actionParam = param_LINE - selecting = False - dashedLine = False - elif self.curTool == self.rectIcon: - feedbackType = feedback_RECT - action = self.createRect - actionParam = param_RECT - selecting = False - dashedLine = False - elif self.curTool == self.ellipseIcon: - feedbackType = feedback_ELLIPSE - action = self.createEllipse - actionParam = param_RECT - selecting = False - dashedLine = False - elif self.curTool == self.textIcon: - feedbackType = feedback_RECT - action = self.createText - actionParam = param_RECT - selecting = False - dashedLine = True - else: - wx.Bell(); print "2" - return - - if event.LeftDown(): - mousePt = self._getEventCoordinates(event) - if selecting: - obj, handle = self._getObjectAndSelectionHandleAt(mousePt) - - if selecting and (obj != None) and (handle != handle_NONE): - - # The user clicked on an object's selection handle. Let the - # user resize the clicked-on object. - - self.dragMode = drag_RESIZE - self.resizeObject = obj - - if obj.getType() == obj_LINE: - self.resizeFeedback = feedback_LINE - pos = obj.getPosition() - startPt = wx.Point(pos.x + obj.getStartPt().x, - pos.y + obj.getStartPt().y) - endPt = wx.Point(pos.x + obj.getEndPt().x, - pos.y + obj.getEndPt().y) - if handle == handle_START_POINT: - self.resizeAnchor = endPt - self.resizeFloater = startPt - else: - self.resizeAnchor = startPt - self.resizeFloater = endPt - else: - self.resizeFeedback = feedback_RECT - pos = obj.getPosition() - size = obj.getSize() - topLeft = wx.Point(pos.x, pos.y) - topRight = wx.Point(pos.x + size.width, pos.y) - botLeft = wx.Point(pos.x, pos.y + size.height) - botRight = wx.Point(pos.x + size.width, pos.y + size.height) - - if handle == handle_TOP_LEFT: - self.resizeAnchor = botRight - self.resizeFloater = topLeft - elif handle == handle_TOP_RIGHT: - self.resizeAnchor = botLeft - self.resizeFloater = topRight - elif handle == handle_BOTTOM_LEFT: - self.resizeAnchor = topRight - self.resizeFloater = botLeft - elif handle == handle_BOTTOM_RIGHT: - self.resizeAnchor = topLeft - self.resizeFloater = botRight - - self.curPt = mousePt - self.resizeOffsetX = self.resizeFloater.x - mousePt.x - self.resizeOffsetY = self.resizeFloater.y - mousePt.y - endPt = wx.Point(self.curPt.x + self.resizeOffsetX, - self.curPt.y + self.resizeOffsetY) - self._drawVisualFeedback(self.resizeAnchor, endPt, - self.resizeFeedback, False) - - elif selecting and (self._getObjectAt(mousePt) != None): - - # The user clicked on an object to select it. If the user - # drags, he/she will move the object. - - self.select(self._getObjectAt(mousePt)) - self.dragMode = drag_MOVE - self.moveOrigin = mousePt - self.curPt = mousePt - self._drawObjectOutline(0, 0) - - else: - - # The user is dragging out a selection rect or new object. - - self.dragOrigin = mousePt - self.curPt = mousePt - self.drawPanel.SetCursor(wx.CROSS_CURSOR) - self.drawPanel.CaptureMouse() - self._drawVisualFeedback(mousePt, mousePt, feedbackType, - dashedLine) - self.dragMode = drag_DRAG - - event.Skip() - return - - if event.Dragging(): - if self.dragMode == drag_RESIZE: - - # We're resizing an object. - - mousePt = self._getEventCoordinates(event) - if (self.curPt.x != mousePt.x) or (self.curPt.y != mousePt.y): - # Erase previous visual feedback. - endPt = wx.Point(self.curPt.x + self.resizeOffsetX, - self.curPt.y + self.resizeOffsetY) - self._drawVisualFeedback(self.resizeAnchor, endPt, - self.resizeFeedback, False) - self.curPt = mousePt - # Draw new visual feedback. - endPt = wx.Point(self.curPt.x + self.resizeOffsetX, - self.curPt.y + self.resizeOffsetY) - self._drawVisualFeedback(self.resizeAnchor, endPt, - self.resizeFeedback, False) - - elif self.dragMode == drag_MOVE: - - # We're moving a selected object. - - mousePt = self._getEventCoordinates(event) - if (self.curPt.x != mousePt.x) or (self.curPt.y != mousePt.y): - # Erase previous visual feedback. - self._drawObjectOutline(self.curPt.x - self.moveOrigin.x, - self.curPt.y - self.moveOrigin.y) - self.curPt = mousePt - # Draw new visual feedback. - self._drawObjectOutline(self.curPt.x - self.moveOrigin.x, - self.curPt.y - self.moveOrigin.y) - - elif self.dragMode == drag_DRAG: - - # We're dragging out a new object or selection rect. - - mousePt = self._getEventCoordinates(event) - if (self.curPt.x != mousePt.x) or (self.curPt.y != mousePt.y): - # Erase previous visual feedback. - self._drawVisualFeedback(self.dragOrigin, self.curPt, - feedbackType, dashedLine) - self.curPt = mousePt - # Draw new visual feedback. - self._drawVisualFeedback(self.dragOrigin, self.curPt, - feedbackType, dashedLine) - - event.Skip() - return - - if event.LeftUp(): - if self.dragMode == drag_RESIZE: - - # We're resizing an object. - - mousePt = self._getEventCoordinates(event) - # Erase last visual feedback. - endPt = wx.Point(self.curPt.x + self.resizeOffsetX, - self.curPt.y + self.resizeOffsetY) - self._drawVisualFeedback(self.resizeAnchor, endPt, - self.resizeFeedback, False) - - resizePt = wx.Point(mousePt.x + self.resizeOffsetX, - mousePt.y + self.resizeOffsetY) - - if (self.resizeFloater.x != resizePt.x) or \ - (self.resizeFloater.y != resizePt.y): - self._resizeObject(self.resizeObject, - self.resizeAnchor, - self.resizeFloater, - resizePt) - else: - self.drawPanel.Refresh() # Clean up after empty resize. - - elif self.dragMode == drag_MOVE: - - # We're moving a selected object. - - mousePt = self._getEventCoordinates(event) - # Erase last visual feedback. - self._drawObjectOutline(self.curPt.x - self.moveOrigin.x, - self.curPt.y - self.moveOrigin.y) - if (self.moveOrigin.x != mousePt.x) or \ - (self.moveOrigin.y != mousePt.y): - self._moveObject(mousePt.x - self.moveOrigin.x, - mousePt.y - self.moveOrigin.y) - else: - self.drawPanel.Refresh() # Clean up after empty drag. - - elif self.dragMode == drag_DRAG: - - # We're dragging out a new object or selection rect. - - mousePt = self._getEventCoordinates(event) - # Erase last visual feedback. - self._drawVisualFeedback(self.dragOrigin, self.curPt, - feedbackType, dashedLine) - self.drawPanel.ReleaseMouse() - self.drawPanel.SetCursor(wx.STANDARD_CURSOR) - # Perform the appropriate action for the current tool. - if actionParam == param_RECT: - x1 = min(self.dragOrigin.x, self.curPt.x) - y1 = min(self.dragOrigin.y, self.curPt.y) - x2 = max(self.dragOrigin.x, self.curPt.x) - y2 = max(self.dragOrigin.y, self.curPt.y) - - startX = x1 - startY = y1 - width = x2 - x1 - height = y2 - y1 - - if not selecting: - if ((x2-x1) < 8) or ((y2-y1) < 8): return # Too small. - - action(x1, y1, x2-x1, y2-y1) - elif actionParam == param_LINE: - action(self.dragOrigin.x, self.dragOrigin.y, - self.curPt.x, self.curPt.y) - - self.dragMode = drag_NONE # We've finished with this mouse event. - event.Skip() - - - def onDoubleClickEvent(self, event): - """ Respond to a double-click within our drawing panel. - """ - mousePt = self._getEventCoordinates(event) - obj = self._getObjectAt(mousePt) - if obj == None: return - - # Let the user edit the given object. - - if obj.getType() == obj_TEXT: - editor = EditTextObjectDialog(self, "Edit Text Object") - editor.objectToDialog(obj) - if editor.ShowModal() == wx.ID_CANCEL: - editor.Destroy() - return + if self.curTool is None: return - self._saveUndoInfo() + # Translate event into canvas coordinates and pass to current tool + origx,origy = event.X, event.Y + pt = self._getEventCoordinates(event) + event.m_x = pt.x + event.m_y = pt.y + handled = self.curTool.onMouseEvent(self,event) + event.m_x = origx + event.m_y = origy - editor.dialogToObject(obj) - editor.Destroy() - - self.dirty = True - self.drawPanel.Refresh() - self._adjustMenus() - else: - wx.Bell(); print "3" + if handled: return + # otherwise handle it ourselves + if event.RightDown(): + self.doPopupContextMenu(event) + - def onRightClick(self, event): + def doPopupContextMenu(self, event): """ Respond to the user right-clicking within our drawing panel. We select the clicked-on item, if necessary, and display a pop-up @@ -767,7 +545,7 @@ class DrawingFrame(wx.Frame): item(s). """ mousePt = self._getEventCoordinates(event) - obj = self._getObjectAt(mousePt) + obj = self.getObjectAt(mousePt) if obj == None: return # Nothing selected. @@ -779,51 +557,161 @@ class DrawingFrame(wx.Frame): menu = wx.Menu() menu.Append(menu_DUPLICATE, "Duplicate") - menu.Append(menu_EDIT_TEXT, "Edit...") - menu.Append(menu_DELETE, "Delete") + menu.Append(menu_EDIT_PROPS,"Edit...") + menu.Append(wx.ID_CLEAR, "Delete") menu.AppendSeparator() menu.Append(menu_MOVE_FORWARD, "Move Forward") menu.Append(menu_MOVE_TO_FRONT, "Move to Front") menu.Append(menu_MOVE_BACKWARD, "Move Backward") menu.Append(menu_MOVE_TO_BACK, "Move to Back") - menu.Enable(menu_EDIT_TEXT, obj.getType() == obj_TEXT) + menu.Enable(menu_EDIT_PROPS, obj.hasPropertyEditor()) menu.Enable(menu_MOVE_FORWARD, obj != self.contents[0]) menu.Enable(menu_MOVE_TO_FRONT, obj != self.contents[0]) menu.Enable(menu_MOVE_BACKWARD, obj != self.contents[-1]) menu.Enable(menu_MOVE_TO_BACK, obj != self.contents[-1]) - self.Bind(wx.EVT_MENU, self.doDuplicate, id=menu_DUPLICATE) - self.Bind(wx.EVT_MENU, self.doEditText, id=menu_EDIT_TEXT) - self.Bind(wx.EVT_MENU, self.doDelete, id=menu_DELETE) + self.Bind(wx.EVT_MENU, self.doDuplicate, id=menu_DUPLICATE) + self.Bind(wx.EVT_MENU, self.doEditObject, id=menu_EDIT_PROPS) + self.Bind(wx.EVT_MENU, self.doDelete, id=wx.ID_CLEAR) self.Bind(wx.EVT_MENU, self.doMoveForward, id=menu_MOVE_FORWARD) self.Bind(wx.EVT_MENU, self.doMoveToFront, id=menu_MOVE_TO_FRONT) - self.Bind(wx.EVT_MENU, self.doMoveBackward, id=menu_MOVE_BACKWARD) - self.Bind(wx.EVT_MENU, self.doMoveToBack, id=menu_MOVE_TO_BACK) + self.Bind(wx.EVT_MENU, self.doMoveBackward,id=menu_MOVE_BACKWARD) + self.Bind(wx.EVT_MENU, self.doMoveToBack, id=menu_MOVE_TO_BACK) # Show the pop-up menu. clickPt = wx.Point(mousePt.x + self.drawPanel.GetPosition().x, mousePt.y + self.drawPanel.GetPosition().y) - self.drawPanel.PopupMenu(menu, clickPt) + self.drawPanel.PopupMenu(menu, mousePt) menu.Destroy() - def onPaintEvent(self, event): - """ Respond to a request to redraw the contents of our drawing panel. + def onSize(self, event): + """ + Called when the window is resized. We set a flag so the idle + handler will resize the buffer. + """ + self.requestRedraw() + + + def onIdle(self, event): + """ + If the size was changed then resize the bitmap used for double + buffering to match the window size. We do it in Idle time so + there is only one refresh after resizing is done, not lots while + it is happening. + """ + if self._reInitBuffer and self.IsShown(): + self._initBuffer() + self.drawPanel.Refresh(False) + + def requestRedraw(self): + """Requests a redraw of the drawing panel contents. + + The actual redrawing doesn't happen until the next idle time. + """ + self._reInitBuffer = True + + def onPaint(self, event): + """ + Called when the window is exposed. """ - dc = wx.PaintDC(self.drawPanel) + # Create a buffered paint DC. It will create the real + # wx.PaintDC and then blit the bitmap to it when dc is + # deleted. + dc = wx.BufferedPaintDC(self.drawPanel, self.buffer) + + + # On Windows, if that's all we do things look a little rough + # So in order to make scrolling more polished-looking + # we iterate over the exposed regions and fill in unknown + # areas with a fall-back pattern. + + if wx.Platform != '__WXMSW__': + return + + # First get the update rects and subtract off the part that + # self.buffer has correct already + region = self.drawPanel.GetUpdateRegion() + panelRect = self.drawPanel.GetClientRect() + offset = list(self.drawPanel.CalcUnscrolledPosition(0,0)) + offset[0] -= self.saved_offset[0] + offset[1] -= self.saved_offset[1] + region.Subtract(-offset[0],- offset[1],panelRect.Width, panelRect.Height) + + # Now iterate over the remaining region rects and fill in with a pattern + rgn_iter = wx.RegionIterator(region) + if rgn_iter.HaveRects(): + self.setBackgroundMissingFillStyle(dc) + offset = self.drawPanel.CalcUnscrolledPosition(0,0) + while rgn_iter: + r = rgn_iter.GetRect() + if r.Size != self.drawPanel.ClientSize: + dc.DrawRectangleRect(r) + rgn_iter.Next() + + + def setBackgroundMissingFillStyle(self, dc): + if self.backgroundFillBrush is None: + # Win95 can only handle a 8x8 stipple bitmaps max + #stippleBitmap = wx.BitmapFromBits("\xf0"*4 + "\x0f"*4,8,8) + # ...but who uses Win95? + stippleBitmap = wx.BitmapFromBits("\x06",2,2) + stippleBitmap.SetMask(wx.Mask(stippleBitmap)) + bgbrush = wx.Brush(wx.WHITE, wx.STIPPLE_MASK_OPAQUE) + bgbrush.SetStipple(stippleBitmap) + self.backgroundFillBrush = bgbrush + + dc.SetPen(wx.TRANSPARENT_PEN) + dc.SetBrush(self.backgroundFillBrush) + dc.SetTextForeground(wx.LIGHT_GREY) + dc.SetTextBackground(wx.WHITE) + + + def onEraseBackground(self, event): + """ + Overridden to do nothing to prevent flicker + """ + pass + + + def onPanelScroll(self, event): + """ + Called when the user changes scrolls the drawPanel + """ + # make a note to ourselves to redraw when we get a chance + self.requestRedraw() + event.Skip() + pass + + def drawContents(self, dc): + """ + Does the actual drawing of all drawing contents with the specified dc + """ + # PrepareDC sets the device origin according to current scrolling self.drawPanel.PrepareDC(dc) - dc.BeginDrawing() - for i in range(len(self.contents)-1, -1, -1): - obj = self.contents[i] + gdc = self.wrapDC(dc) + + # First pass draws objects + ordered_selection = [] + for obj in self.contents[::-1]: if obj in self.selection: - obj.draw(dc, True) + obj.draw(gdc, True) + ordered_selection.append(obj) else: - obj.draw(dc, False) + obj.draw(gdc, False) + + # First pass draws objects + if self.curTool is not None: + self.curTool.draw(gdc) + + # Second pass draws selection handles so they're always on top + for obj in ordered_selection: + obj.drawHandles(gdc) + - dc.EndDrawing() # ========================== # == Menu Command Methods == @@ -937,26 +825,22 @@ class DrawingFrame(wx.Frame): def doUndo(self, event): """ Respond to the "Undo" menu command. """ - if self.undoInfo == None: return - - undoData = self.undoInfo - self._saveUndoInfo() # For undoing the undo... + if not self.undoStack: return - self.contents = [] - - for type, data in undoData["contents"]: - obj = DrawingObject(type) - obj.setData(data) - self.contents.append(obj) + state = self._buildStoredState() + self.redoStack.append(state) + state = self.undoStack.pop() + self._restoreStoredState(state) - self.selection = [] - for i in undoData["selection"]: - self.selection.append(self.contents[i]) - - self.dirty = True - self.drawPanel.Refresh() - self._adjustMenus() + def doRedo(self, event): + """ Respond to the "Redo" menu. + """ + if not self.redoStack: return + state = self._buildStoredState() + self.undoStack.append(state) + state = self.redoStack.pop() + self._restoreStoredState(state) def doSelectAll(self, event): """ Respond to the "Select All" menu command. @@ -967,13 +851,12 @@ class DrawingFrame(wx.Frame): def doDuplicate(self, event): """ Respond to the "Duplicate" menu command. """ - self._saveUndoInfo() + self.saveUndoInfo() objs = [] for obj in self.contents: if obj in self.selection: - newObj = DrawingObject(obj.getType()) - newObj.setData(obj.getData()) + newObj = copy.deepcopy(obj) pos = obj.getPosition() newObj.setPosition(wx.Point(pos.x + 10, pos.y + 10)) objs.append(newObj) @@ -983,34 +866,26 @@ class DrawingFrame(wx.Frame): self.selectMany(objs) - def doEditText(self, event): - """ Respond to the "Edit Text" menu command. + def doEditObject(self, event): + """ Respond to the "Edit..." menu command. """ if len(self.selection) != 1: return obj = self.selection[0] - if obj.getType() != obj_TEXT: return - - editor = EditTextObjectDialog(self, "Edit Text Object") - editor.objectToDialog(obj) - if editor.ShowModal() == wx.ID_CANCEL: - editor.Destroy() - return - - self._saveUndoInfo() - - editor.dialogToObject(obj) - editor.Destroy() + if not obj.hasPropertyEditor(): + assert False, "doEditObject called on non-editable" - self.dirty = True - self.drawPanel.Refresh() - self._adjustMenus() + ret = obj.doPropertyEdit(self) + if ret: + self.dirty = True + self.requestRedraw() + self._adjustMenus() def doDelete(self, event): """ Respond to the "Delete" menu command. """ - self._saveUndoInfo() + self.saveUndoInfo() for obj in self.selection: self.contents.remove(obj) @@ -1018,56 +893,53 @@ class DrawingFrame(wx.Frame): self.deselectAll() - def doChooseSelectTool(self, event=None): - """ Respond to the "Select Tool" menu command. - """ - self._setCurrentTool(self.selectIcon) - self.drawPanel.SetCursor(wx.STANDARD_CURSOR) - self._adjustMenus() - - - def doChooseLineTool(self, event=None): - """ Respond to the "Line Tool" menu command. - """ - self._setCurrentTool(self.lineIcon) - self.drawPanel.SetCursor(wx.CROSS_CURSOR) - self.deselectAll() - self._adjustMenus() - - - def doChooseRectTool(self, event=None): - """ Respond to the "Rect Tool" menu command. - """ - self._setCurrentTool(self.rectIcon) - self.drawPanel.SetCursor(wx.CROSS_CURSOR) - self.deselectAll() - self._adjustMenus() - - - def doChooseEllipseTool(self, event=None): - """ Respond to the "Ellipse Tool" menu command. - """ - self._setCurrentTool(self.ellipseIcon) - self.drawPanel.SetCursor(wx.CROSS_CURSOR) - self.deselectAll() - self._adjustMenus() - - - def doChooseTextTool(self, event=None): - """ Respond to the "Text Tool" menu command. + def onChooseTool(self, event): + """ Respond to tool selection menu and tool palette selections """ - self._setCurrentTool(self.textIcon) - self.drawPanel.SetCursor(wx.CROSS_CURSOR) - self.deselectAll() + obj = event.GetEventObject() + id2name = { id_SELECT: "select", + id_LINE: "line", + id_POLYGON: "polygon", + id_SCRIBBLE: "scribble", + id_RECT: "rect", + id_ELLIPSE: "ellipse", + id_TEXT: "text" } + toolID = event.GetId() + name = id2name.get( toolID ) + + if name: + self.setCurrentTool(name) + + def updChooseTool(self, event): + """UI update event that keeps tool menu in sync with the PaletteIcons""" + obj = event.GetEventObject() + id2name = { id_SELECT: "select", + id_LINE: "line", + id_POLYGON: "polygon", + id_SCRIBBLE: "scribble", + id_RECT: "rect", + id_ELLIPSE: "ellipse", + id_TEXT: "text" } + toolID = event.GetId() + event.Check( toolID == self.curToolIcon.GetId() ) + + + def doChooseQuality(self, event): + """Respond to the render quality menu commands + """ + if event.GetId() == menu_DC: + self.wrapDC = lambda dc: dc + else: + self.wrapDC = lambda dc: wx.GCDC(dc) self._adjustMenus() - + self.requestRedraw() def doMoveForward(self, event): """ Respond to the "Move Forward" menu command. """ if len(self.selection) != 1: return - self._saveUndoInfo() + self.saveUndoInfo() obj = self.selection[0] index = self.contents.index(obj) @@ -1076,7 +948,7 @@ class DrawingFrame(wx.Frame): del self.contents[index] self.contents.insert(index-1, obj) - self.drawPanel.Refresh() + self.requestRedraw() self._adjustMenus() @@ -1085,13 +957,13 @@ class DrawingFrame(wx.Frame): """ if len(self.selection) != 1: return - self._saveUndoInfo() + self.saveUndoInfo() obj = self.selection[0] self.contents.remove(obj) self.contents.insert(0, obj) - self.drawPanel.Refresh() + self.requestRedraw() self._adjustMenus() @@ -1100,7 +972,7 @@ class DrawingFrame(wx.Frame): """ if len(self.selection) != 1: return - self._saveUndoInfo() + self.saveUndoInfo() obj = self.selection[0] index = self.contents.index(obj) @@ -1109,7 +981,7 @@ class DrawingFrame(wx.Frame): del self.contents[index] self.contents.insert(index+1, obj) - self.drawPanel.Refresh() + self.requestRedraw() self._adjustMenus() @@ -1118,13 +990,13 @@ class DrawingFrame(wx.Frame): """ if len(self.selection) != 1: return - self._saveUndoInfo() + self.saveUndoInfo() obj = self.selection[0] self.contents.remove(obj) self.contents.append(obj) - self.drawPanel.Refresh() + self.requestRedraw() self._adjustMenus() @@ -1170,8 +1042,12 @@ class DrawingFrame(wx.Frame): lab4.SetFont(boldFont) lab4.SetSize(lab4.GetBestSize()) - lab5 = wx.StaticText(panel, -1, "Author: Erik Westra " + \ - "(ewestra@wave.co.nz)") + lab5 = wx.StaticText(panel, -1, + "Author: Erik Westra " + \ + "(ewestra@wave.co.nz)\n" + \ + "Contributors: Bill Baxter " +\ + "(wbaxter@gmail.com) ") + lab5.SetFont(boldFont) lab5.SetSize(lab5.GetBestSize()) @@ -1204,89 +1080,62 @@ class DrawingFrame(wx.Frame): btn = dialog.ShowModal() dialog.Destroy() + def getTextEditor(self): + if not hasattr(self,'textEditor') or not self.textEditor: + self.textEditor = EditTextObjectDialog(self, "Edit Text Object") + return self.textEditor + # ============================= # == Object Creation Methods == # ============================= - def createLine(self, x1, y1, x2, y2): - """ Create a new line object at the given position and size. - """ - self._saveUndoInfo() - - topLeftX = min(x1, x2) - topLeftY = min(y1, y2) - botRightX = max(x1, x2) - botRightY = max(y1, y2) - - obj = DrawingObject(obj_LINE, position=wx.Point(topLeftX, topLeftY), - size=wx.Size(botRightX-topLeftX, - botRightY-topLeftY), - penColour=self.penColour, - fillColour=self.fillColour, - lineSize=self.lineSize, - startPt = wx.Point(x1 - topLeftX, y1 - topLeftY), - endPt = wx.Point(x2 - topLeftX, y2 - topLeftY)) - self.contents.insert(0, obj) - self.dirty = True - self.doChooseSelectTool() - self.select(obj) - - - def createRect(self, x, y, width, height): - """ Create a new rectangle object at the given position and size. + def addObject(self, obj, select=True): + """Add a new drawing object to the canvas. + + If select is True then also select the object """ - self._saveUndoInfo() - - obj = DrawingObject(obj_RECT, position=wx.Point(x, y), - size=wx.Size(width, height), - penColour=self.penColour, - fillColour=self.fillColour, - lineSize=self.lineSize) + self.saveUndoInfo() self.contents.insert(0, obj) self.dirty = True - self.doChooseSelectTool() - self.select(obj) + if select: + self.select(obj) + #self.setCurrentTool('select') + def saveUndoInfo(self): + """ Remember the current state of the document, to allow for undo. - def createEllipse(self, x, y, width, height): - """ Create a new ellipse object at the given position and size. + We make a copy of the document's contents, so that we can return to + the previous contents if the user does something and then wants to + undo the operation. + + This should be called only for a new modification to the document + since it erases the redo history. """ - self._saveUndoInfo() + state = self._buildStoredState() - obj = DrawingObject(obj_ELLIPSE, position=wx.Point(x, y), - size=wx.Size(width, height), - penColour=self.penColour, - fillColour=self.fillColour, - lineSize=self.lineSize) - self.contents.insert(0, obj) + self.undoStack.append(state) + self.redoStack = [] self.dirty = True - self.doChooseSelectTool() - self.select(obj) + self._adjustMenus() + # ======================= + # == Selection Methods == + # ======================= - def createText(self, x, y, width, height): - """ Create a new text object at the given position and size. + def setCurrentTool(self, toolName): + """ Set the currently selected tool. """ - editor = EditTextObjectDialog(self, "Create Text Object") - if editor.ShowModal() == wx.ID_CANCEL: - editor.Destroy() - return - - self._saveUndoInfo() - - obj = DrawingObject(obj_TEXT, position=wx.Point(x, y), - size=wx.Size(width, height)) - editor.dialogToObject(obj) - editor.Destroy() + + toolIcon, tool = self.tools[toolName] + if self.curToolIcon is not None: + self.curToolIcon.SetValue(False) - self.contents.insert(0, obj) - self.dirty = True - self.doChooseSelectTool() - self.select(obj) + toolIcon.SetValue(True) + self.curToolName = toolName + self.curToolIcon = toolIcon + self.curTool = tool + self.drawPanel.SetCursor(tool.getDefaultCursor()) - # ======================= - # == Selection Methods == - # ======================= def selectAll(self): """ Select every DrawingObject in our document. @@ -1294,7 +1143,7 @@ class DrawingFrame(wx.Frame): self.selection = [] for obj in self.contents: self.selection.append(obj) - self.drawPanel.Refresh() + self.requestRedraw() self._adjustMenus() @@ -1302,23 +1151,27 @@ class DrawingFrame(wx.Frame): """ Deselect every DrawingObject in our document. """ self.selection = [] - self.drawPanel.Refresh() + self.requestRedraw() self._adjustMenus() - def select(self, obj): + def select(self, obj, add=False): """ Select the given DrawingObject within our document. - """ - self.selection = [obj] - self.drawPanel.Refresh() - self._adjustMenus() + If 'add' is True obj is added onto the current selection + """ + if not add: + self.selection = [] + if obj not in self.selection: + self.selection += [obj] + self.requestRedraw() + self._adjustMenus() def selectMany(self, objs): """ Select the given list of DrawingObjects. """ self.selection = objs - self.drawPanel.Refresh() + self.requestRedraw() self._adjustMenus() @@ -1329,9 +1182,36 @@ class DrawingFrame(wx.Frame): for obj in self.contents: if obj.objectWithinRect(x, y, width, height): self.selection.append(obj) - self.drawPanel.Refresh() + self.requestRedraw() self._adjustMenus() + def getObjectAndSelectionHandleAt(self, pt): + """ Return the object and selection handle at the given point. + + We draw selection handles (small rectangles) around the currently + selected object(s). If the given point is within one of the + selection handle rectangles, we return the associated object and a + code indicating which selection handle the point is in. If the + point isn't within any selection handle at all, we return the tuple + (None, None). + """ + for obj in self.selection: + handle = obj.getSelectionHandleContainingPoint(pt.x, pt.y) + if handle is not None: + return obj, handle + + return None, None + + + def getObjectAt(self, pt): + """ Return the first object found which is at the given point. + """ + for obj in self.contents: + if obj.objectContainsPoint(pt.x, pt.y): + return obj + return None + + # ====================== # == File I/O Methods == # ====================== @@ -1339,35 +1219,50 @@ class DrawingFrame(wx.Frame): def loadContents(self): """ Load the contents of our document into memory. """ - f = open(self.fileName, "rb") - objData = cPickle.load(f) - f.close() - for type, data in objData: - obj = DrawingObject(type) - obj.setData(data) - self.contents.append(obj) + try: + f = open(self.fileName, "rb") + objData = cPickle.load(f) + f.close() - self.dirty = False - self.selection = [] - self.undoInfo = None + for klass, data in objData: + obj = klass() + obj.setData(data) + self.contents.append(obj) + + self.dirty = False + self.selection = [] + self.undoStack = [] + self.redoStack = [] + + self.requestRedraw() + self._adjustMenus() + except: + response = wx.MessageBox("Unable to load " + self.fileName + ".", + "Error", wx.OK|wx.ICON_ERROR, self) - self.drawPanel.Refresh() - self._adjustMenus() def saveContents(self): """ Save the contents of our document to disk. """ - objData = [] - for obj in self.contents: - objData.append([obj.getType(), obj.getData()]) + # SWIG-wrapped native wx contents cannot be pickled, so + # we have to convert our data to something pickle-friendly. + + try: + objData = [] + for obj in self.contents: + objData.append([obj.__class__, obj.getData()]) - f = open(self.fileName, "wb") - cPickle.dump(objData, f) - f.close() + f = open(self.fileName, "wb") + cPickle.dump(objData, f) + f.close() - self.dirty = False + self.dirty = False + self._adjustMenus() + except: + response = wx.MessageBox("Unable to load " + self.fileName + ".", + "Error", wx.OK|wx.ICON_ERROR, self) def askIfUserWantsToSave(self, action): @@ -1402,16 +1297,38 @@ class DrawingFrame(wx.Frame): # == Private Methods == # ===================== + def _initBuffer(self): + """Initialize the bitmap used for buffering the display.""" + size = self.drawPanel.GetSize() + self.buffer = wx.EmptyBitmap(max(1,size.width),max(1,size.height)) + dc = wx.BufferedDC(None, self.buffer) + dc.SetBackground(wx.Brush(self.drawPanel.GetBackgroundColour())) + dc.Clear() + self.drawContents(dc) + del dc # commits all drawing to the buffer + + self.saved_offset = self.drawPanel.CalcUnscrolledPosition(0,0) + + self._reInitBuffer = False + + + def _adjustMenus(self): """ Adjust our menus and toolbar to reflect the current state of the world. + + Doing this manually rather than using an EVT_UPDATE_UI is a bit + more efficient (since it's only done when it's really needed), + but it means we have to remember to call _adjustMenus any time + menus may need adjusting. """ canSave = (self.fileName != None) and self.dirty canRevert = (self.fileName != None) and self.dirty - canUndo = self.undoInfo != None + canUndo = self.undoStack!=[] + canRedo = self.redoStack!=[] selection = len(self.selection) > 0 onlyOne = len(self.selection) == 1 - isText = onlyOne and (self.selection[0].getType() == obj_TEXT) + hasEditor = onlyOne and self.selection[0].hasPropertyEditor() front = onlyOne and (self.selection[0] == self.contents[0]) back = onlyOne and (self.selection[0] == self.contents[-1]) @@ -1420,16 +1337,11 @@ class DrawingFrame(wx.Frame): self.fileMenu.Enable(wx.ID_SAVE, canSave) self.fileMenu.Enable(wx.ID_REVERT, canRevert) - self.editMenu.Enable(menu_UNDO, canUndo) + self.editMenu.Enable(wx.ID_UNDO, canUndo) + self.editMenu.Enable(wx.ID_REDO, canRedo) self.editMenu.Enable(menu_DUPLICATE, selection) - self.editMenu.Enable(menu_EDIT_TEXT, isText) - self.editMenu.Enable(menu_DELETE, selection) - - self.toolsMenu.Check(menu_SELECT, self.curTool == self.selectIcon) - self.toolsMenu.Check(menu_LINE, self.curTool == self.lineIcon) - self.toolsMenu.Check(menu_RECT, self.curTool == self.rectIcon) - self.toolsMenu.Check(menu_ELLIPSE, self.curTool == self.ellipseIcon) - self.toolsMenu.Check(menu_TEXT, self.curTool == self.textIcon) + self.editMenu.Enable(menu_EDIT_PROPS,hasEditor) + self.editMenu.Enable(wx.ID_CLEAR, selection) self.objectMenu.Enable(menu_MOVE_FORWARD, onlyOne and not front) self.objectMenu.Enable(menu_MOVE_TO_FRONT, onlyOne and not front) @@ -1438,85 +1350,98 @@ class DrawingFrame(wx.Frame): # Enable/disable our toolbar icons. - self.toolbar.EnableTool(wx.ID_NEW, True) - self.toolbar.EnableTool(wx.ID_OPEN, True) - self.toolbar.EnableTool(wx.ID_SAVE, canSave) - self.toolbar.EnableTool(menu_UNDO, canUndo) + self.toolbar.EnableTool(wx.ID_NEW, True) + self.toolbar.EnableTool(wx.ID_OPEN, True) + self.toolbar.EnableTool(wx.ID_SAVE, canSave) + self.toolbar.EnableTool(wx.ID_UNDO, canUndo) + self.toolbar.EnableTool(wx.ID_REDO, canRedo) self.toolbar.EnableTool(menu_DUPLICATE, selection) self.toolbar.EnableTool(menu_MOVE_FORWARD, onlyOne and not front) self.toolbar.EnableTool(menu_MOVE_BACKWARD, onlyOne and not back) - def _setCurrentTool(self, newToolIcon): - """ Set the currently selected tool. - """ - if self.curTool == newToolIcon: return # Nothing to do. - - if self.curTool != None: - self.curTool.deselect() - - newToolIcon.select() - self.curTool = newToolIcon - - def _setPenColour(self, colour): """ Set the default or selected object's pen colour. """ if len(self.selection) > 0: - self._saveUndoInfo() + self.saveUndoInfo() for obj in self.selection: obj.setPenColour(colour) - self.drawPanel.Refresh() - else: - self.penColour = colour - self.optionIndicator.setPenColour(colour) + self.requestRedraw() + + self.penColour = colour + self.optionIndicator.setPenColour(colour) def _setFillColour(self, colour): """ Set the default or selected object's fill colour. """ if len(self.selection) > 0: - self._saveUndoInfo() + self.saveUndoInfo() for obj in self.selection: obj.setFillColour(colour) - self.drawPanel.Refresh() - else: - self.fillColour = colour - self.optionIndicator.setFillColour(colour) + self.requestRedraw() + + self.fillColour = colour + self.optionIndicator.setFillColour(colour) def _setLineSize(self, size): """ Set the default or selected object's line size. """ if len(self.selection) > 0: - self._saveUndoInfo() + self.saveUndoInfo() for obj in self.selection: obj.setLineSize(size) - self.drawPanel.Refresh() - else: - self.lineSize = size - self.optionIndicator.setLineSize(size) + self.requestRedraw() + self.lineSize = size + self.optionIndicator.setLineSize(size) - def _saveUndoInfo(self): + + def _buildStoredState(self): """ Remember the current state of the document, to allow for undo. We make a copy of the document's contents, so that we can return to the previous contents if the user does something and then wants to - undo the operation. + undo the operation. + + Returns an object representing the current document state. """ savedContents = [] for obj in self.contents: - savedContents.append([obj.getType(), obj.getData()]) + savedContents.append([obj.__class__, obj.getData()]) savedSelection = [] for i in range(len(self.contents)): if self.contents[i] in self.selection: savedSelection.append(i) - self.undoInfo = {"contents" : savedContents, - "selection" : savedSelection} + info = {"contents" : savedContents, + "selection" : savedSelection} + + return info + + def _restoreStoredState(self, savedState): + """Restore the state of the document to a previous point for undo/redo. + + Takes a stored state object and recreates the document from it. + Used by undo/redo implementation. + """ + self.contents = [] + + for draw_class, data in savedState["contents"]: + obj = draw_class() + obj.setData(data) + self.contents.append(obj) + + self.selection = [] + for i in savedState["selection"]: + self.selection.append(self.contents[i]) + self.dirty = True + self._adjustMenus() + self.requestRedraw() def _resizeObject(self, obj, anchorPt, oldPt, newPt): """ Resize the given object. @@ -1528,12 +1453,12 @@ class DrawingFrame(wx.Frame): new point is less than the anchor point the object will need to be moved as well as resized, to avoid giving it a negative size. """ - if obj.getType() == obj_TEXT: + if isinstance(obj, TextDrawingObject): # Not allowed to resize text objects -- they're sized to fit text. - wx.Bell(); print "4" + wx.Bell() return - self._saveUndoInfo() + self.saveUndoInfo() topLeft = wx.Point(min(anchorPt.x, newPt.x), min(anchorPt.y, newPt.y)) @@ -1543,7 +1468,7 @@ class DrawingFrame(wx.Frame): newWidth = botRight.x - topLeft.x newHeight = botRight.y - topLeft.y - if obj.getType() == obj_LINE: + if isinstance(obj, LineDrawingObject): # Adjust the line so that its start and end points match the new # overall object size. @@ -1575,13 +1500,13 @@ class DrawingFrame(wx.Frame): obj.setPosition(topLeft) obj.setSize(wx.Size(botRight.x - topLeft.x, botRight.y - topLeft.y)) - self.drawPanel.Refresh() + self.requestRedraw() def _moveObject(self, offsetX, offsetY): """ Move the currently selected object(s) by the given offset. """ - self._saveUndoInfo() + self.saveUndoInfo() for obj in self.selection: pos = obj.getPosition() @@ -1589,7 +1514,7 @@ class DrawingFrame(wx.Frame): pos.y = pos.y + offsetY obj.setPosition(pos) - self.drawPanel.Refresh() + self.requestRedraw() def _buildLineSizePopup(self, lineSize): @@ -1629,7 +1554,7 @@ class DrawingFrame(wx.Frame): elif id == id_LINESIZE_4: self._setLineSize(4) elif id == id_LINESIZE_5: self._setLineSize(5) else: - wx.Bell(); print "5" + wx.Bell() return self.optionIndicator.setLineSize(self.lineSize) @@ -1647,35 +1572,8 @@ class DrawingFrame(wx.Frame): event.GetY() + (originY * unitY)) - def _getObjectAndSelectionHandleAt(self, pt): - """ Return the object and selection handle at the given point. - - We draw selection handles (small rectangles) around the currently - selected object(s). If the given point is within one of the - selection handle rectangles, we return the associated object and a - code indicating which selection handle the point is in. If the - point isn't within any selection handle at all, we return the tuple - (None, handle_NONE). - """ - for obj in self.selection: - handle = obj.getSelectionHandleContainingPoint(pt.x, pt.y) - if handle != handle_NONE: - return obj, handle - - return None, handle_NONE - - - def _getObjectAt(self, pt): - """ Return the first object found which is at the given point. - """ - for obj in self.contents: - if obj.objectContainsPoint(pt.x, pt.y): - return obj - return None - - - def _drawObjectOutline(self, offsetX, offsetY): - """ Draw an outline of the currently selected object. + def _drawObjectOutline(self, offsetX, offsetY): + """ Draw an outline of the currently selected object. The selected object's outline is drawn at the object's position plus the given offset. @@ -1702,109 +1600,607 @@ class DrawingFrame(wx.Frame): dc.EndDrawing() - def _drawVisualFeedback(self, startPt, endPt, type, dashedLine): - """ Draw visual feedback for a drawing operation. +#============================================================================ +class DrawingTool(object): + """Base class for drawing tools""" - The visual feedback consists of a line, ellipse, or rectangle based - around the two given points. 'type' should be one of the following - predefined feedback type constants: + def __init__(self): + pass - feedback_RECT -> draw rectangular feedback. - feedback_LINE -> draw line feedback. - feedback_ELLIPSE -> draw elliptical feedback. + def getDefaultCursor(self): + """Return the cursor to use by default which this drawing tool is selected""" + return wx.STANDARD_CURSOR - if 'dashedLine' is True, the feedback is drawn as a dashed rather - than a solid line. + def draw(self,dc): + pass - Note that the feedback is drawn by *inverting* the window's - contents, so calling _drawVisualFeedback twice in succession will - restore the window's contents back to what they were previously. + + def onMouseEvent(self,parent, event): + """Mouse events passed in from the parent. + + Returns True if the event is handled by the tool, + False if the canvas can try to use it. """ - dc = wx.ClientDC(self.drawPanel) - self.drawPanel.PrepareDC(dc) - dc.BeginDrawing() - if dashedLine: + event.Skip() + return False + +#---------------------------------------------------------------------------- +class SelectDrawingTool(DrawingTool): + """Represents the tool for selecting things""" + + def __init__(self): + self.curHandle = None + self.curObject = None + self.objModified = False + self.startPt = None + self.curPt = None + + def getDefaultCursor(self): + """Return the cursor to use by default which this drawing tool is selected""" + return wx.STANDARD_CURSOR + + def draw(self, dc): + if self._doingRectSelection(): dc.SetPen(wx.BLACK_DASHED_PEN) + dc.SetBrush(wx.TRANSPARENT_BRUSH) + x = [self.startPt.x, self.curPt.x]; x.sort() + y = [self.startPt.y, self.curPt.y]; y.sort() + dc.DrawRectangle(x[0],y[0], x[1]-x[0],y[1]-y[0]) + + + def onMouseEvent(self,parent, event): + handlers = { wx.EVT_LEFT_DOWN.evtType[0]: self.onMouseLeftDown, + wx.EVT_MOTION.evtType[0]: self.onMouseMotion, + wx.EVT_LEFT_UP.evtType[0]: self.onMouseLeftUp, + wx.EVT_LEFT_DCLICK.evtType[0]: self.onMouseLeftDClick } + handler = handlers.get(event.GetEventType()) + if handler is not None: + return handler(parent,event) else: - dc.SetPen(wx.BLACK_PEN) - dc.SetBrush(wx.TRANSPARENT_BRUSH) - dc.SetLogicalFunction(wx.INVERT) + event.Skip() + return False + + def onMouseLeftDown(self,parent,event): + mousePt = wx.Point(event.X,event.Y) + obj, handle = parent.getObjectAndSelectionHandleAt(mousePt) + self.startPt = mousePt + self.curPt = mousePt + if obj is not None and handle is not None: + self.curObject = obj + self.curHandle = handle + else: + self.curObject = None + self.curHandle = None + + obj = parent.getObjectAt(mousePt) + if self.curObject is None and obj is not None: + self.curObject = obj + self.dragDelta = obj.position-mousePt + self.curHandle = None + parent.select(obj, event.ShiftDown()) + + return True + + def onMouseMotion(self,parent,event): + if not event.LeftIsDown(): return + + self.curPt = wx.Point(event.X,event.Y) + + obj,handle = self.curObject,self.curHandle + if self._doingDragHandle(): + self._prepareToModify(parent) + obj.moveHandle(handle,event.X,event.Y) + parent.requestRedraw() + + elif self._doingDragObject(): + self._prepareToModify(parent) + obj.position = self.curPt + self.dragDelta + parent.requestRedraw() + + elif self._doingRectSelection(): + parent.requestRedraw() + + return True + + def onMouseLeftUp(self,parent,event): + + obj,handle = self.curObject,self.curHandle + if self._doingDragHandle(): + obj.moveHandle(handle,event.X,event.Y) + obj.finalizeHandle(handle,event.X,event.Y) + + elif self._doingDragObject(): + curPt = wx.Point(event.X,event.Y) + obj.position = curPt + self.dragDelta + + elif self._doingRectSelection(): + x = [event.X, self.startPt.x] + y = [event.Y, self.startPt.y] + x.sort() + y.sort() + parent.selectByRectangle(x[0],y[0],x[1]-x[0],y[1]-y[0]) + + + self.curObject = None + self.curHandle = None + self.curPt = None + self.startPt = None + self.objModified = False + parent.requestRedraw() + + return True + + def onMouseLeftDClick(self,parent,event): + event.Skip() + mousePt = wx.Point(event.X,event.Y) + obj = parent.getObjectAt(mousePt) + if obj and obj.hasPropertyEditor(): + if obj.doPropertyEdit(parent): + parent.requestRedraw() + return True + + return False + + + def _prepareToModify(self,parent): + if not self.objModified: + parent.saveUndoInfo() + self.objModified = True + + def _doingRectSelection(self): + return self.curObject is None \ + and self.startPt is not None \ + and self.curPt is not None + + def _doingDragObject(self): + return self.curObject is not None and self.curHandle is None + + def _doingDragHandle(self): + return self.curObject is not None and self.curHandle is not None + + + +#---------------------------------------------------------------------------- +class LineDrawingTool(DrawingTool): + """Represents the tool for drawing lines""" + + def __init__(self): + self.newObject = None + self.startPt = None + + + def getDefaultCursor(self): + """Return the cursor to use by default which this drawing tool is selected""" + return wx.StockCursor(wx.CURSOR_PENCIL) + + def draw(self, dc): + if self.newObject is None: return + self.newObject.draw(dc,True) + + def onMouseEvent(self,parent, event): + handlers = { wx.EVT_LEFT_DOWN.evtType[0]: self.onMouseLeftDown, + wx.EVT_MOTION.evtType[0]: self.onMouseMotion, + wx.EVT_LEFT_UP.evtType[0]: self.onMouseLeftUp } + handler = handlers.get(event.GetEventType()) + if handler is not None: + return handler(parent,event) + else: + event.Skip() + return False + + def onMouseLeftDown(self,parent, event): + self.startPt = wx.Point(event.GetX(), event.GetY()) + self.newObject = None + event.Skip() + return True + + def onMouseMotion(self,parent, event): + if not event.Dragging(): return + + if self.newObject is None: + obj = LineDrawingObject(startPt=wx.Point(0,0), + penColour=parent.penColour, + fillColour=parent.fillColour, + lineSize=parent.lineSize, + position=wx.Point(event.X,event.Y)) + self.newObject = obj + + self._updateObjFromEvent(self.newObject, event) + + parent.requestRedraw() + event.Skip() + return True + + def onMouseLeftUp(self,parent, event): + + if self.newObject is None: + return + + self._updateObjFromEvent(self.newObject,event) + + parent.addObject(self.newObject) + + self.newObject = None + self.startPt = None + + event.Skip() + return True + + + def _updateObjFromEvent(self,obj,event): + obj.setEndPt(wx.Point(event.X,event.Y)) + + +#---------------------------------------------------------------------------- +class RectDrawingTool(DrawingTool): + """Represents the tool for drawing rectangles""" + + def __init__(self): + self.newObject = None + + def getDefaultCursor(self): + """Return the cursor to use by default which this drawing tool is selected""" + return wx.CROSS_CURSOR + + def draw(self, dc): + if self.newObject is None: return + self.newObject.draw(dc,True) + + + def onMouseEvent(self,parent, event): + handlers = { wx.EVT_LEFT_DOWN.evtType[0]: self.onMouseLeftDown, + wx.EVT_MOTION.evtType[0]: self.onMouseMotion, + wx.EVT_LEFT_UP.evtType[0]: self.onMouseLeftUp } + handler = handlers.get(event.GetEventType()) + if handler is not None: + return handler(parent,event) + else: + event.Skip() + return False + + def onMouseLeftDown(self,parent, event): + self.startPt = wx.Point(event.GetX(), event.GetY()) + self.newObject = None + event.Skip() + return True + + def onMouseMotion(self,parent, event): + if not event.Dragging(): return + + if self.newObject is None: + obj = RectDrawingObject(penColour=parent.penColour, + fillColour=parent.fillColour, + lineSize=parent.lineSize) + self.newObject = obj + + self._updateObjFromEvent(self.newObject, event) + + parent.requestRedraw() + event.Skip() + return True + + def onMouseLeftUp(self,parent, event): + + if self.newObject is None: + return + + self._updateObjFromEvent(self.newObject,event) + + parent.addObject(self.newObject) + + self.newObject = None + + event.Skip() + return True + + + def _updateObjFromEvent(self,obj,event): + x = [event.X, self.startPt.x] + y = [event.Y, self.startPt.y] + x.sort() + y.sort() + width = x[1]-x[0] + height = y[1]-y[0] + + obj.setPosition(wx.Point(x[0],y[0])) + obj.setSize(wx.Size(width,height)) + + + + +#---------------------------------------------------------------------------- +class EllipseDrawingTool(DrawingTool): + """Represents the tool for drawing ellipses""" + + def getDefaultCursor(self): + """Return the cursor to use by default which this drawing tool is selected""" + return wx.CROSS_CURSOR + + + def __init__(self): + self.newObject = None + + def getDefaultCursor(self): + """Return the cursor to use by default which this drawing tool is selected""" + return wx.CROSS_CURSOR + + def draw(self, dc): + if self.newObject is None: return + self.newObject.draw(dc,True) + + + def onMouseEvent(self,parent, event): + handlers = { wx.EVT_LEFT_DOWN.evtType[0]: self.onMouseLeftDown, + wx.EVT_MOTION.evtType[0]: self.onMouseMotion, + wx.EVT_LEFT_UP.evtType[0]: self.onMouseLeftUp } + handler = handlers.get(event.GetEventType()) + if handler is not None: + return handler(parent,event) + else: + event.Skip() + return False + + def onMouseLeftDown(self,parent, event): + self.startPt = wx.Point(event.GetX(), event.GetY()) + self.newObject = None + event.Skip() + return True + + def onMouseMotion(self,parent, event): + if not event.Dragging(): return + + if self.newObject is None: + obj = EllipseDrawingObject(penColour=parent.penColour, + fillColour=parent.fillColour, + lineSize=parent.lineSize) + self.newObject = obj + + self._updateObjFromEvent(self.newObject, event) + + parent.requestRedraw() + event.Skip() + return True + + def onMouseLeftUp(self,parent, event): + + if self.newObject is None: + return + + self._updateObjFromEvent(self.newObject,event) + + parent.addObject(self.newObject) + + self.newObject = None + + event.Skip() + return True + + + def _updateObjFromEvent(self,obj,event): + x = [event.X, self.startPt.x] + y = [event.Y, self.startPt.y] + x.sort() + y.sort() + width = x[1]-x[0] + height = y[1]-y[0] + + obj.setPosition(wx.Point(x[0],y[0])) + obj.setSize(wx.Size(width,height)) + + +#---------------------------------------------------------------------------- +class PolygonDrawingTool(DrawingTool): + """Represents the tool for drawing polygons""" + + def __init__(self): + self.newObject = None + + def getDefaultCursor(self): + """Return the cursor to use by default which this drawing tool is selected""" + return wx.CROSS_CURSOR + + + def draw(self, dc): + if self.newObject is None: return + self.newObject.draw(dc,True) + + + def onMouseEvent(self,parent, event): + handlers = { wx.EVT_LEFT_DOWN.evtType[0]: self.onMouseLeftDown, + wx.EVT_MOTION.evtType[0]: self.onMouseMotion, + wx.EVT_LEFT_UP.evtType[0]: self.onMouseLeftUp, + wx.EVT_LEFT_DCLICK.evtType[0]:self.onMouseLeftDClick } + handler = handlers.get(event.GetEventType()) + if handler is not None: + return handler(parent,event) + else: + event.Skip() + return False + + def onMouseLeftDown(self,parent, event): + event.Skip() + self.startPt = (event.GetX(), event.GetY()) + if self.newObject is None: + obj = PolygonDrawingObject(points=[(0,0)],penColour=parent.penColour, + fillColour=parent.fillColour, + lineSize=parent.lineSize, + position=wx.Point(event.X, event.Y)) + obj.addPoint(event.X,event.Y) + self.newObject = obj + else: + CLOSE_THRESH=3 + pt0 = self.newObject.getPoint(0) + if abs(pt0[0]-event.X) self.position.x + self.size.x: return False + if y < self.position.y: return False + if y > self.position.y + self.size.y: return False + + # Now things get tricky. There's no straightforward way of + # knowing whether the point is within an arbitrary object's + # bounds...to get around this, we draw the object into a + # memory-based bitmap and see if the given point was drawn. + # This could no doubt be done more efficiently by some tricky + # maths, but this approach works and is simple enough. + + # Subclasses can implement smarter faster versions of this. + + bitmap = wx.EmptyBitmap(self.size.x + 10, self.size.y + 10) + dc = wx.MemoryDC() + dc.SelectObject(bitmap) + dc.BeginDrawing() + dc.SetBackground(wx.WHITE_BRUSH) + dc.Clear() + dc.SetPen(wx.Pen(wx.BLACK, self.lineSize + 5, wx.SOLID)) + dc.SetBrush(wx.BLACK_BRUSH) + self._privateDraw(dc, wx.Point(5, 5), True) + dc.EndDrawing() + pixel = dc.GetPixel(x - self.position.x + 5, y - self.position.y + 5) + if (pixel.Red() == 0) and (pixel.Green() == 0) and (pixel.Blue() == 0): + return True + else: + return False + + handle_TOP = 0 + handle_BOTTOM = 1 + handle_LEFT = 0 + handle_RIGHT = 1 + + def getSelectionHandleContainingPoint(self, x, y): + """ Return the selection handle containing the given point, if any. + + We return one of the predefined selection handle ID codes. + """ + # Default implementation assumes selection handles at all four bbox corners. + # Return a list so we can modify the contents later in moveHandle() + if self._pointInSelRect(x, y, self.position.x, self.position.y): + return [self.handle_TOP, self.handle_LEFT] + elif self._pointInSelRect(x, y, self.position.x + self.size.width, + self.position.y): + return [self.handle_TOP, self.handle_RIGHT] + elif self._pointInSelRect(x, y, self.position.x, + self.position.y + self.size.height): + return [self.handle_BOTTOM, self.handle_LEFT] + elif self._pointInSelRect(x, y, self.position.x + self.size.width, + self.position.y + self.size.height): + return [self.handle_BOTTOM, self.handle_RIGHT] + else: + return None + + def moveHandle(self, handle, x, y): + """ Move the specified selection handle to given canvas location. + """ + assert handle is not None + + # Default implementation assumes selection handles at all four bbox corners. + pt = wx.Point(x,y) + x,y = self.position + w,h = self.size + if handle[0] == self.handle_TOP: + if handle[1] == self.handle_LEFT: + dpos = pt - self.position + self.position = pt + self.size.width -= dpos.x + self.size.height -= dpos.y + else: + dx = pt.x - ( x + w ) + dy = pt.y - ( y ) + self.position.y = pt.y + self.size.width += dx + self.size.height -= dy + else: # BOTTOM + if handle[1] == self.handle_LEFT: + dx = pt.x - ( x ) + dy = pt.y - ( y + h ) + self.position.x = pt.x + self.size.width -= dx + self.size.height += dy + else: + dpos = pt - self.position + dpos.x -= w + dpos.y -= h + self.size.width += dpos.x + self.size.height += dpos.y + + + # Finally, normalize so no negative widths or heights. + # And update the handle variable accordingly. + if self.size.height<0: + self.position.y += self.size.height + self.size.height = -self.size.height + handle[0] = 1-handle[0] + + if self.size.width<0: + self.position.x += self.size.width + self.size.width = -self.size.width + handle[1] = 1-handle[1] + + + + def finalizeHandle(self, handle, x, y): + pass + + + def objectWithinRect(self, x, y, width, height): + """ Return True iff this object falls completely within the given rect. + """ + if x > self.position.x: return False + if x + width < self.position.x + self.size.width: return False + if y > self.position.y: return False + if y + height < self.position.y + self.size.height: return False + return True + + # ===================== + # == Private Methods == + # ===================== + + def _privateDraw(self, dc, position, selected): + """ Private routine to draw this DrawingObject. + + 'dc' is the device context to use for drawing, while 'position' is + the position in which to draw the object. + """ + pass + + def _drawSelHandle(self, dc, x, y): + """ Draw a selection handle around this DrawingObject. + + 'dc' is the device context to draw the selection handle within, + while 'x' and 'y' are the coordinates to use for the centre of the + selection handle. + """ + dc.DrawRectangle(x - 3, y - 3, 6, 6) + + + def _pointInSelRect(self, x, y, rX, rY): + """ Return True iff (x, y) is within the selection handle at (rX, ry). + """ + if x < rX - 3: return False + elif x > rX + 3: return False + elif y < rY - 3: return False + elif y > rY + 3: return False + else: return True + + +#---------------------------------------------------------------------------- +class LineDrawingObject(DrawingObject): + """ DrawingObject subclass that represents one line segment. + + Adds the following members to the base DrawingObject: + 'startPt' The point, relative to the object's position, where + the line starts. + 'endPt' The point, relative to the object's position, where + the line ends. + """ + + def __init__(self, startPt=wx.Point(0,0), endPt=wx.Point(0,0), *varg, **kwarg): + DrawingObject.__init__(self, *varg, **kwarg) + + self.startPt = wx.Point(startPt.x,startPt.y) + self.endPt = wx.Point(endPt.x,endPt.y) + + # ============================ + # == Object Drawing Methods == + # ============================ + + def drawHandles(self, dc): + """Draw selection handles for this DrawingObject""" + + dc.SetPen(wx.BLACK_PEN) + dc.SetBrush(wx.BLACK_BRUSH) + + x,y = self.position + # Draw selection handles at the start and end points. + self._drawSelHandle(dc, x + self.startPt.x, y + self.startPt.y) + self._drawSelHandle(dc, x + self.endPt.x, y + self.endPt.y) + + + + # ======================= + # == Selection Methods == + # ======================= + + + handle_START_POINT = 1 + handle_END_POINT = 2 + + def getSelectionHandleContainingPoint(self, x, y): + """ Return the selection handle containing the given point, if any. + + We return one of the predefined selection handle ID codes. + """ + # We have selection handles at the start and end points. + if self._pointInSelRect(x, y, self.position.x + self.startPt.x, + self.position.y + self.startPt.y): + return self.handle_START_POINT + elif self._pointInSelRect(x, y, self.position.x + self.endPt.x, + self.position.y + self.endPt.y): + return self.handle_END_POINT + else: + return None + + def moveHandle(self, handle, x, y): + """Move the handle to specified handle to the specified canvas coordinates + """ + ptTrans = wx.Point(x-self.position.x, y-self.position.y) + if handle == self.handle_START_POINT: + self.startPt = ptTrans + elif handle == self.handle_END_POINT: + self.endPt = ptTrans + else: + raise ValueError("Bad handle type for a line") + + self._updateBoundingBox() + + # ============================= + # == Object Property Methods == + # ============================= + + def getData(self): + """ Return a copy of the object's internal data. + + This is used to save this DrawingObject to disk. + """ + # get the basics + data = DrawingObject.getData(self) + # add our specifics + data += [self.startPt.x, self.startPt.y, + self.endPt.x, self.endPt.y] + return data + + def setData(self, data): + """ Set the object's internal data. + + 'data' is a copy of the object's saved data, as returned by + getData() above. This is used to restore a previously saved + DrawingObject. + """ + #data = copy.deepcopy(data) # Needed? + + d = DrawingObject.setData(self, data) + + try: + self.startPt = wx.Point(d.next(), d.next()) + self.endPt = wx.Point(d.next(), d.next()) + except StopIteration: + raise ValueError('Not enough data in setData call') + + return d + + + def setStartPt(self, startPt): + """ Set the starting point for this line DrawingObject. + """ + self.startPt = startPt - self.position + self._updateBoundingBox() + + + def getStartPt(self): + """ Return the starting point for this line DrawingObject. + """ + return self.startPt + self.position + + + def setEndPt(self, endPt): + """ Set the ending point for this line DrawingObject. + """ + self.endPt = endPt - self.position + self._updateBoundingBox() + + + def getEndPt(self): + """ Return the ending point for this line DrawingObject. + """ + return self.endPt + self.position + + + # ===================== + # == Private Methods == + # ===================== + + + def _privateDraw(self, dc, position, selected): + """ Private routine to draw this DrawingObject. + + 'dc' is the device context to use for drawing, while 'position' is + the position in which to draw the object. If 'selected' is True, + the object is drawn with selection handles. This private drawing + routine assumes that the pen and brush have already been set by the + caller. + """ + dc.DrawLine(position.x + self.startPt.x, + position.y + self.startPt.y, + position.x + self.endPt.x, + position.y + self.endPt.y) + + def _updateBoundingBox(self): + x = [self.startPt.x, self.endPt.x]; x.sort() + y = [self.startPt.y, self.endPt.y]; y.sort() + + dp = wx.Point(-x[0],-y[0]) + self.position.x += x[0] + self.position.y += y[0] + self.size.width = x[1]-x[0] + self.size.height = y[1]-y[0] + + self.startPt += dp + self.endPt += dp + +#---------------------------------------------------------------------------- +class PolygonDrawingObject(DrawingObject): + """ DrawingObject subclass that represents a poly-line or polygon + """ + def __init__(self, points=[], *varg, **kwarg): + DrawingObject.__init__(self, *varg, **kwarg) + self.points = list(points) + + # ======================= + # == Selection Methods == + # ======================= + + def getSelectionHandleContainingPoint(self, x, y): + """ Return the selection handle containing the given point, if any. + + We return one of the predefined selection handle ID codes. + """ + # We have selection handles at the start and end points. + for i,p in enumerate(self.points): + if self._pointInSelRect(x, y, + self.position.x + p[0], + self.position.y + p[1]): + return i+1 + + return None + + + def addPoint(self, x,y): + self.points.append((x-self.position.x,y-self.position.y)) + self._updateBoundingBox() + + def getPoint(self, idx): + x,y = self.points[idx] + return (x+self.position.x,y+self.position.y) + + def movePoint(self, idx, x,y): + self.points[idx] = (x-self.position.x,y-self.position.y) + self._updateBoundingBox() + + def popPoint(self, idx=-1): + self.points.pop(idx) + self._updateBoundingBox() + + # ===================== + # == Drawing Methods == + # ===================== + + def drawHandles(self, dc): + """Draw selection handles for this DrawingObject""" + + dc.SetPen(wx.BLACK_PEN) + dc.SetBrush(wx.BLACK_BRUSH) + + x,y = self.position + # Draw selection handles at the start and end points. + for p in self.points: + self._drawSelHandle(dc, x + p[0], y + p[1]) + + def moveHandle(self, handle, x, y): + """Move the specified handle""" + self.movePoint(handle-1,x,y) + + + # ============================= + # == Object Property Methods == + # ============================= + + def getData(self): + """ Return a copy of the object's internal data. + + This is used to save this DrawingObject to disk. + """ + # get the basics + data = DrawingObject.getData(self) + # add our specifics + data += [list(self.points)] + + return data + + + def setData(self, data): + """ Set the object's internal data. + + 'data' is a copy of the object's saved data, as returned by + getData() above. This is used to restore a previously saved + DrawingObject. + """ + #data = copy.deepcopy(data) # Needed? + d = DrawingObject.setData(self, data) + + try: + self.points = d.next() + except StopIteration: + raise ValueError('Not enough data in setData call') + + return d + + + # ===================== + # == Private Methods == + # ===================== + def _privateDraw(self, dc, position, selected): + """ Private routine to draw this DrawingObject. + + 'dc' is the device context to use for drawing, while 'position' is + the position in which to draw the object. If 'selected' is True, + the object is drawn with selection handles. This private drawing + routine assumes that the pen and brush have already been set by the + caller. + """ + dc.DrawPolygon(self.points, position.x, position.y) + + def _updateBoundingBox(self): + x = min([p[0] for p in self.points]) + y = min([p[1] for p in self.points]) + x2 = max([p[0] for p in self.points]) + y2 = max([p[1] for p in self.points]) + dx = -x + dy = -y + self.position.x += x + self.position.y += y + self.size.width = x2-x + self.size.height = y2-y + # update coords also because they're relative to self.position + for i,p in enumerate(self.points): + self.points[i] = (p[0]+dx,p[1]+dy) + + +#---------------------------------------------------------------------------- +class ScribbleDrawingObject(DrawingObject): + """ DrawingObject subclass that represents a poly-line or polygon + """ + def __init__(self, points=[], *varg, **kwarg): + DrawingObject.__init__(self, *varg, **kwarg) + self.points = list(points) + + # ======================= + # == Selection Methods == + # ======================= + + def addPoint(self, x,y): + self.points.append((x-self.position.x,y-self.position.y)) + self._updateBoundingBox() + + def getPoint(self, idx): + x,y = self.points[idx] + return (x+self.position.x,y+self.position.y) + + def movePoint(self, idx, x,y): + self.points[idx] = (x-self.position.x,y-self.position.y) + self._updateBoundingBox() + + def popPoint(self, idx=-1): + self.points.pop(idx) + self._updateBoundingBox() + + + # ============================= + # == Object Property Methods == + # ============================= + + def getData(self): + """ Return a copy of the object's internal data. + + This is used to save this DrawingObject to disk. + """ + # get the basics + data = DrawingObject.getData(self) + # add our specifics + data += [list(self.points)] + + return data + + + def setData(self, data): + """ Set the object's internal data. + + 'data' is a copy of the object's saved data, as returned by + getData() above. This is used to restore a previously saved + DrawingObject. + """ + #data = copy.deepcopy(data) # Needed? + d = DrawingObject.setData(self, data) + + try: + self.points = d.next() + except StopIteration: + raise ValueError('Not enough data in setData call') + + return d + + + # ===================== + # == Private Methods == + # ===================== + def _privateDraw(self, dc, position, selected): + """ Private routine to draw this DrawingObject. + + 'dc' is the device context to use for drawing, while 'position' is + the position in which to draw the object. If 'selected' is True, + the object is drawn with selection handles. This private drawing + routine assumes that the pen and brush have already been set by the + caller. + """ + dc.SetBrush(wx.TRANSPARENT_BRUSH) + dc.DrawLines(self.points, position.x, position.y) + + def _updateBoundingBox(self): + x = min([p[0] for p in self.points]) + y = min([p[1] for p in self.points]) + x2 = max([p[0] for p in self.points]) + y2 = max([p[1] for p in self.points]) + dx = -x + dy = -y + self.position = wx.Point(self.position.x + x,self.position.y + y) + self.size = wx.Size(x2-x, y2-y) + #self.position.x += x + #self.position.y += y + #self.size.width = x2-x + #self.size.height = y2-y + # update coords also because they're relative to self.position + for i,p in enumerate(self.points): + self.points[i] = (p[0]+dx,p[1]+dy) + +#---------------------------------------------------------------------------- +class RectDrawingObject(DrawingObject): + """ DrawingObject subclass that represents an axis-aligned rectangle. + """ + def __init__(self, *varg, **kwarg): + DrawingObject.__init__(self, *varg, **kwarg) + + def objectContainsPoint(self, x, y): + """ Returns True iff this object contains the given point. + + This is used to determine if the user clicked on the object. + """ + # Firstly, ignore any points outside of the object's bounds. + + if x < self.position.x: return False + if x > self.position.x + self.size.x: return False + if y < self.position.y: return False + if y > self.position.y + self.size.y: return False + + # Rectangles are easy -- they're always selected if the + # point is within their bounds. + return True + + # ===================== + # == Private Methods == + # ===================== + def _privateDraw(self, dc, position, selected): + """ Private routine to draw this DrawingObject. - def getType(self): - """ Return this DrawingObject's type. + 'dc' is the device context to use for drawing, while 'position' is + the position in which to draw the object. If 'selected' is True, + the object is drawn with selection handles. This private drawing + routine assumes that the pen and brush have already been set by the + caller. """ - return self.type + dc.DrawRectangle(position.x, position.y, + self.size.width, self.size.height) - def setPosition(self, position): - """ Set the origin (top-left corner) for this DrawingObject. - """ - self.position = position +#---------------------------------------------------------------------------- +class EllipseDrawingObject(DrawingObject): + """ DrawingObject subclass that represents an axis-aligned ellipse. + """ + def __init__(self, *varg, **kwarg): + DrawingObject.__init__(self, *varg, **kwarg) + # ===================== + # == Private Methods == + # ===================== + def _privateDraw(self, dc, position, selected): + """ Private routine to draw this DrawingObject. - def getPosition(self): - """ Return this DrawingObject's position. + 'dc' is the device context to use for drawing, while 'position' is + the position in which to draw the object. If 'selected' is True, + the object is drawn with selection handles. This private drawing + routine assumes that the pen and brush have already been set by the + caller. """ - return self.position + dc.DrawEllipse(position.x, position.y, + self.size.width, self.size.height) - def setSize(self, size): - """ Set the size for this DrawingObject. - """ - self.size = size - - def getSize(self): - """ Return this DrawingObject's size. - """ - return self.size +#---------------------------------------------------------------------------- +class TextDrawingObject(DrawingObject): + """ DrawingObject subclass that holds text. - def setPenColour(self, colour): - """ Set the pen colour used for this DrawingObject. - """ - self.penColour = colour + Adds the following members to the base DrawingObject: + 'text' The object's text (obj_TEXT objects only). + 'textFont' The text object's font name. + """ + def __init__(self, text=None, *varg, **kwarg): + DrawingObject.__init__(self, *varg, **kwarg) - def getPenColour(self): - """ Return this DrawingObject's pen colour. - """ - return self.penColour + self.text = text + self.textFont = wx.SystemSettings_GetFont(wx.SYS_DEFAULT_GUI_FONT) - def setFillColour(self, colour): - """ Set the fill colour used for this DrawingObject. - """ - self.fillColour = colour + # ============================= + # == Object Property Methods == + # ============================= + def getData(self): + """ Return a copy of the object's internal data. - def getFillColour(self): - """ Return this DrawingObject's fill colour. + This is used to save this DrawingObject to disk. """ - return self.fillColour + # get the basics + data = DrawingObject.getData(self) + # add our specifics + data += [self.text, self.textFont.GetNativeFontInfoDesc()] + return data - def setLineSize(self, lineSize): - """ Set the linesize used for this DrawingObject. - """ - self.lineSize = lineSize + def setData(self, data): + """ Set the object's internal data. - def getLineSize(self): - """ Return this DrawingObject's line size. + 'data' is a copy of the object's saved data, as returned by + getData() above. This is used to restore a previously saved + DrawingObject. """ - return self.lineSize - + d = DrawingObject.setData(self, data) - def setStartPt(self, startPt): - """ Set the starting point for this line DrawingObject. - """ - self.startPt = startPt + try: + self.text = d.next() + desc = d.next() + self.textFont = wx.FontFromNativeInfoString(desc) + except StopIteration: + raise ValueError('Not enough data in setData call') + return d + - def getStartPt(self): - """ Return the starting point for this line DrawingObject. - """ - return self.startPt + def hasPropertyEditor(self): + return True + def doPropertyEdit(self, parent): + editor = parent.getTextEditor() + editor.SetTitle("Edit Text Object") + editor.objectToDialog(self) + if editor.ShowModal() == wx.ID_CANCEL: + editor.Hide() + return False - def setEndPt(self, endPt): - """ Set the ending point for this line DrawingObject. - """ - self.endPt = endPt + parent.saveUndoInfo() + editor.dialogToObject(self) + editor.Hide() - def getEndPt(self): - """ Return the ending point for this line DrawingObject. - """ - return self.endPt + return True def setText(self, text): @@ -1965,64 +3052,18 @@ class DrawingObject: return self.text - def setTextFont(self, font): - """ Set the typeface for this text DrawingObject. + def setFont(self, font): + """ Set the font for this text DrawingObject. """ self.textFont = font - def getTextFont(self): - """ Return this text DrawingObject's typeface. + def getFont(self): + """ Return this text DrawingObject's font. """ return self.textFont - def setTextSize(self, size): - """ Set the point size for this text DrawingObject. - """ - self.textSize = size - - - def getTextSize(self): - """ Return this text DrawingObject's text size. - """ - return self.textSize - - - def setTextBoldface(self, boldface): - """ Set the boldface flag for this text DrawingObject. - """ - self.textBoldface = boldface - - - def getTextBoldface(self): - """ Return this text DrawingObject's boldface flag. - """ - return self.textBoldface - - - def setTextItalic(self, italic): - """ Set the italic flag for this text DrawingObject. - """ - self.textItalic = italic - - - def getTextItalic(self): - """ Return this text DrawingObject's italic flag. - """ - return self.textItalic - - - def setTextUnderline(self, underline): - """ Set the underling flag for this text DrawingObject. - """ - self.textUnderline = underline - - - def getTextUnderline(self): - """ Return this text DrawingObject's underline flag. - """ - return self.textUnderline # ============================ # == Object Drawing Methods == @@ -2034,22 +3075,11 @@ class DrawingObject: 'dc' is the device context to use for drawing. If 'selected' is True, the object is currently selected and should be drawn as such. """ - if self.type != obj_TEXT: - if self.lineSize == 0: - dc.SetPen(wx.Pen(self.penColour, self.lineSize, wx.TRANSPARENT)) - else: - dc.SetPen(wx.Pen(self.penColour, self.lineSize, wx.SOLID)) - dc.SetBrush(wx.Brush(self.fillColour, wx.SOLID)) - else: - dc.SetTextForeground(self.penColour) - dc.SetTextBackground(self.fillColour) + dc.SetTextForeground(self.penColour) + dc.SetTextBackground(self.fillColour) self._privateDraw(dc, self.position, selected) - # ======================= - # == Selection Methods == - # ======================= - def objectContainsPoint(self, x, y): """ Returns True iff this object contains the given point. @@ -2062,93 +3092,17 @@ class DrawingObject: if y < self.position.y: return False if y > self.position.y + self.size.y: return False - if self.type in [obj_RECT, obj_TEXT]: - # Rectangles and text are easy -- they're always selected if the - # point is within their bounds. - return True - - # Now things get tricky. There's no straightforward way of knowing - # whether the point is within the object's bounds...to get around this, - # we draw the object into a memory-based bitmap and see if the given - # point was drawn. This could no doubt be done more efficiently by - # some tricky maths, but this approach works and is simple enough. - - bitmap = wx.EmptyBitmap(self.size.x + 10, self.size.y + 10) - dc = wx.MemoryDC() - dc.SelectObject(bitmap) - dc.BeginDrawing() - dc.SetBackground(wx.WHITE_BRUSH) - dc.Clear() - dc.SetPen(wx.Pen(wx.BLACK, self.lineSize + 5, wx.SOLID)) - dc.SetBrush(wx.BLACK_BRUSH) - self._privateDraw(dc, wx.Point(5, 5), True) - dc.EndDrawing() - pixel = dc.GetPixel(x - self.position.x + 5, y - self.position.y + 5) - if (pixel.Red() == 0) and (pixel.Green() == 0) and (pixel.Blue() == 0): - return True - else: - return False - - - def getSelectionHandleContainingPoint(self, x, y): - """ Return the selection handle containing the given point, if any. - - We return one of the predefined selection handle ID codes. - """ - if self.type == obj_LINE: - # We have selection handles at the start and end points. - if self._pointInSelRect(x, y, self.position.x + self.startPt.x, - self.position.y + self.startPt.y): - return handle_START_POINT - elif self._pointInSelRect(x, y, self.position.x + self.endPt.x, - self.position.y + self.endPt.y): - return handle_END_POINT - else: - return handle_NONE - else: - # We have selection handles at all four corners. - if self._pointInSelRect(x, y, self.position.x, self.position.y): - return handle_TOP_LEFT - elif self._pointInSelRect(x, y, self.position.x + self.size.width, - self.position.y): - return handle_TOP_RIGHT - elif self._pointInSelRect(x, y, self.position.x, - self.position.y + self.size.height): - return handle_BOTTOM_LEFT - elif self._pointInSelRect(x, y, self.position.x + self.size.width, - self.position.y + self.size.height): - return handle_BOTTOM_RIGHT - else: - return handle_NONE - - - def objectWithinRect(self, x, y, width, height): - """ Return True iff this object falls completely within the given rect. - """ - if x > self.position.x: return False - if x + width < self.position.x + self.size.width: return False - if y > self.position.y: return False - if y + height < self.position.y + self.size.height: return False + # Text is easy -- it's always selected if the + # point is within its bounds. return True - # ===================== - # == Utility Methods == - # ===================== def fitToText(self): """ Resize a text DrawingObject so that it fits it's text exactly. """ - if self.type != obj_TEXT: return - - if self.textBoldface: weight = wx.BOLD - else: weight = wx.NORMAL - if self.textItalic: style = wx.ITALIC - else: style = wx.NORMAL - font = wx.Font(self.textSize, wx.DEFAULT, style, weight, - self.textUnderline, self.textFont) dummyWindow = wx.Frame(None, -1, "") - dummyWindow.SetFont(font) + dummyWindow.SetFont(self.textFont) width, height = dummyWindow.GetTextExtent(self.text) dummyWindow.Destroy() @@ -2167,70 +3121,46 @@ class DrawingObject: routine assumes that the pen and brush have already been set by the caller. """ - if self.type == obj_LINE: - dc.DrawLine(position.x + self.startPt.x, - position.y + self.startPt.y, - position.x + self.endPt.x, - position.y + self.endPt.y) - elif self.type == obj_RECT: - dc.DrawRectangle(position.x, position.y, - self.size.width, self.size.height) - elif self.type == obj_ELLIPSE: - dc.DrawEllipse(position.x, position.y, - self.size.width, self.size.height) - elif self.type == obj_TEXT: - if self.textBoldface: weight = wx.BOLD - else: weight = wx.NORMAL - if self.textItalic: style = wx.ITALIC - else: style = wx.NORMAL - font = wx.Font(self.textSize, wx.DEFAULT, style, weight, - self.textUnderline, self.textFont) - dc.SetFont(font) - dc.DrawText(self.text, position.x, position.y) - - if selected: - dc.SetPen(wx.TRANSPARENT_PEN) - dc.SetBrush(wx.BLACK_BRUSH) - - if self.type == obj_LINE: - # Draw selection handles at the start and end points. - self._drawSelHandle(dc, position.x + self.startPt.x, - position.y + self.startPt.y) - self._drawSelHandle(dc, position.x + self.endPt.x, - position.y + self.endPt.y) - else: - # Draw selection handles at all four corners. - self._drawSelHandle(dc, position.x, position.y) - self._drawSelHandle(dc, position.x + self.size.width, - position.y) - self._drawSelHandle(dc, position.x, - position.y + self.size.height) - self._drawSelHandle(dc, position.x + self.size.width, - position.y + self.size.height) + dc.SetFont(self.textFont) + dc.DrawText(self.text, position.x, position.y) - def _drawSelHandle(self, dc, x, y): - """ Draw a selection handle around this DrawingObject. - 'dc' is the device context to draw the selection handle within, - while 'x' and 'y' are the coordinates to use for the centre of the - selection handle. - """ - dc.DrawRectangle(x - 3, y - 3, 6, 6) +#---------------------------------------------------------------------------- +class ToolPaletteToggleX(wx.ToggleButton): + """ An icon appearing in the tool palette area of our sketching window. + + Note that this is actually implemented as a wx.Bitmap rather + than as a wx.Icon. wx.Icon has a very specific meaning, and isn't + appropriate for this more general use. + """ + def __init__(self, parent, iconID, iconName, toolTip, mode = wx.ITEM_NORMAL): + """ Standard constructor. - def _pointInSelRect(self, x, y, rX, rY): - """ Return True iff (x, y) is within the selection handle at (rX, ry). + 'parent' is the parent window this icon will be part of. + 'iconID' is the internal ID used for this icon. + 'iconName' is the name used for this icon. + 'toolTip' is the tool tip text to show for this icon. + 'mode' is one of wx.ITEM_NORMAL, wx.ITEM_CHECK, wx.ITEM_RADIO + + The icon name is used to get the appropriate bitmap for this icon. """ - if x < rX - 3: return False - elif x > rX + 3: return False - elif y < rY - 3: return False - elif y > rY + 3: return False - else: return True + bmp = wx.Bitmap("images/" + iconName + "Icon.bmp", wx.BITMAP_TYPE_BMP) + bmpsel = wx.Bitmap("images/" + iconName + "IconSel.bmp", wx.BITMAP_TYPE_BMP) -#---------------------------------------------------------------------------- + wx.ToggleButton.__init__(self, parent, iconID, + size=(bmp.GetWidth()+1, bmp.GetHeight()+1) + ) + self.SetLabel( iconName ) + self.SetToolTip(wx.ToolTip(toolTip)) + #self.SetBitmapLabel(bmp) + #self.SetBitmapSelected(bmpsel) + + self.iconID = iconID + self.iconName = iconName -class ToolPaletteIcon(GenBitmapButton): +class ToolPaletteToggle(GenBitmapToggleButton): """ An icon appearing in the tool palette area of our sketching window. Note that this is actually implemented as a wx.Bitmap rather @@ -2238,50 +3168,61 @@ class ToolPaletteIcon(GenBitmapButton): appropriate for this more general use. """ - def __init__(self, parent, iconID, iconName, toolTip): + def __init__(self, parent, iconID, iconName, toolTip, mode = wx.ITEM_NORMAL): """ Standard constructor. 'parent' is the parent window this icon will be part of. 'iconID' is the internal ID used for this icon. 'iconName' is the name used for this icon. 'toolTip' is the tool tip text to show for this icon. + 'mode' is one of wx.ITEM_NORMAL, wx.ITEM_CHECK, wx.ITEM_RADIO The icon name is used to get the appropriate bitmap for this icon. """ bmp = wx.Bitmap("images/" + iconName + "Icon.bmp", wx.BITMAP_TYPE_BMP) - GenBitmapButton.__init__(self, parent, iconID, bmp, wx.DefaultPosition, - wx.Size(bmp.GetWidth(), bmp.GetHeight())) + bmpsel = wx.Bitmap("images/" + iconName + "IconSel.bmp", wx.BITMAP_TYPE_BMP) + + GenBitmapToggleButton.__init__(self, parent, iconID, bitmap=bmp, + size=(bmp.GetWidth()+1, bmp.GetHeight()+1), + style=wx.BORDER_NONE) + self.SetToolTip(wx.ToolTip(toolTip)) + self.SetBitmapLabel(bmp) + self.SetBitmapSelected(bmpsel) self.iconID = iconID self.iconName = iconName - self.isSelected = False - - def select(self): - """ Select the icon. - The icon's visual representation is updated appropriately. - """ - if self.isSelected: return # Nothing to do! +class ToolPaletteButton(GenBitmapButton): + """ An icon appearing in the tool palette area of our sketching window. - bmp = wx.Bitmap("images/" + self.iconName + "IconSel.bmp", - wx.BITMAP_TYPE_BMP) - self.SetBitmapLabel(bmp) - self.isSelected = True + Note that this is actually implemented as a wx.Bitmap rather + than as a wx.Icon. wx.Icon has a very specific meaning, and isn't + appropriate for this more general use. + """ + def __init__(self, parent, iconID, iconName, toolTip): + """ Standard constructor. - def deselect(self): - """ Deselect the icon. + 'parent' is the parent window this icon will be part of. + 'iconID' is the internal ID used for this icon. + 'iconName' is the name used for this icon. + 'toolTip' is the tool tip text to show for this icon. - The icon's visual representation is updated appropriately. + The icon name is used to get the appropriate bitmap for this icon. """ - if not self.isSelected: return # Nothing to do! - - bmp = wx.Bitmap("images/" + self.iconName + "Icon.bmp", - wx.BITMAP_TYPE_BMP) + bmp = wx.Bitmap("images/" + iconName + "Icon.bmp", wx.BITMAP_TYPE_BMP) + GenBitmapButton.__init__(self, parent, iconID, bitmap=bmp, + size=(bmp.GetWidth()+1, bmp.GetHeight()+1), + style=wx.BORDER_NONE) + self.SetToolTip(wx.ToolTip(toolTip)) self.SetBitmapLabel(bmp) - self.isSelected = False + + self.iconID = iconID + self.iconName = iconName + + #---------------------------------------------------------------------------- @@ -2297,7 +3238,13 @@ class ToolOptionIndicator(wx.Window): self.fillColour = wx.WHITE self.lineSize = 1 - self.Bind(wx.EVT_PAINT, self.OnPaint) + # Win95 can only handle a 8x8 stipple bitmaps max + #self.stippleBitmap = wx.BitmapFromBits("\xf0"*4 + "\x0f"*4,8,8) + # ...but who uses Win95? + self.stippleBitmap = wx.BitmapFromBits("\xff\x00"*8+"\x00\xff"*8,16,16) + self.stippleBitmap.SetMask(wx.Mask(self.stippleBitmap)) + + self.Bind(wx.EVT_PAINT, self.onPaint) def setPenColour(self, penColour): @@ -2321,20 +3268,31 @@ class ToolOptionIndicator(wx.Window): self.Refresh() - def OnPaint(self, event): + def onPaint(self, event): """ Paint our tool option indicator. """ dc = wx.PaintDC(self) dc.BeginDrawing() + dc.SetPen(wx.BLACK_PEN) + bgbrush = wx.Brush(wx.WHITE, wx.STIPPLE_MASK_OPAQUE) + bgbrush.SetStipple(self.stippleBitmap) + dc.SetTextForeground(wx.LIGHT_GREY) + dc.SetTextBackground(wx.WHITE) + dc.SetBrush(bgbrush) + dc.DrawRectangle(0, 0, self.GetSize().width,self.GetSize().height) + if self.lineSize == 0: dc.SetPen(wx.Pen(self.penColour, self.lineSize, wx.TRANSPARENT)) else: dc.SetPen(wx.Pen(self.penColour, self.lineSize, wx.SOLID)) dc.SetBrush(wx.Brush(self.fillColour, wx.SOLID)) - dc.DrawRectangle(5, 5, self.GetSize().width - 10, - self.GetSize().height - 10) + size = self.GetSize() + ctrx = size.x/2 + ctry = size.y/2 + radius = min(size)//2 - 5 + dc.DrawCircle(ctrx, ctry, radius) dc.EndDrawing() @@ -2349,75 +3307,40 @@ class EditTextObjectDialog(wx.Dialog): def __init__(self, parent, title): """ Standard constructor. """ - wx.Dialog.__init__(self, parent, -1, title) + wx.Dialog.__init__(self, parent, -1, title, + style=wx.DEFAULT_DIALOG_STYLE|wx.RESIZE_BORDER) - self.textCtrl = wx.TextCtrl(self, 1001, "", style=wx.TE_PROCESS_ENTER, - validator=TextObjectValidator()) + self.textCtrl = wx.TextCtrl( + self, 1001, "Enter text here", style=wx.TE_PROCESS_ENTER|wx.TE_RICH, + validator=TextObjectValidator() + ) extent = self.textCtrl.GetFullTextExtent("Hy") lineHeight = extent[1] + extent[3] self.textCtrl.SetSize(wx.Size(-1, lineHeight * 4)) + self.curFont = self.textCtrl.GetFont() + self.curClr = wx.BLACK self.Bind(wx.EVT_TEXT_ENTER, self._doEnter, id=1001) - fonts = wx.FontEnumerator() - fonts.EnumerateFacenames() - self.fontList = fonts.GetFacenames() - self.fontList.sort() - - fontLabel = wx.StaticText(self, -1, "Font:") - self._setFontOptions(fontLabel, weight=wx.BOLD) - - self.fontCombo = wx.ComboBox(self, -1, "", wx.DefaultPosition, - wx.DefaultSize, self.fontList, - style = wx.CB_READONLY) - self.fontCombo.SetSelection(0) # Default to first available font. - - self.sizeList = ["8", "9", "10", "12", "14", "16", - "18", "20", "24", "32", "48", "72"] - - sizeLabel = wx.StaticText(self, -1, "Size:") - self._setFontOptions(sizeLabel, weight=wx.BOLD) - - self.sizeCombo = wx.ComboBox(self, -1, "", wx.DefaultPosition, - wx.DefaultSize, self.sizeList, - style=wx.CB_READONLY) - self.sizeCombo.SetSelection(3) # Default to 12 point text. + fontBtn = wx.Button(self, -1, "Select Font...") + self.Bind(wx.EVT_BUTTON, self.OnSelectFont, fontBtn) gap = wx.LEFT | wx.TOP | wx.RIGHT - comboSizer = wx.BoxSizer(wx.HORIZONTAL) - comboSizer.Add(fontLabel, 0, gap | wx.ALIGN_CENTRE_VERTICAL, 5) - comboSizer.Add(self.fontCombo, 0, gap, 5) - comboSizer.Add((5, 5)) # Spacer. - comboSizer.Add(sizeLabel, 0, gap | wx.ALIGN_CENTRE_VERTICAL, 5) - comboSizer.Add(self.sizeCombo, 0, gap, 5) - - self.boldCheckbox = wx.CheckBox(self, -1, "Bold") - self.italicCheckbox = wx.CheckBox(self, -1, "Italic") - self.underlineCheckbox = wx.CheckBox(self, -1, "Underline") + self.okButton = wx.Button(self, wx.ID_OK, "&OK") + self.okButton.SetDefault() + self.cancelButton = wx.Button(self, wx.ID_CANCEL, "&Cancel") - self._setFontOptions(self.boldCheckbox, weight=wx.BOLD) - self._setFontOptions(self.italicCheckbox, style=wx.ITALIC) - self._setFontOptions(self.underlineCheckbox, underline=True) + btnSizer = wx.StdDialogButtonSizer() - styleSizer = wx.BoxSizer(wx.HORIZONTAL) - styleSizer.Add(self.boldCheckbox, 0, gap, 5) - styleSizer.Add(self.italicCheckbox, 0, gap, 5) - styleSizer.Add(self.underlineCheckbox, 0, gap, 5) - - self.okButton = wx.Button(self, wx.ID_OK, "OK") - self.cancelButton = wx.Button(self, wx.ID_CANCEL, "Cancel") - - btnSizer = wx.BoxSizer(wx.HORIZONTAL) btnSizer.Add(self.okButton, 0, gap, 5) btnSizer.Add(self.cancelButton, 0, gap, 5) sizer = wx.BoxSizer(wx.VERTICAL) sizer.Add(self.textCtrl, 1, gap | wx.EXPAND, 5) + sizer.Add(fontBtn, 0, gap | wx.ALIGN_RIGHT, 5) sizer.Add((10, 10)) # Spacer. - sizer.Add(comboSizer, 0, gap | wx.ALIGN_CENTRE, 5) - sizer.Add(styleSizer, 0, gap | wx.ALIGN_CENTRE, 5) - sizer.Add((10, 10)) # Spacer. + btnSizer.Realize() sizer.Add(btnSizer, 0, gap | wx.ALIGN_CENTRE, 5) self.SetAutoLayout(True) @@ -2427,59 +3350,52 @@ class EditTextObjectDialog(wx.Dialog): self.textCtrl.SetFocus() + def OnSelectFont(self, evt): + """Shows the font dialog and sets the font of the sample text""" + data = wx.FontData() + data.EnableEffects(True) + data.SetColour(self.curClr) # set colour + data.SetInitialFont(self.curFont) + + dlg = wx.FontDialog(self, data) + + if dlg.ShowModal() == wx.ID_OK: + data = dlg.GetFontData() + font = data.GetChosenFont() + colour = data.GetColour() + + self.curFont = font + self.curClr = colour + + self.textCtrl.SetFont(font) + # Update dialog for the new height of the text + self.GetSizer().Fit(self) + + dlg.Destroy() + + def objectToDialog(self, obj): """ Copy the properties of the given text object into the dialog box. """ self.textCtrl.SetValue(obj.getText()) self.textCtrl.SetSelection(0, len(obj.getText())) - for i in range(len(self.fontList)): - if self.fontList[i] == obj.getTextFont(): - self.fontCombo.SetSelection(i) - break + self.curFont = obj.getFont() + self.textCtrl.SetFont(self.curFont) - for i in range(len(self.sizeList)): - if self.sizeList[i] == str(obj.getTextSize()): - self.sizeCombo.SetSelection(i) - break - - self.boldCheckbox.SetValue(obj.getTextBoldface()) - self.italicCheckbox.SetValue(obj.getTextItalic()) - self.underlineCheckbox.SetValue(obj.getTextUnderline()) def dialogToObject(self, obj): """ Copy the properties from the dialog box into the given text object. """ obj.setText(self.textCtrl.GetValue()) - obj.setTextFont(self.fontCombo.GetValue()) - obj.setTextSize(int(self.sizeCombo.GetValue())) - obj.setTextBoldface(self.boldCheckbox.GetValue()) - obj.setTextItalic(self.italicCheckbox.GetValue()) - obj.setTextUnderline(self.underlineCheckbox.GetValue()) + obj.setFont(self.curFont) obj.fitToText() # ====================== # == Private Routines == # ====================== - def _setFontOptions(self, ctrl, family=None, pointSize=-1, - style=wx.NORMAL, weight=wx.NORMAL, - underline=False): - """ Change the font settings for the given control. - - The meaning of the 'family', 'pointSize', 'style', 'weight' and - 'underline' parameters are the same as for the wx.Font constructor. - If the family and/or pointSize isn't specified, the current default - value is used. - """ - if family == None: family = ctrl.GetFont().GetFamily() - if pointSize == -1: pointSize = ctrl.GetFont().GetPointSize() - - ctrl.SetFont(wx.Font(pointSize, family, style, weight, underline)) - ctrl.SetSize(ctrl.GetBestSize()) # Adjust size to reflect font change. - - def _doEnter(self, event): """ Respond to the user hitting the ENTER key. @@ -2570,15 +3486,17 @@ class ExceptionHandler: s = self._buff + s self._buff = "" + f = open("errors.txt", "a") + f.write(s) + f.close() + if s[:9] == "Traceback": # Tell the user than an exception occurred. wx.MessageBox("An internal error has occurred.\nPlease " + \ "refer to the 'errors.txt' file for details.", "Error", wx.OK | wx.CENTRE | wx.ICON_EXCLAMATION) - f = open("errors.txt", "a") - f.write(s) - f.close() + except: pass # Don't recursively crash on errors. diff --git a/wxPython/samples/pydocview/TextEditor.py b/wxPython/samples/pydocview/TextEditor.py index 9fa41a92ca..28acf21868 100644 --- a/wxPython/samples/pydocview/TextEditor.py +++ b/wxPython/samples/pydocview/TextEditor.py @@ -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())) diff --git a/wxPython/samples/roses/clroses.py b/wxPython/samples/roses/clroses.py new file mode 100644 index 0000000000..e62c37091c --- /dev/null +++ b/wxPython/samples/roses/clroses.py @@ -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) diff --git a/wxPython/samples/roses/wxroses.py b/wxPython/samples/roses/wxroses.py new file mode 100644 index 0000000000..fd4be6e4bd --- /dev/null +++ b/wxPython/samples/roses/wxroses.py @@ -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() diff --git a/wxPython/setup.py b/wxPython/setup.py index b8a1f05f4f..d7c8adb430 100755 --- a/wxPython/setup.py +++ b/wxPython/setup.py @@ -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, diff --git a/wxPython/src/_bitmap.i b/wxPython/src/_bitmap.i index 994d5e93e8..2046df39ca 100644 --- a/wxPython/src/_bitmap.i +++ b/wxPython/src/_bitmap.i @@ -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 diff --git a/wxPython/src/_colour.i b/wxPython/src/_colour.i index 23ddd08c3c..b70b05094a 100644 --- a/wxPython/src/_colour.i +++ b/wxPython/src/_colour.i @@ -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; diff --git a/wxPython/src/_core_api.i b/wxPython/src/_core_api.i index b85f62cae2..2c40aef26b 100644 --- a/wxPython/src/_core_api.i +++ b/wxPython/src/_core_api.i @@ -242,6 +242,8 @@ static wxPyCoreAPI API = { wxRect2D_helper, wxPosition_helper, + wxPyCBOutputStream_create, + wxPyCBOutputStream_copy, }; #endif diff --git a/wxPython/src/_defs.i b/wxPython/src/_defs.i index 1eb46b0cf2..ad493d5fc7 100644 --- a/wxPython/src/_defs.i +++ b/wxPython/src/_defs.i @@ -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 + + + //--------------------------------------------------------------------------- %{ diff --git a/wxPython/src/_filesys.i b/wxPython/src/_filesys.i index fa76da3e68..953bec16cf 100644 --- a/wxPython/src/_filesys.i +++ b/wxPython/src/_filesys.i @@ -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); diff --git a/wxPython/src/_functions.i b/wxPython/src/_functions.i index baf74525ac..89d3bb7764 100644 --- a/wxPython/src/_functions.i +++ b/wxPython/src/_functions.i @@ -451,7 +451,7 @@ public: }; -MustHaveApp(wxThread); +MustHaveApp(wxThread_IsMain); %inline %{ bool wxThread_IsMain() { #ifdef WXP_WITH_THREAD diff --git a/wxPython/src/_gdicmn.i b/wxPython/src/_gdicmn.i index ac15dc4d98..ecce8edd35 100644 --- a/wxPython/src/_gdicmn.i +++ b/wxPython/src/_gdicmn.i @@ -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); diff --git a/wxPython/src/_graphics.i b/wxPython/src/_graphics.i index 8b667a7235..4ec84d7694 100644 --- a/wxPython/src/_graphics.i +++ b/wxPython/src/_graphics.i @@ -350,9 +350,6 @@ MustHaveApp(wxGraphicsPath); MustHaveApp(wxGraphicsContext); MustHaveApp(wxGCDC); -typedef double wxDouble; - - //--------------------------------------------------------------------------- diff --git a/wxPython/src/_image.i b/wxPython/src/_image.i index 3f568e5cb6..c58b04947f 100644 --- a/wxPython/src/_image.i +++ b/wxPython/src/_image.i @@ -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( diff --git a/wxPython/src/_log.i b/wxPython/src/_log.i index b9204ea80e..be961b21d1 100644 --- a/wxPython/src/_log.i +++ b/wxPython/src/_log.i @@ -214,7 +214,8 @@ public: void PassMessages(bool bDoPass); bool IsPassingMessages(); wxLog *GetOldLog(); - + void DetachOldLog(); + %property(OldLog, GetOldLog, doc="See `GetOldLog`"); }; diff --git a/wxPython/src/_menu.i b/wxPython/src/_menu.i index db3c33ce71..de7e75939e 100644 --- a/wxPython/src/_menu.i +++ b/wxPython/src/_menu.i @@ -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; diff --git a/wxPython/src/_panel.i b/wxPython/src/_panel.i index 6dc14e0f6f..783cb8fb48 100644 --- a/wxPython/src/_panel.i +++ b/wxPython/src/_panel.i @@ -1,5 +1,5 @@ ///////////////////////////////////////////////////////////////////////////// -// Name: _window.i +// Name: _panel.i // Purpose: SWIG interface for wxPanel and wxScrolledWindow // // Author: Robin Dunn diff --git a/wxPython/src/_richtextbuffer.i b/wxPython/src/_richtextbuffer.i new file mode 100644 index 0000000000..b5f69bca1f --- /dev/null +++ b/wxPython/src/_richtextbuffer.i @@ -0,0 +1,1968 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: _richtextbuffer.i +// Purpose: wxRichTextAttr +// +// Author: Robin Dunn +// +// Created: 11-April-2006 +// RCS-ID: $Id$ +// Copyright: (c) 2006 by Total Control Software +// Licence: wxWindows license +///////////////////////////////////////////////////////////////////////////// + +// Not a %module + + +//--------------------------------------------------------------------------- + +%{ +#include +#include "wx/wxPython/pyistream.h" +%} + +//--------------------------------------------------------------------------- +%newgroup + +enum { +/*! + * File types + */ + wxRICHTEXT_TYPE_ANY, + wxRICHTEXT_TYPE_TEXT, + wxRICHTEXT_TYPE_XML, + wxRICHTEXT_TYPE_HTML, + wxRICHTEXT_TYPE_RTF, + wxRICHTEXT_TYPE_PDF, + +/*! + * Flags determining the available space, passed to Layout + */ + wxRICHTEXT_FIXED_WIDTH, + wxRICHTEXT_FIXED_HEIGHT, + wxRICHTEXT_VARIABLE_WIDTH, + wxRICHTEXT_VARIABLE_HEIGHT, + + + wxRICHTEXT_LAYOUT_SPECIFIED_RECT, + wxRICHTEXT_DRAW_IGNORE_CACHE, + + +/*! + * Flags returned from hit-testing + */ + wxRICHTEXT_HITTEST_NONE, + wxRICHTEXT_HITTEST_BEFORE, + wxRICHTEXT_HITTEST_AFTER, + wxRICHTEXT_HITTEST_ON, + wxRICHTEXT_HITTEST_OUTSIDE, + +/*! + * Flags for GetRangeSize + */ + wxRICHTEXT_FORMATTED, + wxRICHTEXT_UNFORMATTED, + +/*! + * Flags for SetStyle/SetListStyle + */ + wxRICHTEXT_SETSTYLE_NONE, + wxRICHTEXT_SETSTYLE_WITH_UNDO, + wxRICHTEXT_SETSTYLE_OPTIMIZE, + wxRICHTEXT_SETSTYLE_PARAGRAPHS_ONLY, + wxRICHTEXT_SETSTYLE_CHARACTERS_ONLY, + wxRICHTEXT_SETSTYLE_RENUMBER, + wxRICHTEXT_SETSTYLE_SPECIFY_LEVEL, + wxRICHTEXT_SETSTYLE_RESET, + wxRICHTEXT_SETSTYLE_REMOVE, + +/*! + * Flags for text insertion + */ + wxRICHTEXT_INSERT_NONE, + wxRICHTEXT_INSERT_WITH_PREVIOUS_PARAGRAPH_STYLE, + + + // TODO: Rename these to be wxRICHTEXT_* ?? + + wxTEXT_ATTR_TEXT_COLOUR, + wxTEXT_ATTR_BACKGROUND_COLOUR, + wxTEXT_ATTR_FONT_FACE, + wxTEXT_ATTR_FONT_SIZE, + wxTEXT_ATTR_FONT_WEIGHT, + wxTEXT_ATTR_FONT_ITALIC, + wxTEXT_ATTR_FONT_UNDERLINE, + wxTEXT_ATTR_FONT, + wxTEXT_ATTR_ALIGNMENT, + wxTEXT_ATTR_LEFT_INDENT, + wxTEXT_ATTR_RIGHT_INDENT, + wxTEXT_ATTR_TABS, + + wxTEXT_ATTR_PARA_SPACING_AFTER, + wxTEXT_ATTR_PARA_SPACING_BEFORE, + wxTEXT_ATTR_LINE_SPACING, + wxTEXT_ATTR_CHARACTER_STYLE_NAME, + wxTEXT_ATTR_PARAGRAPH_STYLE_NAME, + wxTEXT_ATTR_BULLET_STYLE, + wxTEXT_ATTR_BULLET_NUMBER, + wxTEXT_ATTR_BULLET_TEXT, + wxTEXT_ATTR_BULLET_NAME, + wxTEXT_ATTR_URL, + wxTEXT_ATTR_PAGE_BREAK, + wxTEXT_ATTR_EFFECTS, + wxTEXT_ATTR_OUTLINE_LEVEL, + +/*! + * Styles for wxTextAttrEx::SetBulletStyle + */ + wxTEXT_ATTR_BULLET_STYLE_NONE, + wxTEXT_ATTR_BULLET_STYLE_ARABIC, + wxTEXT_ATTR_BULLET_STYLE_LETTERS_UPPER, + wxTEXT_ATTR_BULLET_STYLE_LETTERS_LOWER, + wxTEXT_ATTR_BULLET_STYLE_ROMAN_UPPER, + wxTEXT_ATTR_BULLET_STYLE_ROMAN_LOWER, + wxTEXT_ATTR_BULLET_STYLE_SYMBOL, + wxTEXT_ATTR_BULLET_STYLE_BITMAP, + wxTEXT_ATTR_BULLET_STYLE_PARENTHESES, + wxTEXT_ATTR_BULLET_STYLE_PERIOD, + wxTEXT_ATTR_BULLET_STYLE_STANDARD, + wxTEXT_ATTR_BULLET_STYLE_RIGHT_PARENTHESIS, + wxTEXT_ATTR_BULLET_STYLE_OUTLINE, + + wxTEXT_ATTR_BULLET_STYLE_ALIGN_LEFT, + wxTEXT_ATTR_BULLET_STYLE_ALIGN_RIGHT, + wxTEXT_ATTR_BULLET_STYLE_ALIGN_CENTRE, + +/*! + * Styles for wxTextAttrEx::SetTextEffects + */ + wxTEXT_ATTR_EFFECT_NONE, + wxTEXT_ATTR_EFFECT_CAPITALS, + wxTEXT_ATTR_EFFECT_SMALL_CAPITALS, + wxTEXT_ATTR_EFFECT_STRIKETHROUGH, + wxTEXT_ATTR_EFFECT_DOUBLE_STRIKETHROUGH, + wxTEXT_ATTR_EFFECT_SHADOW, + wxTEXT_ATTR_EFFECT_EMBOSS, + wxTEXT_ATTR_EFFECT_OUTLINE, + wxTEXT_ATTR_EFFECT_ENGRAVE, + wxTEXT_ATTR_EFFECT_SUPERSCRIPT, + wxTEXT_ATTR_EFFECT_SUBSCRIPT, + +/*! + * Line spacing values + */ + wxTEXT_ATTR_LINE_SPACING_NORMAL, + wxTEXT_ATTR_LINE_SPACING_HALF, + wxTEXT_ATTR_LINE_SPACING_TWICE, + +/*! + * Character and paragraph combined styles + */ + wxTEXT_ATTR_CHARACTER, + wxTEXT_ATTR_PARAGRAPH, + wxTEXT_ATTR_ALL, + + }; + + +//--------------------------------------------------------------------------- +%newgroup + + + +%typemap(in) wxRichTextRange& (wxRichTextRange temp) { + $1 = &temp; + if ( ! wxRichTextRange_helper($input, &$1)) SWIG_fail; +} +%typemap(typecheck, precedence=SWIG_TYPECHECK_POINTER) wxRichTextRange& { + $1 = wxPySimple_typecheck($input, wxT("wxRichTextRange"), 2); +} + + +%{ +bool wxRichTextRange_helper(PyObject* source, wxRichTextRange** obj) +{ + if (source == Py_None) { + **obj = wxRICHTEXT_NONE; + return true; + } + return wxPyTwoIntItem_helper(source, obj, wxT("wxRichTextRange")); +} +%} + + + +DocStr(wxRichTextRange, +"RichTextRange is a data structure that represents a range of text +within a `RichTextCtrl`. It simply contains integer ``start`` and +``end`` properties and a few operations useful for dealing with +ranges. In most places in wxPython where a RichTextRange is expected a +2-tuple containing (start, end) can be used instead.", ""); + +// Turn off the generation of code that aquires the Global Interpreter Lock +%threadWrapperOff + +class wxRichTextRange +{ +public: + DocCtorStr( + wxRichTextRange(long start=0, long end=0), + "Creates a new range object.", ""); + + ~wxRichTextRange(); + + %extend { + DocStr(__eq__, "Test for equality of RichTextRange objects.", ""); + bool __eq__(PyObject* other) { + wxRichTextRange temp, *obj = &temp; + if ( other == Py_None ) return false; + if ( ! wxRichTextRange_helper(other, &obj) ) { + PyErr_Clear(); + return false; + } + return self->operator==(*obj); + } + } + + + DocDeclStr( + wxRichTextRange , operator -(const wxRichTextRange& range) const, + "", ""); + + DocDeclStr( + wxRichTextRange , operator +(const wxRichTextRange& range) const, + "", ""); + + + DocDeclStr( + void , SetRange(long start, long end), + "", ""); + + + DocDeclStr( + void , SetStart(long start), + "", ""); + DocDeclStr( + long , GetStart() const, + "", ""); + %pythoncode { start = property(GetStart, SetStart) } + + + DocDeclStr( + void , SetEnd(long end), + "", ""); + DocDeclStr( + long , GetEnd() const, + "", ""); + %pythoncode { end = property(GetEnd, SetEnd) } + + + DocDeclStr( + bool , IsOutside(const wxRichTextRange& range) const, + "Returns true if this range is completely outside 'range'", ""); + + + DocDeclStr( + bool , IsWithin(const wxRichTextRange& range) const, + "Returns true if this range is completely within 'range'", ""); + + + DocDeclStr( + bool , Contains(long pos) const, + "Returns true if the given position is within this range. Allow for the +possibility of an empty range - assume the position is within this +empty range.", ""); + + + DocDeclStr( + bool , LimitTo(const wxRichTextRange& range) , + "Limit this range to be within 'range'", ""); + + + DocDeclStr( + long , GetLength() const, + "Gets the length of the range", ""); + + + DocDeclStr( + void , Swap(), + "Swaps the start and end", ""); + + + DocDeclStr( + wxRichTextRange , ToInternal() const, + "Convert to internal form: (n, n) is the range of a single character.", ""); + + + DocDeclStr( + wxRichTextRange , FromInternal() const, + "Convert from internal to public API form: (n, n+1) is the range of a +single character.", ""); + + + %extend { + DocAStr(Get, + "Get() -> (start,end)", + "Returns the start and end properties as a tuple.", ""); + PyObject* Get() { + PyObject* tup = PyTuple_New(2); + PyTuple_SET_ITEM(tup, 0, PyInt_FromLong(self->GetStart())); + PyTuple_SET_ITEM(tup, 1, PyInt_FromLong(self->GetEnd())); + return tup; + } + } + %pythoncode { + def __str__(self): return str(self.Get()) + def __repr__(self): return 'RichTextRange'+str(self.Get()) + def __len__(self): return len(self.Get()) + def __getitem__(self, index): return self.Get()[index] + def __setitem__(self, index, val): + if index == 0: self.start = val + elif index == 1: self.end = val + else: raise IndexError + def __nonzero__(self): return self.Get() != (0,0) + __safe_for_unpickling__ = True + def __reduce__(self): return (RichTextRange, self.Get()) + } + + %property(End, GetEnd, SetEnd, doc="See `GetEnd` and `SetEnd`"); + %property(Length, GetLength, doc="See `GetLength`"); + %property(Start, GetStart, SetStart, doc="See `GetStart` and `SetStart`"); +}; + + + +%{ + wxRichTextRange wxPy_RTR_ALL(wxRICHTEXT_ALL); + wxRichTextRange wxPy_RTR_NONE(wxRICHTEXT_NONE); +%} + +%rename(RICHTEXT_ALL) wxPy_RTR_ALL; +%rename(RICHTEXT_NONE) wxPy_RTR_NONE; + +%immutable; +wxRichTextRange wxPy_RTR_ALL; +wxRichTextRange wxPy_RTR_NONE; +%mutable; + +// Turn back on the generation of code that aquires the Global Interpreter Lock +%threadWrapperOn + + + + +//--------------------------------------------------------------------------- +%newgroup + + +DocStr(wxRichTextAttr, +"The RichTextAttr class stores information about the various attributes +for a block of text, including font, colour, indents, alignments, and +etc.", ""); + +class wxRichTextAttr +{ +public: + + wxRichTextAttr(const wxColour& colText = wxNullColour, + const wxColour& colBack = wxNullColour, + wxTextAttrAlignment alignment = wxTEXT_ALIGNMENT_DEFAULT); + + ~wxRichTextAttr(); + +// // Making a wxTextAttrEx object. +// operator wxTextAttrEx () const ; + +// // Copy to a wxTextAttr +// void CopyTo(wxTextAttrEx& attr) const; + + + DocDeclStr( + void , Init(), + "Initialise this object.", ""); + + + DocDeclStr( + void , Copy(const wxRichTextAttr& attr), + "Copy from attr to self.", ""); + + + // Equality test + bool operator== (const wxRichTextAttr& attr) const; + + + + DocDeclStr( + wxFont , CreateFont() const, + "Create font from the font attributes in this attr object.", ""); + + + DocDeclStr( + bool , GetFontAttributes(const wxFont& font), + "Set our font attributes from the font.", ""); + + + %pythoncode { + def GetFont(self): + return self.CreateFont() + def SetFont(self, font): + return self.GetFontAttributes(font) + } + + // setters + void SetTextColour(const wxColour& colText); + void SetBackgroundColour(const wxColour& colBack); + void SetAlignment(wxTextAttrAlignment alignment); + void SetTabs(const wxArrayInt& tabs); + void SetLeftIndent(int indent, int subIndent = 0); + void SetRightIndent(int indent); + + void SetFontSize(int pointSize); + void SetFontStyle(int fontStyle); + void SetFontWeight(int fontWeight); + void SetFontFaceName(const wxString& faceName); + void SetFontUnderlined(bool underlined); + + void SetFlags(long flags); + + void SetCharacterStyleName(const wxString& name); + void SetParagraphStyleName(const wxString& name); + void SetListStyleName(const wxString& name); + void SetParagraphSpacingAfter(int spacing); + void SetParagraphSpacingBefore(int spacing); + void SetLineSpacing(int spacing); + void SetBulletStyle(int style); + void SetBulletNumber(int n); + void SetBulletText(wxChar symbol); + void SetBulletFont(const wxString& bulletFont); + void SetBulletName(const wxString& name); + void SetURL(const wxString& url); + void SetPageBreak(bool pageBreak = true); + void SetTextEffects(int effects); + void SetTextEffectFlags(int effects); + void SetOutlineLevel(int level); + + const wxColour& GetTextColour() const; + const wxColour& GetBackgroundColour() const; + wxTextAttrAlignment GetAlignment() const; + const wxArrayInt& GetTabs() const; + long GetLeftIndent() const; + long GetLeftSubIndent() const; + long GetRightIndent() const; + long GetFlags() const; + + int GetFontSize() const; + int GetFontStyle() const; + int GetFontWeight() const; + bool GetFontUnderlined() const; + const wxString& GetFontFaceName() const; + + const wxString& GetCharacterStyleName() const; + const wxString& GetParagraphStyleName() const; + const wxString& GetListStyleName() const; + int GetParagraphSpacingAfter() const; + int GetParagraphSpacingBefore() const; + int GetLineSpacing() const; + int GetBulletStyle() const; + int GetBulletNumber() const; + const wxString& GetBulletText() const; + const wxString& GetBulletFont() const; + const wxString& GetBulletName() const; + const wxString& GetURL() const; + int GetTextEffects() const; + int GetTextEffectFlags() const; + int GetOutlineLevel() const; + + // accessors + bool HasTextColour() const; + bool HasBackgroundColour() const; + bool HasAlignment() const; + bool HasTabs() const; + bool HasLeftIndent() const; + bool HasRightIndent() const; + bool HasFontWeight() const; + bool HasFontSize() const; + bool HasFontItalic() const; + bool HasFontUnderlined() const; + bool HasFontFaceName() const; + bool HasFont() const; + + bool HasParagraphSpacingAfter() const; + bool HasParagraphSpacingBefore() const; + bool HasLineSpacing() const; + bool HasCharacterStyleName() const; + bool HasParagraphStyleName() const; + bool HasListStyleName() const; + bool HasBulletStyle() const; + bool HasBulletNumber() const; + bool HasBulletText() const; + bool HasBulletName() const; + bool HasURL() const; + bool HasPageBreak() const; + bool HasTextEffects() const; + bool HasTextEffect(int effect) const; + bool HasOutlineLevel() const; + + bool HasFlag(long flag) const; + + bool IsCharacterStyle() const; + bool IsParagraphStyle() const; + + + DocDeclStr( + bool , IsDefault() const, + "Returns false if we have any attributes set, true otherwise", ""); + + + DocDeclStr( + bool , Apply(const wxRichTextAttr& style, const wxRichTextAttr* compareWith = NULL), + "Merges the given attributes. Does not affect self. If compareWith is +not None, then it will be used to mask out those attributes that are +the same in style and compareWith, for situations where we don't want +to explicitly set inherited attributes. +", ""); + + + DocDeclStr( + wxRichTextAttr , Combine(const wxRichTextAttr& style, const wxRichTextAttr* compareWith = NULL) const, + "Merges the given attributes and returns the result. Does not affect +self. If compareWith is not None, then it will be used to mask out +those attributes that are the same in style and compareWith, for +situations where we don't want to explicitly set inherited attributes. +", ""); + + + + %property(Alignment, GetAlignment, SetAlignment); + %property(BackgroundColour, GetBackgroundColour, SetBackgroundColour); + %property(BulletFont, GetBulletFont, SetBulletFont); + %property(BulletNumber, GetBulletNumber, SetBulletNumber); + %property(BulletStyle, GetBulletStyle, SetBulletStyle); + %property(BulletText, GetBulletText, SetBulletText); + %property(CharacterStyleName, GetCharacterStyleName, SetCharacterStyleName); + %property(Flags, GetFlags, SetFlags); + %property(Font, GetFont, SetFont); + %property(FontAttributes, GetFontAttributes); + %property(FontFaceName, GetFontFaceName, SetFontFaceName); + %property(FontSize, GetFontSize, SetFontSize); + %property(FontStyle, GetFontStyle, SetFontStyle); + %property(FontUnderlined, GetFontUnderlined, SetFontUnderlined); + %property(FontWeight, GetFontWeight, SetFontWeight); + %property(LeftIndent, GetLeftIndent, SetLeftIndent); + %property(LeftSubIndent, GetLeftSubIndent); + %property(LineSpacing, GetLineSpacing, SetLineSpacing); + %property(ParagraphSpacingAfter, GetParagraphSpacingAfter, SetParagraphSpacingAfter); + %property(ParagraphSpacingBefore, GetParagraphSpacingBefore, SetParagraphSpacingBefore); + %property(ParagraphStyleName, GetParagraphStyleName, SetParagraphStyleName); + %property(RightIndent, GetRightIndent, SetRightIndent); + %property(Tabs, GetTabs, SetTabs); + %property(TextColour, GetTextColour, SetTextColour); + + %property(ListStyleName, GetListStyleName, SetListStyleName); + %property(BulletName, GetBulletName, SetBulletName); + %property(URL, GetURL, SetURL); + %property(TextEffects, GetTextEffects, SetTextEffects); + %property(TextEffectFlags, GetTextEffectFlags, SetTextEffectFlags); + %property(OutlineLevel, GetOutlineLevel, SetOutlineLevel); +}; + + + +//--------------------------------------------------------------------------- +//--------------------------------------------------------------------------- + + +// TODO TODO TODO +// There's still lots to do for these classes... +// +// 1. Decide how to coalesce overloaded methods and ctors +// 2. correctly set disown flags and re-ownership as needed +// 3. Implement PyRichTextObject +// 4. Decide how to typemap and tweak the virtuals that pass back +// values in their parameters (yuck! damn C++) +// 5. better handling of streams +// 6. list-like wrapper for C++ wxLists +// 7. wrappers for wxTextAttrEx --> wxRichTextAttr (as needed) +// 8. Add more properties + + + +DocStr(wxRichTextObject, +"This is the base class for all drawable objects in a `RichTextCtrl`. + +The data displayed in a `RichTextCtrl` is handled by `RichTextBuffer`, +and a `RichTextCtrl` always has one such buffer. + +The content is represented by a hierarchy of objects, all derived from +`RichTextObject`. An object might be an image, a fragment of text, a +paragraph, or a whole buffer. Objects store a an attribute object +containing style information; a paragraph object can contain both +paragraph and character information, but content objects such as text +can only store character information. The final style displayed in the +control or in a printout is a combination of base style, paragraph +style and content (character) style. + +The top of the hierarchy is the buffer, a kind of +`RichTextParagraphLayoutBox`. containing further `RichTextParagraph` +objects, each of which can include text, images and potentially other +types of objects. + +Each object maintains a range (start and end position) measured from +the start of the main parent object. + +When Layout is called on an object, it is given a size which the +object must limit itself to, or one or more flexible directions +(vertical or horizontal). So, for example, a centred paragraph is +given the page width to play with (minus any margins), but can extend +indefinitely in the vertical direction. The implementation of Layout +caches the calculated size and position. + +When the buffer is modified, a range is invalidated (marked as +requiring layout), so that only the minimum amount of layout is +performed. + +A paragraph of pure text with the same style contains just one further +object, a `RichTextPlainText` object. When styling is applied to part +of this object, the object is decomposed into separate objects, one +object for each different character style. So each object within a +paragraph always has just one attribute object to denote its character +style. Of course, this can lead to fragmentation after a lot of edit +operations, potentially leading to several objects with the same style +where just one would do. So a Defragment function is called when +updating the control's display, to ensure that the minimum number of +objects is used. + +To implement your own RichTextObjects in Python you must derive a +class from `PyRichTextObject`, which has been instrumented to forward +the virtual C++ method calls to the Python methods in the derived +class. (This class hasn't been implemented yet!)", ""); + +// argout typemap for wxPoint +%typemap(in, numinputs=0, noblock=1) wxPoint& OUTPUT (wxPoint temp) { + $1 = &temp; +} +%typemap(argout, noblock=1) wxPoint& OUTPUT { + %append_output(SWIG_NewPointerObj((void*)new wxPoint(*$1), $1_descriptor, SWIG_POINTER_OWN)); +} + +// argout typemap for wxSize +%typemap(in, numinputs=0, noblock=1) wxSize& OUTPUT (wxSize temp) { + $1 = &temp; +} +%typemap(argout, noblock=1) wxSize& OUTPUT { + %append_output(SWIG_NewPointerObj((void*)new wxSize(*$1), $1_descriptor, SWIG_POINTER_OWN)); +} + + +class wxRichTextObject: public wxObject +{ +public: + // wxRichTextObject(wxRichTextObject* parent = NULL); // **** This is an ABC + virtual ~wxRichTextObject(); + + +// Overrideables + + /// Draw the item, within the given range. Some objects may ignore the range (for + /// example paragraphs) while others must obey it (lines, to implement wrapping) + virtual bool Draw(wxDC& dc, const wxRichTextRange& range, + const wxRichTextRange& selectionRange, const wxRect& rect, + int descent, int style); + + /// Lay the item out at the specified position with the given size constraint. + /// Layout must set the cached size. + virtual bool Layout(wxDC& dc, const wxRect& rect, int style); + + /// Hit-testing: returns a flag indicating hit test details, plus + /// information about position + virtual int HitTest(wxDC& dc, const wxPoint& pt, long& OUTPUT /*textPosition*/); + + /// Finds the absolute position and row height for the given character position + virtual bool FindPosition(wxDC& dc, long index, wxPoint& OUTPUT /*pt*/, + int* OUTPUT /*height*/, bool forceLineStart); + + + /// Get the best size, i.e. the ideal starting size for this object irrespective + /// of available space. For a short text string, it will be the size that exactly encloses + /// the text. For a longer string, it might use the parent width for example. + virtual wxSize GetBestSize() const; + + /// Get the object size for the given range. Returns false if the range + /// is invalid for this object. + virtual bool GetRangeSize(const wxRichTextRange& range, wxSize& OUTPUT /*size*/, + int& OUTPUT /*descent*/, wxDC& dc, int flags, + wxPoint position = wxPoint(0,0)) const; + + /// Do a split, returning an object containing the second part, and setting + /// the first part in 'this'. + virtual wxRichTextObject* DoSplit(long pos); + + /// Calculate range. By default, guess that the object is 1 unit long. + virtual void CalculateRange(long start, long& OUTPUT /*end*/); + + /// Delete range + virtual bool DeleteRange(const wxRichTextRange& range); + + /// Returns true if the object is empty + virtual bool IsEmpty() const; + + /// Get any text in this object for the given range + virtual wxString GetTextForRange(const wxRichTextRange& range) const; + + /// Returns true if this object can merge itself with the given one. + virtual bool CanMerge(wxRichTextObject* object) const; + + /// Returns true if this object merged itself with the given one. + /// The calling code will then delete the given object. + virtual bool Merge(wxRichTextObject* object); + + /// Dump to output stream for debugging + //virtual void Dump(wxTextOutputStream& stream); + %extend { + wxString Dump() { + wxStringOutputStream strstream; + wxTextOutputStream txtstream(strstream); + self->Dump(txtstream); + return strstream.GetString(); + } + } + +// Accessors + + /// Get/set the cached object size as calculated by Layout. + virtual wxSize GetCachedSize() const; + virtual void SetCachedSize(const wxSize& sz); + %property(CachedSize, GetCachedSize, SetCachedSize); + + /// Get/set the object position + virtual wxPoint GetPosition() const; + virtual void SetPosition(const wxPoint& pos); + %property(Position, GetPosition, SetPosition); + + /// Get the rectangle enclosing the object + virtual wxRect GetRect() const; + %property(Rect, GetRect); + + + /// Set the range + void SetRange(const wxRichTextRange& range); + /// Get the range + wxRichTextRange GetRange(); + %property(Range, GetRange, SetRange); + + + /// Get/set dirty flag (whether the object needs Layout to be called) + virtual bool GetDirty() const; + virtual void SetDirty(bool dirty); + %property(Dirty, GetDirty, SetDirty); + + + /// Is this composite? + virtual bool IsComposite() const; + + /// Get/set the parent. + virtual wxRichTextObject* GetParent() const; + virtual void SetParent(wxRichTextObject* parent); + %property(Parent, GetParent, SetParent); + + + // TODO: Morph these into SetLeftMargin and etc. for wxPython so + // there can be proper properties + + /// Set the margin around the object + %Rename(SetSameMargins, + virtual void , SetMargins(int margin)); + virtual void SetMargins(int leftMargin, int rightMargin, int topMargin, int bottomMargin); + virtual int GetLeftMargin() const; + virtual int GetRightMargin() const; + virtual int GetTopMargin() const; + virtual int GetBottomMargin() const; + + + /// Set attributes object + void SetAttributes(const wxRichTextAttr& attr); + wxRichTextAttr GetAttributes(); + %property(Attributes, GetAttributes, SetAttributes); + + /// Set/get stored descent + void SetDescent(int descent); + int GetDescent() const; + %property(Descent, GetDescent, SetDescent); + + /// Gets the containing buffer + wxRichTextBuffer* GetBuffer() const; + +// Operations + + /// Clone the object + virtual wxRichTextObject* Clone() const; + + /// Copy + void Copy(const wxRichTextObject& obj); + + /// Reference-counting allows us to use the same object in multiple + /// lists (not yet used) + void Reference(); + void Dereference(); + + /// Convert units in tenths of a millimetre to device units + %Rename(ConvertTenthsMMToPixelsDC, + int, ConvertTenthsMMToPixels(wxDC& dc, int units)); + static int ConvertTenthsMMToPixels(int ppi, int units); + +}; + + + + +wxLIST_WRAPPER(wxRichTextObjectList, wxRichTextObject); + + +DocStr(wxRichTextCompositeObject, + "Objects of this class can contain other rich text objects.", ""); + + +class wxRichTextCompositeObject: public wxRichTextObject +{ +public: + // wxRichTextCompositeObject(wxRichTextObject* parent = NULL); **** This is an ABC + virtual ~wxRichTextCompositeObject(); + +// Accessors + + /// Get the children + wxRichTextObjectList& GetChildren(); + + /// Get the child count + size_t GetChildCount() const ; + + /// Get the nth child + wxRichTextObject* GetChild(size_t n) const ; + +// Operations + + /// Copy + void Copy(const wxRichTextCompositeObject& obj); + + %disownarg(wxRichTextObject* child); + + /// Append a child, returning the position + size_t AppendChild(wxRichTextObject* child) ; + + /// Insert the child in front of the given object, or at the beginning + bool InsertChild(wxRichTextObject* child, wxRichTextObject* inFrontOf) ; + + %cleardisown(wxRichTextObject* child); + + + /// Delete the child + %feature("shadow") RemoveChild %{ + def RemoveChild(self, child, deleteChild=False): + val = _richtext.RichTextCompositeObject_RemoveChild(self, child, deleteChild) + self.this.own(not deleteChild) + return val + %} + bool RemoveChild(wxRichTextObject* child, bool deleteChild = false) ; + + /// Delete all children + bool DeleteChildren(); + + /// Recursively merge all pieces that can be merged. + bool Defragment(); +}; + + + + + + +DocStr(wxRichTextBox, + "This defines a 2D space to lay out objects.", ""); + +class wxRichTextBox: public wxRichTextCompositeObject +{ +public: + wxRichTextBox(wxRichTextObject* parent = NULL); + + virtual wxRichTextObject* Clone() const; + void Copy(const wxRichTextBox& obj); +}; + + + + + + +DocStr(wxRichTextParagraphBox, + "This box knows how to lay out paragraphs.", ""); + +class wxRichTextParagraphLayoutBox: public wxRichTextBox +{ +public: + + wxRichTextParagraphLayoutBox(wxRichTextObject* parent = NULL); + +// Accessors + + /// Associate a control with the buffer, for operations that for example require refreshing the window. + void SetRichTextCtrl(wxRichTextCtrl* ctrl); + + /// Get the associated control. + wxRichTextCtrl* GetRichTextCtrl() const; + + /// Get/set whether the last paragraph is partial or complete + void SetPartialParagraph(bool partialPara); + bool GetPartialParagraph() const; + + /// If this is a buffer, returns the current style sheet. The base layout box + /// class doesn't have an associated style sheet. + virtual wxRichTextStyleSheet* GetStyleSheet() const; + +// Operations + + /// Initialize the object. + void Init(); + + /// Clear all children + virtual void Clear(); + + /// Clear and initialize with one blank paragraph + virtual void Reset(); + + /// Convenience function to add a paragraph of text + virtual wxRichTextRange AddParagraph(const wxString& text, wxTextAttrEx* paraStyle = NULL); + + /// Convenience function to add an image + virtual wxRichTextRange AddImage(const wxImage& image, wxTextAttrEx* paraStyle = NULL); + + /// Adds multiple paragraphs, based on newlines. + virtual wxRichTextRange AddParagraphs(const wxString& text, wxTextAttrEx* paraStyle = NULL); + + /// Get the line at the given position. If caretPosition is true, the position is + /// a caret position, which is normally a smaller number. + virtual wxRichTextLine* GetLineAtPosition(long pos, bool caretPosition = false) const; + + /// Get the line at the given y pixel position, or the last line. + virtual wxRichTextLine* GetLineAtYPosition(int y) const; + + /// Get the paragraph at the given character or caret position + virtual wxRichTextParagraph* GetParagraphAtPosition(long pos, bool caretPosition = false) const; + + /// Get the line size at the given position + virtual wxSize GetLineSizeAtPosition(long pos, bool caretPosition = false) const; + + /// Given a position, get the number of the visible line (potentially many to a paragraph), + /// starting from zero at the start of the buffer. We also have to pass a bool (startOfLine) + /// that indicates whether the caret is being shown at the end of the previous line or at the start + /// of the next, since the caret can be shown at 2 visible positions for the same underlying + /// position. + virtual long GetVisibleLineNumber(long pos, bool caretPosition = false, bool startOfLine = false) const; + + /// Given a line number, get the corresponding wxRichTextLine object. + virtual wxRichTextLine* GetLineForVisibleLineNumber(long lineNumber) const; + + /// Get the leaf object in a paragraph at this position. + /// Given a line number, get the corresponding wxRichTextLine object. + virtual wxRichTextObject* GetLeafObjectAtPosition(long position) const; + + /// Get the paragraph by number + virtual wxRichTextParagraph* GetParagraphAtLine(long paragraphNumber) const; + + /// Get the paragraph for a given line + virtual wxRichTextParagraph* GetParagraphForLine(wxRichTextLine* line) const; + + /// Get the length of the paragraph + virtual int GetParagraphLength(long paragraphNumber) const; + + /// Get the number of paragraphs + virtual int GetParagraphCount() const { return GetChildCount(); } + + /// Get the number of visible lines + virtual int GetLineCount() const; + + /// Get the text of the paragraph + virtual wxString GetParagraphText(long paragraphNumber) const; + + /// Convert zero-based line column and paragraph number to a position. + virtual long XYToPosition(long x, long y) const; + + /// Convert zero-based position to line column and paragraph number + virtual bool PositionToXY(long pos, long* x, long* y) const; + + /// Set text attributes: character and/or paragraph styles. + virtual bool SetStyle(const wxRichTextRange& range, + const wxRichTextAttr& style, + int flags = wxRICHTEXT_SETSTYLE_WITH_UNDO); +// virtual bool SetStyle(const wxRichTextRange& range, +// const wxTextAttrEx& style, +// int flags = wxRICHTEXT_SETSTYLE_WITH_UNDO); + + /// Get the conbined text attributes for this position. +// virtual bool GetStyle(long position, wxTextAttrEx& style); + virtual bool GetStyle(long position, wxRichTextAttr& style); + + /// Get the content (uncombined) attributes for this position. +// virtual bool GetUncombinedStyle(long position, wxTextAttrEx& style); + virtual bool GetUncombinedStyle(long position, wxRichTextAttr& style); + +// /// Implementation helper for GetStyle. If combineStyles is true, combine base, paragraph and +// /// context attributes. +// virtual bool DoGetStyle(long position, wxTextAttrEx& style, bool combineStyles = true); + + /// Get the combined style for a range - if any attribute is different within the range, + /// that attribute is not present within the flags + virtual bool GetStyleForRange(const wxRichTextRange& range, wxTextAttrEx& style); + + /// Combines 'style' with 'currentStyle' for the purpose of summarising the attributes of a range of + /// content. + bool CollectStyle(wxTextAttrEx& currentStyle, const wxTextAttrEx& style, long& multipleStyleAttributes, int& multipleTextEffectAttributes); + + /// Set list style + //virtual bool SetListStyle(const wxRichTextRange& range, wxRichTextListStyleDefinition* def, int flags = wxRICHTEXT_SETSTYLE_WITH_UNDO, int startFrom = 1, int specifiedLevel = -1); + virtual bool SetListStyle(const wxRichTextRange& range, const wxString& defName, + int flags = wxRICHTEXT_SETSTYLE_WITH_UNDO, + int startFrom = 1, int specifiedLevel = -1); + + /// Clear list for given range + virtual bool ClearListStyle(const wxRichTextRange& range, + int flags = wxRICHTEXT_SETSTYLE_WITH_UNDO); + + /// Number/renumber any list elements in the given range. + /// def/defName can be NULL/empty to indicate that the existing list style should be used. + //virtual bool NumberList(const wxRichTextRange& range, wxRichTextListStyleDefinition* def = NULL, int flags = wxRICHTEXT_SETSTYLE_WITH_UNDO, int startFrom = 1, int specifiedLevel = -1); + virtual bool NumberList(const wxRichTextRange& range, const wxString& defName, + int flags = wxRICHTEXT_SETSTYLE_WITH_UNDO, + int startFrom = 1, int specifiedLevel = -1); + + /// Promote the list items within the given range. promoteBy can be a positive or negative number, e.g. 1 or -1 + /// def/defName can be NULL/empty to indicate that the existing list style should be used. + //virtual bool PromoteList(int promoteBy, const wxRichTextRange& range, wxRichTextListStyleDefinition* def = NULL, int flags = wxRICHTEXT_SETSTYLE_WITH_UNDO, int specifiedLevel = -1); + virtual bool PromoteList(int promoteBy, const wxRichTextRange& range, + const wxString& defName, + int flags = wxRICHTEXT_SETSTYLE_WITH_UNDO, + int specifiedLevel = -1); + + /// Helper for NumberList and PromoteList, that does renumbering and promotion simultaneously + /// def/defName can be NULL/empty to indicate that the existing list style should be used. + virtual bool DoNumberList(const wxRichTextRange& range, const wxRichTextRange& promotionRange, int promoteBy, wxRichTextListStyleDefinition* def, int flags = wxRICHTEXT_SETSTYLE_WITH_UNDO, int startFrom = 1, int specifiedLevel = -1); + + /// Fills in the attributes for numbering a paragraph after previousParagraph. + virtual bool FindNextParagraphNumber(wxRichTextParagraph* previousParagraph, wxRichTextAttr& attr) const; + + /// Test if this whole range has character attributes of the specified kind. If any + /// of the attributes are different within the range, the test fails. You + /// can use this to implement, for example, bold button updating. style must have + /// flags indicating which attributes are of interest. + //virtual bool HasCharacterAttributes(const wxRichTextRange& range, const wxTextAttrEx& style) const; + virtual bool HasCharacterAttributes(const wxRichTextRange& range, const wxRichTextAttr& style) const; + + /// Test if this whole range has paragraph attributes of the specified kind. If any + /// of the attributes are different within the range, the test fails. You + /// can use this to implement, for example, centering button updating. style must have + /// flags indicating which attributes are of interest. + //virtual bool HasParagraphAttributes(const wxRichTextRange& range, const wxTextAttrEx& style) const; + virtual bool HasParagraphAttributes(const wxRichTextRange& range, const wxRichTextAttr& style) const; + + /// Clone + virtual wxRichTextObject* Clone() const { return new wxRichTextParagraphLayoutBox(*this); } + + /// Insert fragment into this box at the given position. If partialParagraph is true, + /// it is assumed that the last (or only) paragraph is just a piece of data with no paragraph + /// marker. + virtual bool InsertFragment(long position, wxRichTextParagraphLayoutBox& fragment); + + /// Make a copy of the fragment corresponding to the given range, putting it in 'fragment'. + virtual bool CopyFragment(const wxRichTextRange& range, wxRichTextParagraphLayoutBox& fragment); + + /// Apply the style sheet to the buffer, for example if the styles have changed. + virtual bool ApplyStyleSheet(wxRichTextStyleSheet* styleSheet); + + /// Copy + void Copy(const wxRichTextParagraphLayoutBox& obj); + + /// Calculate ranges + virtual void UpdateRanges(); + + /// Get all the text + virtual wxString GetText() const; + + /// Set default style for new content. Setting it to a default attribute + /// makes new content take on the 'basic' style. + virtual bool SetDefaultStyle(const wxTextAttrEx& style); + + /// Get default style + virtual const wxTextAttrEx& GetDefaultStyle() const; + + /// Set basic (overall) style + //virtual void SetBasicStyle(const wxTextAttrEx& style); + virtual void SetBasicStyle(const wxRichTextAttr& style); + + /// Get basic (overall) style + virtual const wxTextAttrEx& GetBasicStyle() const; + + /// Invalidate the buffer. With no argument, invalidates whole buffer. + void Invalidate(const wxRichTextRange& invalidRange = wxRICHTEXT_ALL); + + /// Get invalid range, rounding to entire paragraphs if argument is true. + wxRichTextRange GetInvalidRange(bool wholeParagraphs = false) const; + +}; + + + + + +DocStr(wxRichTextLine, + "This object represents a line in a paragraph, and stores offsets from +the start of the paragraph representing the start and end positions of +the line.", ""); + +class wxRichTextLine +{ +public: + wxRichTextLine(wxRichTextParagraph* parent); + virtual ~wxRichTextLine(); + + /// Set the range + void SetRange(const wxRichTextRange& range); + + /// Get the parent paragraph + wxRichTextParagraph* GetParent(); + + /// Get the range + wxRichTextRange GetRange(); + + /// Get the absolute range + wxRichTextRange GetAbsoluteRange() const; + + /// Get/set the line size as calculated by Layout. + virtual wxSize GetSize() const; + virtual void SetSize(const wxSize& sz); + + /// Get/set the object position relative to the parent + virtual wxPoint GetPosition() const; + virtual void SetPosition(const wxPoint& pos); + + /// Get the absolute object position + virtual wxPoint GetAbsolutePosition() const; + + /// Get the rectangle enclosing the line + virtual wxRect GetRect() const; + + /// Set/get stored descent + void SetDescent(int descent); + int GetDescent() const; + +// Operations + + /// Initialisation + void Init(wxRichTextParagraph* parent); + + /// Copy + void Copy(const wxRichTextLine& obj); + + /// Clone + virtual wxRichTextLine* Clone() const; +}; + + + + + + +DocStr(wxRichTextParagraph, + "This object represents a single paragraph (or in a straight text +editor, a line).", ""); + +class wxRichTextParagraph: public wxRichTextBox +{ +public: + %extend { + wxRichTextParagraph(const wxString& text = wxPyEmptyString, + wxRichTextObject* parent = NULL, + wxRichTextAttr* paraStyle = NULL, + wxRichTextAttr* charStyle = NULL) + { + wxTextAttrEx* psAttr = NULL; + wxTextAttrEx* csAttr = NULL; + wxTextAttrEx psAttr_v; + wxTextAttrEx csAttr_v; + if (paraStyle) { + psAttr_v = *paraStyle; + psAttr = &psAttr_v; + } + if (charStyle) { + csAttr_v = *charStyle; + csAttr = &csAttr_v; + } + return new wxRichTextParagraph(text, parent, psAttr, csAttr); + } + } + virtual ~wxRichTextParagraph(); + + +// Accessors + + /// Get the cached lines + wxRichTextLineList& GetLines(); + +// Operations + + /// Copy + void Copy(const wxRichTextParagraph& obj); + + /// Clone + virtual wxRichTextObject* Clone() const; + + /// Clear the cached lines + void ClearLines(); + +// Implementation + + /// Apply paragraph styles such as centering to the wrapped lines + virtual void ApplyParagraphStyle(const wxTextAttrEx& attr, const wxRect& rect); + + /// Insert text at the given position + virtual bool InsertText(long pos, const wxString& text); + + /// Split an object at this position if necessary, and return + /// the previous object, or NULL if inserting at beginning. + virtual wxRichTextObject* SplitAt(long pos, wxRichTextObject** previousObject = NULL); + + /// Move content to a list from this point + virtual void MoveToList(wxRichTextObject* obj, wxList& list); + + /// Add content back from list + virtual void MoveFromList(wxList& list); + + /// Get the plain text searching from the start or end of the range. + /// The resulting string may be shorter than the range given. + bool GetContiguousPlainText(wxString& text, const wxRichTextRange& range, bool fromStart = true); + + /// Find a suitable wrap position. wrapPosition is the last position in the line to the left + /// of the split. + bool FindWrapPosition(const wxRichTextRange& range, wxDC& dc, int availableSpace, long& wrapPosition); + + /// Find the object at the given position + wxRichTextObject* FindObjectAtPosition(long position); + + /// Get the bullet text for this paragraph. + wxString GetBulletText(); + + /// Allocate or reuse a line object + wxRichTextLine* AllocateLine(int pos); + + /// Clear remaining unused line objects, if any + bool ClearUnusedLines(int lineCount); + + /// Get combined attributes of the base style, paragraph style and character style. We use this to dynamically + /// retrieve the actual style. +// wxTextAttrEx GetCombinedAttributes(const wxTextAttrEx& contentStyle) const; + + /// Get combined attributes of the base style and paragraph style. + wxTextAttrEx GetCombinedAttributes() const; + + /// Get the first position from pos that has a line break character. + long GetFirstLineBreakPosition(long pos); + + /// Create default tabstop array + static void InitDefaultTabs(); + + /// Clear default tabstop array + static void ClearDefaultTabs(); + + /// Get default tabstop array + static const wxArrayInt& GetDefaultTabs() { return sm_defaultTabs; } +}; + + + + + + + +DocStr(wxRichTextPlainText, + "This object represents a single piece of text.", ""); + +class wxRichTextPlainText: public wxRichTextObject +{ +public: + wxRichTextPlainText(const wxString& text = wxEmptyString, wxRichTextObject* parent = NULL, wxTextAttrEx* style = NULL); + + /// Get the first position from pos that has a line break character. + long GetFirstLineBreakPosition(long pos); + + /// Get the text + const wxString& GetText() const; + + /// Set the text + void SetText(const wxString& text); + +// Operations + + /// Copy + void Copy(const wxRichTextPlainText& obj); + + /// Clone + virtual wxRichTextObject* Clone() const; + +}; + + + + + + +#if 0 +// TODO: we may not even need wrappers for this class. It looks to me +// like wxRichTextImage might be enough... +DocStr(wxRichTextImageBlock, + "Stores information about an image, in binary in-memory form.", ""); + +class wxRichTextImageBlock: public wxObject +{ +public: + wxRichTextImageBlock(); + virtual ~wxRichTextImageBlock(); + + void Init(); + void Clear(); + + // Load the original image into a memory block. + // If the image is not a JPEG, we must convert it into a JPEG + // to conserve space. + // If it's not a JPEG we can make use of 'image', already scaled, so we don't have to + // load the image a 2nd time. + virtual bool MakeImageBlock(const wxString& filename, int imageType, wxImage& image, bool convertToJPEG = true); + + // Make an image block from the wxImage in the given + // format. + virtual bool MakeImageBlock(wxImage& image, int imageType, int quality = 80); + + // Write to a file + bool Write(const wxString& filename); + + // Write data in hex to a stream + bool WriteHex(wxOutputStream& stream); + + // Read data in hex from a stream + bool ReadHex(wxInputStream& stream, int length, int imageType); + + // Copy from 'block' + void Copy(const wxRichTextImageBlock& block); + + // Load a wxImage from the block + bool Load(wxImage& image); + + +//// Accessors + + unsigned char* GetData() const; + size_t GetDataSize() const; + int GetImageType() const; + + void SetData(unsigned char* image); + void SetDataSize(size_t size); + void SetImageType(int imageType); + + bool IsOk() const; + + // Gets the extension for the block's type + wxString GetExtension() const; + +/// Implementation + + // Allocate and read from stream as a block of memory + static unsigned char* ReadBlock(wxInputStream& stream, size_t size); + static unsigned char* ReadBlock(const wxString& filename, size_t size); + + // Write memory block to stream + static bool WriteBlock(wxOutputStream& stream, unsigned char* block, size_t size); + + // Write memory block to file + static bool WriteBlock(const wxString& filename, unsigned char* block, size_t size); +}; +#endif + + + + + + +DocStr(wxRichTextImage, + "This object represents an image.", ""); + +class wxRichTextImage: public wxRichTextObject +{ +public: + // TODO: Which of these constructors? + wxRichTextImage(wxRichTextObject* parent = NULL); + //wxRichTextImage(const wxImage& image, wxRichTextObject* parent = NULL, wxTextAttrEx* charStyle = NULL); + //wxRichTextImage(const wxRichTextImageBlock& imageBlock, wxRichTextObject* parent = NULL, wxTextAttrEx* charStyle = NULL); + + +// Accessors + + /// Get the image + const wxImage& GetImage() const; + + /// Set the image + void SetImage(const wxImage& image); + + /// Get the image block containing the raw data + wxRichTextImageBlock& GetImageBlock(); + +// Operations + + /// Copy + void Copy(const wxRichTextImage& obj); + + /// Clone + virtual wxRichTextObject* Clone() const; + + /// Load wxImage from the block + virtual bool LoadFromBlock(); + + /// Make block from the wxImage + virtual bool MakeBlock(); +}; + + + + + + +%typemap(out) wxRichTextFileHandler* { $result = wxPyMake_wxObject($1, (bool)$owner); } +wxUNTYPED_LIST_WRAPPER(wxRichTextFileHandlerList, wxRichTextFileHandler); + +DocStr(wxRichTextBuffer, + "This is a kind of box, used to represent the whole buffer.", ""); + +class wxRichTextCommand; +class wxRichTextAction; + +class wxRichTextBuffer: public wxRichTextParagraphLayoutBox +{ +public: + wxRichTextBuffer(); + virtual ~wxRichTextBuffer() ; + +// Accessors + + /// Gets the command processor + wxCommandProcessor* GetCommandProcessor() const; + + /// Set style sheet, if any. + void SetStyleSheet(wxRichTextStyleSheet* styleSheet); + virtual wxRichTextStyleSheet* GetStyleSheet() const; + + /// Set style sheet and notify of the change + bool SetStyleSheetAndNotify(wxRichTextStyleSheet* sheet); + + /// Push style sheet to top of stack + bool PushStyleSheet(wxRichTextStyleSheet* styleSheet); + + /// Pop style sheet from top of stack + wxRichTextStyleSheet* PopStyleSheet(); + +// Operations + + /// Initialisation + void Init(); + + /// Clears the buffer, adds an empty paragraph, and clears the command processor. + virtual void ResetAndClearCommands(); + + /// Load a file + virtual bool LoadFile(const wxString& filename, int type = wxRICHTEXT_TYPE_ANY); + + /// Save a file + virtual bool SaveFile(const wxString& filename, int type = wxRICHTEXT_TYPE_ANY); + + /// Load from a stream + %Rename(LoadStream, + virtual bool , LoadFile(wxInputStream& stream, int type = wxRICHTEXT_TYPE_ANY)); + + /// Save to a stream + %Rename(SaveStream, + virtual bool , SaveFile(wxOutputStream& stream, int type = wxRICHTEXT_TYPE_ANY)); + + /// Set the handler flags, controlling loading and saving + void SetHandlerFlags(int flags) { m_handlerFlags = flags; } + + /// Get the handler flags, controlling loading and saving + int GetHandlerFlags() const { return m_handlerFlags; } + + /// Convenience function to add a paragraph of text + virtual wxRichTextRange AddParagraph(const wxString& text, wxTextAttrEx* paraStyle = NULL) { Modify(); return wxRichTextParagraphLayoutBox::AddParagraph(text, paraStyle); } + + /// Begin collapsing undo/redo commands. Note that this may not work properly + /// if combining commands that delete or insert content, changing ranges for + /// subsequent actions. + virtual bool BeginBatchUndo(const wxString& cmdName); + + /// End collapsing undo/redo commands + virtual bool EndBatchUndo(); + + /// Collapsing commands? + virtual bool BatchingUndo() const; + + /// Submit immediately, or delay according to whether collapsing is on + virtual bool SubmitAction(wxRichTextAction* action); + + /// Get collapsed command + virtual wxRichTextCommand* GetBatchedCommand() const; + + /// Begin suppressing undo/redo commands. The way undo is suppressed may be implemented + /// differently by each command. If not dealt with by a command implementation, then + /// it will be implemented automatically by not storing the command in the undo history + /// when the action is submitted to the command processor. + virtual bool BeginSuppressUndo(); + + /// End suppressing undo/redo commands. + virtual bool EndSuppressUndo(); + + /// Collapsing commands? + virtual bool SuppressingUndo() const; + + /// Copy the range to the clipboard + virtual bool CopyToClipboard(const wxRichTextRange& range); + + /// Paste the clipboard content to the buffer + virtual bool PasteFromClipboard(long position); + + /// Can we paste from the clipboard? + virtual bool CanPasteFromClipboard() const; + + /// Begin using a style + virtual bool BeginStyle(const wxTextAttrEx& style); + + /// End the style + virtual bool EndStyle(); + + /// End all styles + virtual bool EndAllStyles(); + + /// Clear the style stack + virtual void ClearStyleStack(); + + /// Get the size of the style stack, for example to check correct nesting + virtual size_t GetStyleStackSize() const; + + /// Begin using bold + bool BeginBold(); + + /// End using bold + bool EndBold(); + + /// Begin using italic + bool BeginItalic(); + + /// End using italic + bool EndItalic(); + + /// Begin using underline + bool BeginUnderline(); + + /// End using underline + bool EndUnderline(); + + /// Begin using point size + bool BeginFontSize(int pointSize); + + /// End using point size + bool EndFontSize(); + + /// Begin using this font + bool BeginFont(const wxFont& font); + + /// End using a font + bool EndFont(); + + /// Begin using this colour + bool BeginTextColour(const wxColour& colour); + + /// End using a colour + bool EndTextColour(); + + /// Begin using alignment + bool BeginAlignment(wxTextAttrAlignment alignment); + + /// End alignment + bool EndAlignment(); + + /// Begin left indent + bool BeginLeftIndent(int leftIndent, int leftSubIndent = 0); + + /// End left indent + bool EndLeftIndent(); + + /// Begin right indent + bool BeginRightIndent(int rightIndent); + + /// End right indent + bool EndRightIndent(); + + /// Begin paragraph spacing + bool BeginParagraphSpacing(int before, int after); + + /// End paragraph spacing + bool EndParagraphSpacing(); + + /// Begin line spacing + bool BeginLineSpacing(int lineSpacing); + + /// End line spacing + bool EndLineSpacing(); + + /// Begin numbered bullet + bool BeginNumberedBullet(int bulletNumber, int leftIndent, int leftSubIndent, int bulletStyle = wxTEXT_ATTR_BULLET_STYLE_ARABIC|wxTEXT_ATTR_BULLET_STYLE_PERIOD); + + /// End numbered bullet + bool EndNumberedBullet(); + + /// Begin symbol bullet + bool BeginSymbolBullet(const wxString& symbol, int leftIndent, int leftSubIndent, int bulletStyle = wxTEXT_ATTR_BULLET_STYLE_SYMBOL); + + /// End symbol bullet + bool EndSymbolBullet(); + + /// Begin standard bullet + bool BeginStandardBullet(const wxString& bulletName, int leftIndent, int leftSubIndent, int bulletStyle = wxTEXT_ATTR_BULLET_STYLE_STANDARD); + + /// End standard bullet + bool EndStandardBullet(); + + /// Begin named character style + bool BeginCharacterStyle(const wxString& characterStyle); + + /// End named character style + bool EndCharacterStyle(); + + /// Begin named paragraph style + bool BeginParagraphStyle(const wxString& paragraphStyle); + + /// End named character style + bool EndParagraphStyle(); + + /// Begin named list style + bool BeginListStyle(const wxString& listStyle, int level = 1, int number = 1); + + /// End named character style + bool EndListStyle(); + + /// Begin URL + bool BeginURL(const wxString& url, const wxString& characterStyle = wxEmptyString); + + /// End URL + bool EndURL(); + +// Event handling + + /// Add an event handler + bool AddEventHandler(wxEvtHandler* handler); + + /// Remove an event handler + bool RemoveEventHandler(wxEvtHandler* handler, bool deleteHandler = false); + + /// Clear event handlers + void ClearEventHandlers(); + + /// Send event to event handlers. If sendToAll is true, will send to all event handlers, + /// otherwise will stop at the first successful one. + bool SendEvent(wxEvent& event, bool sendToAll = true); + +// Implementation + + /// Copy + void Copy(const wxRichTextBuffer& obj); + + /// Clone + virtual wxRichTextObject* Clone() const; + + /// Submit command to insert paragraphs + bool InsertParagraphsWithUndo(long pos, const wxRichTextParagraphLayoutBox& paragraphs, wxRichTextCtrl* ctrl, int flags = 0); + + /// Submit command to insert the given text + bool InsertTextWithUndo(long pos, const wxString& text, wxRichTextCtrl* ctrl, int flags = 0); + + /// Submit command to insert a newline + bool InsertNewlineWithUndo(long pos, wxRichTextCtrl* ctrl, int flags = 0); + + /// Submit command to insert the given image + bool InsertImageWithUndo(long pos, const wxRichTextImageBlock& imageBlock, wxRichTextCtrl* ctrl, int flags = 0); + + /// Submit command to delete this range + bool DeleteRangeWithUndo(const wxRichTextRange& range, wxRichTextCtrl* ctrl); + + /// Mark modified + void Modify(bool modify = true); + bool IsModified() const; + + /// Get the style that is appropriate for a new paragraph at this position. + /// If the previous paragraph has a paragraph style name, look up the next-paragraph + /// style. + wxRichTextAttr GetStyleForNewParagraph(long pos, bool caretPosition = false, bool lookUpNewParaStyle=false) const; + + + /// Returns the file handlers + static wxRichTextFileHandlerList_t& GetHandlers(); + + %disownarg(wxRichTextFileHandler *handler); + + /// Adds a handler to the end + static void AddHandler(wxRichTextFileHandler *handler); + + /// Inserts a handler at the front + static void InsertHandler(wxRichTextFileHandler *handler); + + %cleardisown(wxRichTextFileHandler *handler); + + + /// Removes a handler + static bool RemoveHandler(const wxString& name); + + /// Finds a handler by name + %Rename(FindHandlerByName, + static wxRichTextFileHandler* , FindHandler(const wxString& name)); + + /// Finds a handler by extension and type + %Rename(FindHandlerByExtension, + static wxRichTextFileHandler*, FindHandler(const wxString& extension, int imageType)); + + /// Finds a handler by filename or, if supplied, type + %Rename(FindHandlerByFilename, + static wxRichTextFileHandler* , FindHandlerFilenameOrType(const wxString& filename, int imageType)); + + /// Finds a handler by type + %Rename(FindHandlerByType, + static wxRichTextFileHandler* , FindHandler(int imageType)); + + + // TODO: Handle returning the types array? + + /// Gets a wildcard incorporating all visible handlers. If 'types' is present, + /// will be filled with the file type corresponding to each filter. This can be + /// used to determine the type to pass to LoadFile given a selected filter. + //static wxString GetExtWildcard(bool combine = false, bool save = false, + // wxArrayInt* types = NULL); + %extend { + KeepGIL(GetExtWildcard); + DocAStr(GetExtWildcard, + "GetExtWildcard(self, bool combine=False, bool save=False) --> (wildcards, types)", + "Gets a wildcard string for the file dialog based on all the currently +loaded richtext file handlers, and a list that can be used to map +those filter types to the file handler type.", ""); + static PyObject* GetExtWildcard(bool combine = false, bool save = false) { + wxString wildcards; + wxArrayInt types; + wildcards = wxRichTextBuffer::GetExtWildcard(combine, save, &types); + PyObject* tup = PyTuple_New(2); + PyTuple_SET_ITEM(tup, 0, wx2PyString(wildcards)); + PyTuple_SET_ITEM(tup, 1, wxArrayInt2PyList_helper(types)); + return tup; + } + } + + /// Clean up handlers + static void CleanUpHandlers(); + + /// Initialise the standard handlers + static void InitStandardHandlers(); + + /// Get renderer + static wxRichTextRenderer* GetRenderer(); + + /// Set renderer, deleting old one + static void SetRenderer(wxRichTextRenderer* renderer); + + /// Minimum margin between bullet and paragraph in 10ths of a mm + static int GetBulletRightMargin(); + static void SetBulletRightMargin(int margin); + + /// Factor to multiply by character height to get a reasonable bullet size + static float GetBulletProportion(); + static void SetBulletProportion(float prop); + + /// Scale factor for calculating dimensions + double GetScale() const; + void SetScale(double scale); +}; + + + + + + +// TODO: Do we need wrappers for the command processor, undo/redo, etc.? +// +// enum wxRichTextCommandId +// { +// wxRICHTEXT_INSERT, +// wxRICHTEXT_DELETE, +// wxRICHTEXT_CHANGE_STYLE +// }; +// class WXDLLIMPEXP_RICHTEXT wxRichTextCommand: public wxCommand +// class WXDLLIMPEXP_RICHTEXT wxRichTextAction: public wxObject + + + + +//--------------------------------------------------------------------------- +%newgroup + + +/*! + * Handler flags + */ + +enum { + // Include style sheet when loading and saving + wxRICHTEXT_HANDLER_INCLUDE_STYLESHEET, + + // Save images to memory file system in HTML handler + wxRICHTEXT_HANDLER_SAVE_IMAGES_TO_MEMORY, + + // Save images to files in HTML handler + wxRICHTEXT_HANDLER_SAVE_IMAGES_TO_FILES, + + // Save images as inline base64 data in HTML handler + wxRICHTEXT_HANDLER_SAVE_IMAGES_TO_BASE64, + + // Don't write header and footer (or BODY), so we can include the + // fragment in a larger document + wxRICHTEXT_HANDLER_NO_HEADER_FOOTER, +}; + + + + +DocStr(wxRichTextFileHandler, + "Base class for file handlers", ""); + +class wxRichTextFileHandler: public wxObject +{ +public: + //wxRichTextFileHandler(const wxString& name = wxEmptyString, **** This is an ABC + // const wxString& ext = wxEmptyString, + // int type = 0); + + ~wxRichTextFileHandler(); + + %Rename(LoadStream, + bool, LoadFile(wxRichTextBuffer *buffer, wxInputStream& stream)); + %Rename(SaveStream, + bool, SaveFile(wxRichTextBuffer *buffer, wxOutputStream& stream)); + + bool LoadFile(wxRichTextBuffer *buffer, const wxString& filename); + bool SaveFile(wxRichTextBuffer *buffer, const wxString& filename); + + /// Can we handle this filename (if using files)? By default, checks the extension. + virtual bool CanHandle(const wxString& filename) const; + + /// Can we save using this handler? + virtual bool CanSave() const; + + /// Can we load using this handler? + virtual bool CanLoad() const; + + /// Should this handler be visible to the user? + virtual bool IsVisible() const; + virtual void SetVisible(bool visible); + + /// The name of the nandler + void SetName(const wxString& name); + wxString GetName() const; + %property(Name, GetName, SetName) + + /// The default extension to recognise + void SetExtension(const wxString& ext); + wxString GetExtension() const; + %property(Extension, GetExtension, SetExtension) + + /// The handler type + void SetType(int type); + int GetType() const; + %property(Type, GetType, SetType) + + /// Flags controlling how loading and saving is done + void SetFlags(int flags); + int GetFlags() const; + %property(Flags, GetFlags, SetFlags) + + /// Encoding to use when saving a file. If empty, a suitable encoding is chosen + void SetEncoding(const wxString& encoding); + const wxString& GetEncoding() const; + %property(Encoding, GetEncoding, SetEncoding) +}; + + + +MAKE_CONST_WXSTRING2(TextName, wxT("Text")); +MAKE_CONST_WXSTRING2(TextExt, wxT("txt")); + +class wxRichTextPlainTextHandler: public wxRichTextFileHandler +{ +public: + wxRichTextPlainTextHandler(const wxString& name = wxPyTextName, + const wxString& ext = wxPyTextExt, + int type = wxRICHTEXT_TYPE_TEXT); +}; + + + + + +//--------------------------------------------------------------------------- +%newgroup + + +// TODO: Make a PyRichTextRenderer class + + +/*! + * wxRichTextRenderer isolates common drawing functionality + */ + +class wxRichTextRenderer: public wxObject +{ +public: + wxRichTextRenderer() {} + virtual ~wxRichTextRenderer() {} + + /// Draw a standard bullet, as specified by the value of GetBulletName + virtual bool DrawStandardBullet(wxRichTextParagraph* paragraph, wxDC& dc, const wxTextAttrEx& attr, const wxRect& rect) = 0; + + /// Draw a bullet that can be described by text, such as numbered or symbol bullets + virtual bool DrawTextBullet(wxRichTextParagraph* paragraph, wxDC& dc, const wxTextAttrEx& attr, const wxRect& rect, const wxString& text) = 0; + + /// Draw a bitmap bullet, where the bullet bitmap is specified by the value of GetBulletName + virtual bool DrawBitmapBullet(wxRichTextParagraph* paragraph, wxDC& dc, const wxTextAttrEx& attr, const wxRect& rect) = 0; + + /// Enumerate the standard bullet names currently supported + virtual bool EnumerateStandardBulletNames(wxArrayString& bulletNames) = 0; +}; + +/*! + * wxRichTextStdRenderer: standard renderer + */ + +class wxRichTextStdRenderer: public wxRichTextRenderer +{ +public: + wxRichTextStdRenderer() {} + + /// Draw a standard bullet, as specified by the value of GetBulletName + virtual bool DrawStandardBullet(wxRichTextParagraph* paragraph, wxDC& dc, const wxTextAttrEx& attr, const wxRect& rect); + + /// Draw a bullet that can be described by text, such as numbered or symbol bullets + virtual bool DrawTextBullet(wxRichTextParagraph* paragraph, wxDC& dc, const wxTextAttrEx& attr, const wxRect& rect, const wxString& text); + + /// Draw a bitmap bullet, where the bullet bitmap is specified by the value of GetBulletName + virtual bool DrawBitmapBullet(wxRichTextParagraph* paragraph, wxDC& dc, const wxTextAttrEx& attr, const wxRect& rect); + + /// Enumerate the standard bullet names currently supported + virtual bool EnumerateStandardBulletNames(wxArrayString& bulletNames); +}; + +//--------------------------------------------------------------------------- +//--------------------------------------------------------------------------- diff --git a/wxPython/src/_richtextctrl.i b/wxPython/src/_richtextctrl.i new file mode 100644 index 0000000000..7313b46892 --- /dev/null +++ b/wxPython/src/_richtextctrl.i @@ -0,0 +1,1237 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: _richtextctrl.i +// Purpose: wxRichTextCtrl and related classes +// +// Author: Robin Dunn +// +// Created: 11-April-2006 +// RCS-ID: $Id$ +// Copyright: (c) 2006 by Total Control Software +// Licence: wxWindows license +///////////////////////////////////////////////////////////////////////////// + +// Not a %module + + +//--------------------------------------------------------------------------- + +%{ +%} + +//--------------------------------------------------------------------------- +%newgroup + +enum { + wxRE_READONLY, + wxRE_MULTILINE, + + wxRICHTEXT_SHIFT_DOWN, + wxRICHTEXT_CTRL_DOWN, + wxRICHTEXT_ALT_DOWN, + + wxRICHTEXT_SELECTED, + wxRICHTEXT_TAGGED, + wxRICHTEXT_FOCUSSED, + wxRICHTEXT_IS_FOCUS, + +}; + + +//--------------------------------------------------------------------------- + +MAKE_CONST_WXSTRING2(RichTextCtrlNameStr, wxT("richText")); + +MustHaveApp(wxRichTextCtrl); + + +DocStr(wxRichTextCtrl, +"", ""); + + +class wxRichTextCtrl : public wxScrolledWindow +{ +public: + %pythonAppend wxRichTextCtrl "self._setOORInfo(self)" + %pythonAppend wxRichTextCtrl() "" + + wxRichTextCtrl( wxWindow* parent, + wxWindowID id = -1, + const wxString& value = wxPyEmptyString, + const wxPoint& pos = wxDefaultPosition, + const wxSize& size = wxDefaultSize, + long style = wxRE_MULTILINE, + const wxValidator& validator = wxDefaultValidator, + const wxString& name = wxPyRichTextCtrlNameStr ); + %RenameCtor(PreRichTextCtrl, wxRichTextCtrl()); + + + bool Create( wxWindow* parent, + wxWindowID id = -1, + const wxString& value = wxPyEmptyString, + const wxPoint& pos = wxDefaultPosition, + const wxSize& size = wxDefaultSize, + long style = wxRE_MULTILINE, + const wxValidator& validator = wxDefaultValidator, + const wxString& name = wxPyRichTextCtrlNameStr ); + + + DocDeclStr( + virtual wxString , GetValue() const, + "", ""); + + DocDeclStr( + virtual void , SetValue(const wxString& value), + "", ""); + + + DocDeclStr( + virtual wxString , GetRange(long from, long to) const, + "", ""); + + + DocDeclStr( + virtual int , GetLineLength(long lineNo) const , + "", ""); + + DocDeclStr( + virtual wxString , GetLineText(long lineNo) const , + "", ""); + + DocDeclStr( + virtual int , GetNumberOfLines() const , + "", ""); + + + DocDeclStr( + virtual bool , IsModified() const , + "", ""); + + DocDeclStr( + virtual bool , IsEditable() const , + "", ""); + + + // more readable flag testing methods + DocDeclStr( + bool , IsSingleLine() const, + "", ""); + + DocDeclStr( + bool , IsMultiLine() const, + "", ""); + + + DocDeclAStr( + virtual void , GetSelection(long* OUTPUT, long* OUTPUT) const, + "GetSelection() --> (start, end)", + "Returns the start and end positions of the current selection. If the +values are the same then there is no selection.", ""); + + + DocDeclStr( + virtual wxString , GetStringSelection() const, + "", ""); + + + DocDeclStr( + wxString , GetFilename() const, + "", ""); + + + DocDeclStr( + void , SetFilename(const wxString& filename), + "", ""); + + + DocDeclStr( + void , SetDelayedLayoutThreshold(long threshold), + "Set the threshold in character positions for doing layout optimization +during sizing.", ""); + + + DocDeclStr( + long , GetDelayedLayoutThreshold() const, + "Get the threshold in character positions for doing layout optimization +during sizing.", ""); + + + + DocDeclStr( + virtual void , Clear(), + "", ""); + + DocDeclStr( + virtual void , Replace(long from, long to, const wxString& value), + "", ""); + + DocDeclStr( + virtual void , Remove(long from, long to), + "", ""); + + + DocDeclStr( + virtual bool , LoadFile(const wxString& file, int type = wxRICHTEXT_TYPE_ANY), + "Load the contents of the document from the given filename.", ""); + + DocDeclStr( + virtual bool , SaveFile(const wxString& file = wxPyEmptyString, + int type = wxRICHTEXT_TYPE_ANY), + "Save the contents of the document to the given filename, or if the +empty string is passed then to the filename set with `SetFilename`.", ""); + + + DocDeclStr( + void , SetHandlerFlags(int flags), + "Set the handler flags, controlling loading and saving.", ""); + + DocDeclStr( + int , GetHandlerFlags() const, + "Get the handler flags, controlling loading and saving.", ""); + + // sets/clears the dirty flag + DocDeclStr( + virtual void , MarkDirty(), + "Sets the dirty flag, meaning that the contents of the control have +changed and need to be saved.", ""); + + DocDeclStr( + virtual void , DiscardEdits(), + "Clears the dirty flag. +:see: `MarkDirty`", ""); + + + DocDeclStr( + virtual void , SetMaxLength(unsigned long len), + "Set the max number of characters which may be entered in a single line +text control.", ""); + + + DocDeclStr( + virtual void , WriteText(const wxString& text), + "Insert text at the current position.", ""); + + DocDeclStr( + virtual void , AppendText(const wxString& text), + "Append text to the end of the document.", ""); + + + DocDeclStr( + virtual bool , SetStyle(const wxRichTextRange& range, const wxRichTextAttr& style), + "Set the style for the text in ``range`` to ``style``", ""); + + DocDeclStr( + virtual bool , GetStyle(long position, wxRichTextAttr& style), + "Retrieve the style used at the given position. Copies the style +values at ``position`` into the ``style`` parameter and returns ``True`` +if successful. Returns ``False`` otherwise.", ""); + + + DocDeclStr( + virtual bool , GetStyleForRange(const wxRichTextRange& range, wxRichTextAttr& style), + "Get the common set of styles for the range", ""); + + + DocDeclStr( + virtual bool , SetStyleEx(const wxRichTextRange& range, const wxRichTextAttr& style, + int flags = wxRICHTEXT_SETSTYLE_WITH_UNDO), + "Extended style setting operation with flags including: +RICHTEXT_SETSTYLE_WITH_UNDO, RICHTEXT_SETSTYLE_OPTIMIZE, +RICHTEXT_SETSTYLE_PARAGRAPHS_ONLY, RICHTEXT_SETSTYLE_CHARACTERS_ONLY", ""); + + + + DocDeclStr( + virtual bool , GetUncombinedStyle(long position, wxRichTextAttr& style), + "Get the content (uncombined) attributes for this position. Copies the +style values at ``position`` into the ``style`` parameter and returns +``True`` if successful. Returns ``False`` otherwise.", ""); + + + DocDeclStr( + virtual bool , SetDefaultStyle(const wxRichTextAttr& style), + "Set the style used by default for the rich text document.", ""); + + + DocDeclStrName( + virtual const wxRichTextAttr , GetDefaultStyleEx() const, + "Retrieves a copy of the default style object.", "", + GetDefaultStyle); + + +// TODO: Select which of these to keep or rename + + /// Set list style +// virtual bool SetListStyle(const wxRichTextRange& range, +// wxRichTextListStyleDefinition* def, +// int flags = wxRICHTEXT_SETSTYLE_WITH_UNDO, +// int startFrom = 1, int specifiedLevel = -1); + virtual bool SetListStyle(const wxRichTextRange& range, + const wxString& defName, + int flags = wxRICHTEXT_SETSTYLE_WITH_UNDO, + int startFrom = 1, int specifiedLevel = -1); + + /// Clear list for given range + virtual bool ClearListStyle(const wxRichTextRange& range, int flags = wxRICHTEXT_SETSTYLE_WITH_UNDO); + + /// Number/renumber any list elements in the given range + /// def/defName can be NULL/empty to indicate that the existing list style should be used. +// virtual bool NumberList(const wxRichTextRange& range, +// wxRichTextListStyleDefinition* def = NULL, +// int flags = wxRICHTEXT_SETSTYLE_WITH_UNDO, +// int startFrom = 1, int specifiedLevel = -1); + virtual bool NumberList(const wxRichTextRange& range, + const wxString& defName, + int flags = wxRICHTEXT_SETSTYLE_WITH_UNDO, + int startFrom = 1, int specifiedLevel = -1); + + /// Promote the list items within the given range. promoteBy can be a positive or negative number, e.g. 1 or -1 + /// def/defName can be NULL/empty to indicate that the existing list style should be used. +// virtual bool PromoteList(int promoteBy, const wxRichTextRange& range, +// wxRichTextListStyleDefinition* def = NULL, +// int flags = wxRICHTEXT_SETSTYLE_WITH_UNDO, +// int specifiedLevel = -1); + virtual bool PromoteList(int promoteBy, const wxRichTextRange& range, + const wxString& defName, + int flags = wxRICHTEXT_SETSTYLE_WITH_UNDO, + int specifiedLevel = -1); + + /// Deletes the content in the given range + virtual bool Delete(const wxRichTextRange& range); + + + + + DocDeclStr( + virtual long , XYToPosition(long x, long y) const, + "Translate a col,row coordinants into a document position.", ""); + + DocDeclAStr( + virtual void , PositionToXY(long pos, long *OUTPUT, long *OUTPUT) const, + "PositionToXY(self, long pos) --> (x, y)", + "Retrieves the col,row for the given position within the document", ""); + + + DocDeclStr( + virtual void , ShowPosition(long position), + "Ensure that the given position in the document is visible.", ""); + + + DocDeclAStr( + virtual wxTextCtrlHitTestResult , HitTest(const wxPoint& pt, long *OUTPUT) const, + "HitTest(self, Point pt) --> (result, pos)", + "Returns the character position at the given point in pixels. Note +that ``pt`` should be given in device coordinates, and not be adjusted +for the client area origin nor for scrolling. The return value is a +tuple of the hit test result and the position.", " + +Possible result values are a bitmask of these flags: + + ========================= ==================================== + RICHTEXT_HITTEST_NONE The point was not on this object. + RICHTEXT_HITTEST_BEFORE The point was before the position + returned from HitTest. + RICHTEXT_HITTEST_AFTER The point was after the position + returned from HitTest. + RICHTEXT_HITTEST_ON The point was on the position + returned from HitTest + ========================= ==================================== +"); + + DocDeclAStrName( + virtual wxTextCtrlHitTestResult , HitTest(const wxPoint& pt, + wxTextCoord *OUTPUT, + wxTextCoord *OUTPUT) const, + "HitTestRC(self, Point pt) --> (result, col, row)", + "Returns the column and row of the given point in pixels. Note that +``pt`` should be given in device coordinates, and not be adjusted for +the client area origin nor for scrolling. The return value is a tuple +of the hit test result and the column and row values.", " +:see: `HitTest`", + HitTestXY); + + + // Clipboard operations + DocDeclStr( + virtual void , Copy(), + "Copies the selected text to the clipboard.", ""); + + DocDeclStr( + virtual void , Cut(), + "Copies the selected text to the clipboard and removes the selection.", ""); + + DocDeclStr( + virtual void , Paste(), + "Pastes text from the clipboard into the document at the current +insertion point.", ""); + + DocDeclStr( + virtual void , DeleteSelection(), + "Remove the current selection.", ""); + + + DocDeclStr( + virtual bool , CanCopy() const, + "Returns ``True`` if the selection can be copied to the clipboard.", ""); + + DocDeclStr( + virtual bool , CanCut() const, + "Returns ``True`` if the selection can be cut to the clipboard.", ""); + + DocDeclStr( + virtual bool , CanPaste() const, + "Returns ``True`` if the current contents of the clipboard can be +pasted into the document.", ""); + + DocDeclStr( + virtual bool , CanDeleteSelection() const, + "Returns ``True`` if the selection can be removed from the document.", ""); + + + // Undo/redo + DocDeclStr( + virtual void , Undo(), + "If the last operation can be undone, undoes the last operation.", ""); + + DocDeclStr( + virtual void , Redo(), + "If the last operation can be redone, redoes the last operation.", ""); + + + DocDeclStr( + virtual bool , CanUndo() const, + "Returns ``True`` if the last operation can be undone.", ""); + + DocDeclStr( + virtual bool , CanRedo() const, + "Returns ``True`` if the last operation can be redone.", ""); + + + // Insertion point + DocDeclStr( + virtual void , SetInsertionPoint(long pos), + "Sets the insertion point at the given position.", ""); + + DocDeclStr( + virtual void , SetInsertionPointEnd(), + "Moves the insertion point to the end of the document.", ""); + + DocDeclStr( + virtual long , GetInsertionPoint() const, + "Returns the insertion point. This is defined as the zero based index +of the character position to the right of the insertion point.", ""); + + DocDeclStr( + virtual long , GetLastPosition() const, + "Returns the zero based index of the last position in the document.", ""); + + + DocDeclStr( + virtual void , SetSelection(long from, long to), + "Selects the text starting at the first position up to (but not +including) the character at the last position. If both parameters are +equal to -1 then all text in the control is selected.", ""); + + DocDeclStr( + virtual void , SelectAll(), + "Select all text in the document.", ""); + + DocDeclStr( + virtual void , SetEditable(bool editable), + "Makes the document editable or read-only, overriding the RE_READONLY +flag.", ""); + + + DocDeclStr( + virtual bool , HasSelection() const, + "", ""); + + +///// Functionality specific to wxRichTextCtrl + + /// Write an image at the current insertion point. Supply optional type to use + /// for internal and file storage of the raw data. + DocDeclStr( + virtual bool , WriteImage(const wxImage& image, int bitmapType = wxBITMAP_TYPE_PNG), + "", ""); + + + /// Write a bitmap at the current insertion point. Supply optional type to use + /// for internal and file storage of the raw data. + DocDeclStrName( + virtual bool , WriteImage(const wxBitmap& bitmap, int bitmapType = wxBITMAP_TYPE_PNG), + "", "", + WriteBitmap); + + + /// Load an image from file and write at the current insertion point. + DocDeclStrName( + virtual bool , WriteImage(const wxString& filename, int bitmapType), + "", "", + WriteImageFile); + + + /// Write an image block at the current insertion point. + DocDeclStrName( + virtual bool , WriteImage(const wxRichTextImageBlock& imageBlock), + "", "", + WriteImageBlock); + + + /// Insert a newline (actually paragraph) at the current insertion point. + DocDeclStr( + virtual bool , Newline(), + "", ""); + + + /// Insert a line break at the current insertion point. + virtual bool LineBreak(); + + + DocDeclStr( + virtual void , SetBasicStyle(const wxRichTextAttr& style), + "", ""); + + + /// Get basic (overall) style + DocDeclStr( + virtual const wxRichTextAttr , GetBasicStyle() const, + "", ""); + + + /// Begin using a style + DocDeclStr( + virtual bool , BeginStyle(const wxRichTextAttr& style), + "", ""); + + + /// End the style + DocDeclStr( + virtual bool , EndStyle(), + "", ""); + + + /// End all styles + DocDeclStr( + virtual bool , EndAllStyles(), + "", ""); + + + /// Begin using bold + DocDeclStr( + bool , BeginBold(), + "", ""); + + + /// End using bold + DocDeclStr( + bool , EndBold(), + "", ""); + + + /// Begin using italic + DocDeclStr( + bool , BeginItalic(), + "", ""); + + + /// End using italic + DocDeclStr( + bool , EndItalic(), + "", ""); + + + /// Begin using underline + DocDeclStr( + bool , BeginUnderline(), + "", ""); + + + /// End using underline + DocDeclStr( + bool , EndUnderline(), + "", ""); + + + /// Begin using point size + DocDeclStr( + bool , BeginFontSize(int pointSize), + "", ""); + + + /// End using point size + DocDeclStr( + bool , EndFontSize(), + "", ""); + + + /// Begin using this font + DocDeclStr( + bool , BeginFont(const wxFont& font), + "", ""); + + + /// End using a font + DocDeclStr( + bool , EndFont(), + "", ""); + + + /// Begin using this colour + DocDeclStr( + bool , BeginTextColour(const wxColour& colour), + "", ""); + + + /// End using a colour + DocDeclStr( + bool , EndTextColour(), + "", ""); + + + /// Begin using alignment + DocDeclStr( + bool , BeginAlignment(wxTextAttrAlignment alignment), + "", ""); + + + /// End alignment + DocDeclStr( + bool , EndAlignment(), + "", ""); + + + /// Begin left indent + DocDeclStr( + bool , BeginLeftIndent(int leftIndent, int leftSubIndent = 0), + "", ""); + + + /// End left indent + DocDeclStr( + bool , EndLeftIndent(), + "", ""); + + + /// Begin right indent + DocDeclStr( + bool , BeginRightIndent(int rightIndent), + "", ""); + + + /// End right indent + DocDeclStr( + bool , EndRightIndent(), + "", ""); + + + /// Begin paragraph spacing + DocDeclStr( + bool , BeginParagraphSpacing(int before, int after), + "", ""); + + + /// End paragraph spacing + DocDeclStr( + bool , EndParagraphSpacing(), + "", ""); + + + /// Begin line spacing + DocDeclStr( + bool , BeginLineSpacing(int lineSpacing), + "", ""); + + + /// End line spacing + DocDeclStr( + bool , EndLineSpacing(), + "", ""); + + + /// Begin numbered bullet + DocDeclStr( + bool , BeginNumberedBullet(int bulletNumber, + int leftIndent, + int leftSubIndent, + int bulletStyle = wxTEXT_ATTR_BULLET_STYLE_ARABIC|wxTEXT_ATTR_BULLET_STYLE_PERIOD), + "", ""); + + + /// End numbered bullet + DocDeclStr( + bool , EndNumberedBullet(), + "", ""); + + + /// Begin symbol bullet + DocDeclStr( + bool , BeginSymbolBullet(const wxString& symbol, + int leftIndent, + int leftSubIndent, + int bulletStyle = wxTEXT_ATTR_BULLET_STYLE_SYMBOL), + "", ""); + + + /// End symbol bullet + DocDeclStr( + bool , EndSymbolBullet(), + "", ""); + + + /// Begin standard bullet + DocDeclStr( + bool , BeginStandardBullet(const wxString& bulletName, + int leftIndent, + int leftSubIndent, + int bulletStyle = wxTEXT_ATTR_BULLET_STYLE_STANDARD), + "", ""); + + + + /// End standard bullet + DocDeclStr( + bool , EndStandardBullet(), + "", ""); + + + /// Begin named character style + DocDeclStr( + bool , BeginCharacterStyle(const wxString& characterStyle), + "", ""); + + + /// End named character style + DocDeclStr( + bool , EndCharacterStyle(), + "", ""); + + + /// Begin named paragraph style + DocDeclStr( + bool , BeginParagraphStyle(const wxString& paragraphStyle), + "", ""); + + + /// End named character style + DocDeclStr( + bool , EndParagraphStyle(), + "", ""); + + + DocDeclStr( + bool , BeginListStyle(const wxString& listStyle, int level = 1, int number = 1), + "Begin named list style.", ""); + + DocDeclStr( + bool , EndListStyle(), "End named list style.", ""); + + DocDeclStr( + bool , BeginURL(const wxString& url, const wxString& characterStyle = wxEmptyString), + "Begin URL.", ""); + + DocDeclStr( + bool , EndURL(), "End URL.", ""); + + /// Sets the default style to the style under the cursor + DocDeclStr( + bool , SetDefaultStyleToCursorStyle(), + "", ""); + + + /// Clear the selection + DocDeclStr( + virtual void , SelectNone(), + "", ""); + + /// Select the word at the given character position + DocDeclStr( + virtual bool , SelectWord(long position), + "", ""); + + + /// Get/set the selection range in character positions. -1, -1 means no selection. + DocDeclStr( + wxRichTextRange , GetSelectionRange() const, + "", ""); + + DocDeclStr( + void , SetSelectionRange(const wxRichTextRange& range), + "", ""); + + /// Get/set the selection range in character positions. -1, -1 means no selection. + /// The range is in internal format, i.e. a single character selection is denoted + /// by (n, n) + DocDeclStr( + const wxRichTextRange& , GetInternalSelectionRange() const, + "", ""); + + DocDeclStr( + void , SetInternalSelectionRange(const wxRichTextRange& range), + "", ""); + + + + /// Add a new paragraph of text to the end of the buffer + DocDeclStr( + virtual wxRichTextRange , AddParagraph(const wxString& text), + "", ""); + + + /// Add an image + DocDeclStr( + virtual wxRichTextRange , AddImage(const wxImage& image), + "", ""); + + + /// Layout the buffer: which we must do before certain operations, such as + /// setting the caret position. + DocDeclStr( + virtual bool , LayoutContent(bool onlyVisibleRect = false), + "", ""); + + + /// Move the caret to the given character position + DocDeclStr( + virtual bool , MoveCaret(long pos, bool showAtLineStart = false), + "", ""); + + + /// Move right + DocDeclStr( + virtual bool , MoveRight(int noPositions = 1, int flags = 0), + "", ""); + + + /// Move left + DocDeclStr( + virtual bool , MoveLeft(int noPositions = 1, int flags = 0), + "", ""); + + + /// Move up + DocDeclStr( + virtual bool , MoveUp(int noLines = 1, int flags = 0), + "", ""); + + + /// Move up + DocDeclStr( + virtual bool , MoveDown(int noLines = 1, int flags = 0), + "", ""); + + + /// Move to the end of the line + DocDeclStr( + virtual bool , MoveToLineEnd(int flags = 0), + "", ""); + + + /// Move to the start of the line + DocDeclStr( + virtual bool , MoveToLineStart(int flags = 0), + "", ""); + + + /// Move to the end of the paragraph + DocDeclStr( + virtual bool , MoveToParagraphEnd(int flags = 0), + "", ""); + + + /// Move to the start of the paragraph + DocDeclStr( + virtual bool , MoveToParagraphStart(int flags = 0), + "", ""); + + + /// Move to the start of the buffer + DocDeclStr( + virtual bool , MoveHome(int flags = 0), + "", ""); + + + /// Move to the end of the buffer + DocDeclStr( + virtual bool , MoveEnd(int flags = 0), + "", ""); + + + /// Move n pages up + DocDeclStr( + virtual bool , PageUp(int noPages = 1, int flags = 0), + "", ""); + + + /// Move n pages down + DocDeclStr( + virtual bool , PageDown(int noPages = 1, int flags = 0), + "", ""); + + + /// Move n words left + DocDeclStr( + virtual bool , WordLeft(int noPages = 1, int flags = 0), + "", ""); + + + /// Move n words right + DocDeclStr( + virtual bool , WordRight(int noPages = 1, int flags = 0), + "", ""); + + + /// Returns the buffer associated with the control. + DocDeclStr( + wxRichTextBuffer& , GetBuffer(), + "", ""); + + + /// Start batching undo history for commands. + DocDeclStr( + virtual bool , BeginBatchUndo(const wxString& cmdName), + "", ""); + + + /// End batching undo history for commands. + DocDeclStr( + virtual bool , EndBatchUndo(), + "", ""); + + + /// Are we batching undo history for commands? + DocDeclStr( + virtual bool , BatchingUndo() const, + "", ""); + + + /// Start suppressing undo history for commands. + DocDeclStr( + virtual bool , BeginSuppressUndo(), + "", ""); + + + /// End suppressing undo history for commands. + DocDeclStr( + virtual bool , EndSuppressUndo(), + "", ""); + + + /// Are we suppressing undo history for commands? + DocDeclStr( + virtual bool , SuppressingUndo() const, + "", ""); + + + /// Test if this whole range has character attributes of the specified kind. If any + /// of the attributes are different within the range, the test fails. You + /// can use this to implement, for example, bold button updating. style must have + /// flags indicating which attributes are of interest. + DocDeclStr( + virtual bool , HasCharacterAttributes(const wxRichTextRange& range, + const wxRichTextAttr& style) const, + "", ""); + + + + /// Test if this whole range has paragraph attributes of the specified kind. If any + /// of the attributes are different within the range, the test fails. You + /// can use this to implement, for example, centering button updating. style must have + /// flags indicating which attributes are of interest. + DocDeclStr( + virtual bool , HasParagraphAttributes(const wxRichTextRange& range, + const wxRichTextAttr& style) const, + "", ""); + + + + /// Is all of the selection bold? + DocDeclStr( + virtual bool , IsSelectionBold(), + "", ""); + + + /// Is all of the selection italics? + DocDeclStr( + virtual bool , IsSelectionItalics(), + "", ""); + + + /// Is all of the selection underlined? + DocDeclStr( + virtual bool , IsSelectionUnderlined(), + "", ""); + + + /// Is all of the selection aligned according to the specified flag? + DocDeclStr( + virtual bool , IsSelectionAligned(wxTextAttrAlignment alignment), + "", ""); + + + /// Apply bold to the selection + DocDeclStr( + virtual bool , ApplyBoldToSelection(), + "", ""); + + + /// Apply italic to the selection + DocDeclStr( + virtual bool , ApplyItalicToSelection(), + "", ""); + + + /// Apply underline to the selection + DocDeclStr( + virtual bool , ApplyUnderlineToSelection(), + "", ""); + + + /// Apply alignment to the selection + DocDeclStr( + virtual bool , ApplyAlignmentToSelection(wxTextAttrAlignment alignment), + "", ""); + + + /// Apply a named style to the selection + virtual bool ApplyStyle(wxRichTextStyleDefinition* def); + + /// Set style sheet, if any. + DocDeclStr( + void , SetStyleSheet(wxRichTextStyleSheet* styleSheet), + "", ""); + + DocDeclStr( + wxRichTextStyleSheet* , GetStyleSheet() const, + "", ""); + + + /// Push style sheet to top of stack + bool PushStyleSheet(wxRichTextStyleSheet* styleSheet); + + + /// Pop style sheet from top of stack + wxRichTextStyleSheet* PopStyleSheet(); + + + /// Apply the style sheet to the buffer, for example if the styles have changed. + DocDeclStr( + bool , ApplyStyleSheet(wxRichTextStyleSheet* styleSheet = NULL), + "", ""); + + + + %property(Buffer, GetBuffer, doc="See `GetBuffer`"); + %property(DefaultStyle, GetDefaultStyle, SetDefaultStyle, doc="See `GetDefaultStyle` and `SetDefaultStyle`"); + %property(DelayedLayoutThreshold, GetDelayedLayoutThreshold, SetDelayedLayoutThreshold, doc="See `GetDelayedLayoutThreshold` and `SetDelayedLayoutThreshold`"); + %property(Filename, GetFilename, SetFilename, doc="See `GetFilename` and `SetFilename`"); + %property(InsertionPoint, GetInsertionPoint, SetInsertionPoint, doc="See `GetInsertionPoint` and `SetInsertionPoint`"); + %property(InternalSelectionRange, GetInternalSelectionRange, SetInternalSelectionRange, doc="See `GetInternalSelectionRange` and `SetInternalSelectionRange`"); + %property(LastPosition, GetLastPosition, doc="See `GetLastPosition`"); + %property(NumberOfLines, GetNumberOfLines, doc="See `GetNumberOfLines`"); + %property(Selection, GetSelection, SetSelectionRange, doc="See `GetSelection` and `SetSelection`"); + %property(SelectionRange, GetSelectionRange, SetSelectionRange, doc="See `GetSelectionRange` and `SetSelectionRange`"); + %property(StringSelection, GetStringSelection, doc="See `GetStringSelection`"); + %property(StyleSheet, GetStyleSheet, SetStyleSheet, doc="See `GetStyleSheet` and `SetStyleSheet`"); + %property(Value, GetValue, SetValue, doc="See `GetValue` and `SetValue`"); + + + + // TODO: Some of these methods may be useful too... + + +// /// Set up scrollbars, e.g. after a resize +// virtual void SetupScrollbars(bool atTop = false); + +// /// Keyboard navigation +// virtual bool KeyboardNavigate(int keyCode, int flags); + +// /// Paint the background +// virtual void PaintBackground(wxDC& dc); + +// #if wxRICHTEXT_BUFFERED_PAINTING +// /// Recreate buffer bitmap if necessary +// virtual bool RecreateBuffer(const wxSize& size = wxDefaultSize); +// #endif + +// /// Set the selection +// virtual void DoSetSelection(long from, long to, bool scrollCaret = true); + +// /// Write text +// virtual void DoWriteText(const wxString& value, int flags = 0); + +// /// Should we inherit colours? +// virtual bool ShouldInheritColours() const { return false; } + +// /// Position the caret +// virtual void PositionCaret(); + +// /// Extend the selection, returning true if the selection was +// /// changed. Selections are in caret positions. +// virtual bool ExtendSelection(long oldPosition, long newPosition, int flags); + +// /// Scroll into view. This takes a _caret_ position. +// virtual bool ScrollIntoView(long position, int keyCode); + +// /// The caret position is the character position just before the caret. +// /// A value of -1 means the caret is at the start of the buffer. +// void SetCaretPosition(long position, bool showAtLineStart = false) ; +// long GetCaretPosition() const { return m_caretPosition; } + +// /// The adjusted caret position is the character position adjusted to take +// /// into account whether we're at the start of a paragraph, in which case +// /// style information should be taken from the next position, not current one. +// long GetAdjustedCaretPosition(long caretPos) const; + +// /// Move caret one visual step forward: this may mean setting a flag +// /// and keeping the same position if we're going from the end of one line +// /// to the start of the next, which may be the exact same caret position. +// void MoveCaretForward(long oldPosition) ; + +// /// Move caret one visual step forward: this may mean setting a flag +// /// and keeping the same position if we're going from the end of one line +// /// to the start of the next, which may be the exact same caret position. +// void MoveCaretBack(long oldPosition) ; + +// /// Get the caret height and position for the given character position +// bool GetCaretPositionForIndex(long position, wxRect& rect); + +// /// Gets the line for the visible caret position. If the caret is +// /// shown at the very end of the line, it means the next character is actually +// /// on the following line. So let's get the line we're expecting to find +// /// if this is the case. +// wxRichTextLine* GetVisibleLineForCaretPosition(long caretPosition) const; + +// /// Gets the command processor +// wxCommandProcessor* GetCommandProcessor() const { return GetBuffer().GetCommandProcessor(); } + +// /// Delete content if there is a selection, e.g. when pressing a key. +// /// Returns the new caret position in newPos, or leaves it if there +// /// was no action. +// bool DeleteSelectedContent(long* newPos= NULL); + +// /// Transform logical to physical +// wxPoint GetPhysicalPoint(const wxPoint& ptLogical) const; + +// /// Transform physical to logical +// wxPoint GetLogicalPoint(const wxPoint& ptPhysical) const; + +// /// Finds the caret position for the next word. Direction +// /// is 1 (forward) or -1 (backwards). +// virtual long FindNextWordPosition(int direction = 1) const; + +// /// Is the given position visible on the screen? +// bool IsPositionVisible(long pos) const; + +// /// Returns the first visible position in the current view +// long GetFirstVisiblePosition() const; + +// /// Returns the caret position since the default formatting was changed. As +// /// soon as this position changes, we no longer reflect the default style +// /// in the UI. A value of -2 means that we should only reflect the style of the +// /// content under the caret. +// long GetCaretPositionForDefaultStyle() const { return m_caretPositionForDefaultStyle; } + +// /// Set the caret position for the default style that the user is selecting. +// void SetCaretPositionForDefaultStyle(long pos) { m_caretPositionForDefaultStyle = pos; } + +// /// Should the UI reflect the default style chosen by the user, rather than the style under +// /// the caret? +// bool IsDefaultStyleShowing() const { return m_caretPositionForDefaultStyle != -2; } + +// /// Convenience function that tells the control to start reflecting the default +// /// style, since the user is changing it. +// void SetAndShowDefaultStyle(const wxRichTextAttr& attr) +// { +// SetDefaultStyle(attr); +// SetCaretPositionForDefaultStyle(GetCaretPosition()); +// } + +// /// Get the first visible point in the window +// wxPoint GetFirstVisiblePoint() const; + +// // Implementation + +// /// Font names take a long time to retrieve, so cache them (on demand) +// static const wxArrayString& GetAvailableFontNames(); +// static void ClearAvailableFontNames(); + +}; + + +//--------------------------------------------------------------------------- +%newgroup + + +%constant wxEventType wxEVT_COMMAND_RICHTEXT_LEFT_CLICK; +%constant wxEventType wxEVT_COMMAND_RICHTEXT_RIGHT_CLICK; +%constant wxEventType wxEVT_COMMAND_RICHTEXT_MIDDLE_CLICK; +%constant wxEventType wxEVT_COMMAND_RICHTEXT_LEFT_DCLICK; +%constant wxEventType wxEVT_COMMAND_RICHTEXT_RETURN; +%constant wxEventType wxEVT_COMMAND_RICHTEXT_CHARACTER; +%constant wxEventType wxEVT_COMMAND_RICHTEXT_DELETE; + +%constant wxEventType wxEVT_COMMAND_RICHTEXT_STYLESHEET_CHANGING; +%constant wxEventType wxEVT_COMMAND_RICHTEXT_STYLESHEET_CHANGED; +%constant wxEventType wxEVT_COMMAND_RICHTEXT_STYLESHEET_REPLACING; +%constant wxEventType wxEVT_COMMAND_RICHTEXT_STYLESHEET_REPLACED; + +%constant wxEventType wxEVT_COMMAND_RICHTEXT_CONTENT_INSERTED; +%constant wxEventType wxEVT_COMMAND_RICHTEXT_CONTENT_DELETED; +%constant wxEventType wxEVT_COMMAND_RICHTEXT_STYLE_CHANGED; +%constant wxEventType wxEVT_COMMAND_RICHTEXT_SELECTION_CHANGED; + +%pythoncode { +EVT_RICHTEXT_LEFT_CLICK = wx.PyEventBinder(wxEVT_COMMAND_RICHTEXT_LEFT_CLICK, 1) +EVT_RICHTEXT_RIGHT_CLICK = wx.PyEventBinder(wxEVT_COMMAND_RICHTEXT_RIGHT_CLICK, 1) +EVT_RICHTEXT_MIDDLE_CLICK = wx.PyEventBinder(wxEVT_COMMAND_RICHTEXT_MIDDLE_CLICK, 1) +EVT_RICHTEXT_LEFT_DCLICK = wx.PyEventBinder(wxEVT_COMMAND_RICHTEXT_LEFT_DCLICK, 1) +EVT_RICHTEXT_RETURN = wx.PyEventBinder( wxEVT_COMMAND_RICHTEXT_RETURN, 1) +EVT_RICHTEXT_CHARACTER = wx.PyEventBinder( wxEVT_COMMAND_RICHTEXT_CHARACTER, 1) +EVT_RICHTEXT_DELETE = wx.PyEventBinder( wxEVT_COMMAND_RICHTEXT_DELETE, 1) + +EVT_RICHTEXT_STYLESHEET_CHANGING = wx.PyEventBinder( wxEVT_COMMAND_RICHTEXT_STYLESHEET_CHANGING, 1) +EVT_RICHTEXT_STYLESHEET_CHANGED = wx.PyEventBinder( wxEVT_COMMAND_RICHTEXT_STYLESHEET_CHANGED, 1) +EVT_RICHTEXT_STYLESHEET_REPLACING = wx.PyEventBinder( wxEVT_COMMAND_RICHTEXT_STYLESHEET_REPLACING, 1) +EVT_RICHTEXT_STYLESHEET_REPLACED = wx.PyEventBinder( wxEVT_COMMAND_RICHTEXT_STYLESHEET_REPLACED, 1) + +EVT_RICHTEXT_CONTENT_INSERTED = wx.PyEventBinder( wxEVT_COMMAND_RICHTEXT_CONTENT_INSERTED, 1) +EVT_RICHTEXT_CONTENT_DELETED = wx.PyEventBinder( wxEVT_COMMAND_RICHTEXT_CONTENT_DELETED, 1) +EVT_RICHTEXT_STYLE_CHANGED = wx.PyEventBinder( wxEVT_COMMAND_RICHTEXT_STYLE_CHANGED, 1) +EVT_RICHTEXT_SELECTION_CHANGED = wx.PyEventBinder( wxEVT_COMMAND_RICHTEXT_SELECTION_CHANGED, 1) +} + + +class wxRichTextEvent : public wxNotifyEvent +{ +public: + wxRichTextEvent(wxEventType commandType = wxEVT_NULL, int winid = 0); + + int GetPosition() const; + void SetPosition(int n); + + int GetFlags() const; + void SetFlags(int flags); + + wxRichTextStyleSheet* GetOldStyleSheet() const; + void SetOldStyleSheet(wxRichTextStyleSheet* sheet); + + wxRichTextStyleSheet* GetNewStyleSheet() const; + void SetNewStyleSheet(wxRichTextStyleSheet* sheet); + + const wxRichTextRange& GetRange() const; + void SetRange(const wxRichTextRange& range); + + wxChar GetCharacter() const; + void SetCharacter(wxChar ch); + + + %property(Flags, GetFlags, SetFlags); + %property(Index, GetPosition, SetPosition); + %property(OldStyleSheet, GetOldStyleSheet, SetOldStyleSheet); + %property(NewStyleSheet, GetNewStyleSheet, SetNewStyleSheet); + %property(Range, GetRange, SetRange); + %property(Character, GetCharacter, SetCharacter); +}; + + +//--------------------------------------------------------------------------- diff --git a/wxPython/src/_richtexthtml.i b/wxPython/src/_richtexthtml.i new file mode 100644 index 0000000000..0cd93849bd --- /dev/null +++ b/wxPython/src/_richtexthtml.i @@ -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 +%} + +//--------------------------------------------------------------------------- +%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); + +}; + +//--------------------------------------------------------------------------- diff --git a/wxPython/src/_richtextxml.i b/wxPython/src/_richtextxml.i new file mode 100644 index 0000000000..09ac9928c1 --- /dev/null +++ b/wxPython/src/_richtextxml.i @@ -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 +%} + +//--------------------------------------------------------------------------- +%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); + +}; + +//--------------------------------------------------------------------------- diff --git a/wxPython/src/_sizers.i b/wxPython/src/_sizers.i index 24dab87eed..8f6d3b0147 100644 --- a/wxPython/src/_sizers.i +++ b/wxPython/src/_sizers.i @@ -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,20 +1252,11 @@ 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, diff --git a/wxPython/src/_stdpaths.i b/wxPython/src/_stdpaths.i index 8a9a73e216..fdb80b5423 100644 --- a/wxPython/src/_stdpaths.i +++ b/wxPython/src/_stdpaths.i @@ -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( diff --git a/wxPython/src/_streams.i b/wxPython/src/_streams.i index a918d91470..d5ef145ae1 100644 --- a/wxPython/src/_streams.i +++ b/wxPython/src/_streams.i @@ -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"); %} //--------------------------------------------------------------------------- diff --git a/wxPython/src/_window.i b/wxPython/src/_window.i index ab8acd6b55..878e421ccd 100644 --- a/wxPython/src/_window.i +++ b/wxPython/src/_window.i @@ -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; } %} diff --git a/wxPython/src/aui.i b/wxPython/src/aui.i index 815e8f0b4e..3e82c2226c 100755 --- a/wxPython/src/aui.i +++ b/wxPython/src/aui.i @@ -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. diff --git a/wxPython/src/combo.i b/wxPython/src/combo.i index 33c70d7387..b75afd8724 100644 --- a/wxPython/src/combo.i +++ b/wxPython/src/combo.i @@ -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 diff --git a/wxPython/src/helpers.cpp b/wxPython/src/helpers.cpp index a99061c732..41b3c33a5d 100644 --- a/wxPython/src/helpers.cpp +++ b/wxPython/src/helpers.cpp @@ -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); diff --git a/wxPython/src/my_typemaps.i b/wxPython/src/my_typemaps.i index 958ac1eac5..6b98d1dd7e 100644 --- a/wxPython/src/my_typemaps.i +++ b/wxPython/src/my_typemaps.i @@ -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; diff --git a/wxPython/src/richtext.i b/wxPython/src/richtext.i index 87a22da1bd..3b3165b267 100644 --- a/wxPython/src/richtext.i +++ b/wxPython/src/richtext.i @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////// // Name: richtext.i -// Purpose: Classes for wxRichTExtCtrl and support classes +// Purpose: Classes for wxRichTextCtrl and support classes // // Author: Robin Dunn // @@ -39,7 +39,6 @@ class wxPrinterDC; //---------------------------------------------------------------------- %import windows.i -// ?? %import gdi.i %pythoncode { wx = _core } %pythoncode { __docfilter__ = wx.__DocFilter(globals()) } @@ -48,91 +47,7 @@ MAKE_CONST_WXSTRING_NOSWIG(EmptyString); //---------------------------------------------------------------------- -enum { - wxRE_READONLY, - wxRE_MULTILINE, - - wxRICHTEXT_SHIFT_DOWN, - wxRICHTEXT_CTRL_DOWN, - wxRICHTEXT_ALT_DOWN, - - wxRICHTEXT_SELECTED, - wxRICHTEXT_TAGGED, - wxRICHTEXT_FOCUSSED, - wxRICHTEXT_IS_FOCUS, - - wxRICHTEXT_TYPE_ANY, - wxRICHTEXT_TYPE_TEXT, - wxRICHTEXT_TYPE_XML, - wxRICHTEXT_TYPE_HTML, - wxRICHTEXT_TYPE_RTF, - wxRICHTEXT_TYPE_PDF, - - wxRICHTEXT_FIXED_WIDTH, - wxRICHTEXT_FIXED_HEIGHT, - wxRICHTEXT_VARIABLE_WIDTH, - wxRICHTEXT_VARIABLE_HEIGHT, - - - wxRICHTEXT_HITTEST_NONE, - wxRICHTEXT_HITTEST_BEFORE, - wxRICHTEXT_HITTEST_AFTER, - wxRICHTEXT_HITTEST_ON, - - wxRICHTEXT_FORMATTED, - wxRICHTEXT_UNFORMATTED, - - wxRICHTEXT_SETSTYLE_NONE, - wxRICHTEXT_SETSTYLE_WITH_UNDO, - wxRICHTEXT_SETSTYLE_OPTIMIZE, - wxRICHTEXT_SETSTYLE_PARAGRAPHS_ONLY, - wxRICHTEXT_SETSTYLE_CHARACTERS_ONLY, - - wxRICHTEXT_INSERT_NONE, - wxRICHTEXT_INSERT_WITH_PREVIOUS_PARAGRAPH_STYLE, - - - - // TODO: Rename these to be wxRICHTEXT_* ?? - - wxTEXT_ATTR_TEXT_COLOUR, - wxTEXT_ATTR_BACKGROUND_COLOUR, - wxTEXT_ATTR_FONT_FACE, - wxTEXT_ATTR_FONT_SIZE, - wxTEXT_ATTR_FONT_WEIGHT, - wxTEXT_ATTR_FONT_ITALIC, - wxTEXT_ATTR_FONT_UNDERLINE, - wxTEXT_ATTR_FONT, - wxTEXT_ATTR_ALIGNMENT, - wxTEXT_ATTR_LEFT_INDENT, - wxTEXT_ATTR_RIGHT_INDENT, - wxTEXT_ATTR_TABS, - - wxTEXT_ATTR_PARA_SPACING_AFTER, - wxTEXT_ATTR_PARA_SPACING_BEFORE, - wxTEXT_ATTR_LINE_SPACING, - wxTEXT_ATTR_CHARACTER_STYLE_NAME, - wxTEXT_ATTR_PARAGRAPH_STYLE_NAME, - wxTEXT_ATTR_BULLET_STYLE, - wxTEXT_ATTR_BULLET_NUMBER, - - wxTEXT_ATTR_BULLET_STYLE_NONE, - wxTEXT_ATTR_BULLET_STYLE_ARABIC, - wxTEXT_ATTR_BULLET_STYLE_LETTERS_UPPER, - wxTEXT_ATTR_BULLET_STYLE_LETTERS_LOWER, - wxTEXT_ATTR_BULLET_STYLE_ROMAN_UPPER, - wxTEXT_ATTR_BULLET_STYLE_ROMAN_LOWER, - wxTEXT_ATTR_BULLET_STYLE_SYMBOL, - wxTEXT_ATTR_BULLET_STYLE_BITMAP, - wxTEXT_ATTR_BULLET_STYLE_PARENTHESES, - wxTEXT_ATTR_BULLET_STYLE_PERIOD, - - wxTEXT_ATTR_LINE_SPACING_NORMAL, - wxTEXT_ATTR_LINE_SPACING_HALF, - wxTEXT_ATTR_LINE_SPACING_TWICE, - -}; - +// TODO: These are already defined in _textctrl.i, do we really need them here? enum wxTextAttrAlignment { wxTEXT_ALIGNMENT_DEFAULT, @@ -145,1427 +60,10 @@ enum wxTextAttrAlignment //---------------------------------------------------------------------- -%typemap(in) wxRichTextRange& (wxRichTextRange temp) { - $1 = &temp; - if ( ! wxRichTextRange_helper($input, &$1)) SWIG_fail; -} -%typemap(typecheck, precedence=SWIG_TYPECHECK_POINTER) wxRichTextRange& { - $1 = wxPySimple_typecheck($input, wxT("wxRichTextRange"), 2); -} - - -%{ - -bool wxRichTextRange_helper(PyObject* source, wxRichTextRange** obj) -{ - if (source == Py_None) { - **obj = wxRICHTEXT_NONE; - return true; - } - return wxPyTwoIntItem_helper(source, obj, wxT("wxRichTextRange")); -} -%} - - - -DocStr(wxRichTextRange, -"RichTextRange is a data structure that represents a range of text -within a `RichTextCtrl`. It simply contains integer ``start`` and -``end`` properties and a few operations useful for dealing with -ranges. In most places in wxPython where a RichTextRange is expected a -2-tuple containing (start, end) can be used instead.", ""); - -class wxRichTextRange -{ -public: - DocCtorStr( - wxRichTextRange(long start=0, long end=0), - "Creates a new range object.", ""); - - ~wxRichTextRange(); - - %extend { - KeepGIL(__eq__); - DocStr(__eq__, "Test for equality of RichTextRange objects.", ""); - bool __eq__(PyObject* other) { - wxRichTextRange temp, *obj = &temp; - if ( other == Py_None ) return false; - if ( ! wxRichTextRange_helper(other, &obj) ) { - PyErr_Clear(); - return false; - } - return self->operator==(*obj); - } - } - - - DocDeclStr( - wxRichTextRange , operator -(const wxRichTextRange& range) const, - "", ""); - - DocDeclStr( - wxRichTextRange , operator +(const wxRichTextRange& range) const, - "", ""); - - - DocDeclStr( - void , SetRange(long start, long end), - "", ""); - - - DocDeclStr( - void , SetStart(long start), - "", ""); - - DocDeclStr( - long , GetStart() const, - "", ""); - - %pythoncode { start = property(GetStart, SetStart) } - - DocDeclStr( - void , SetEnd(long end), - "", ""); - - DocDeclStr( - long , GetEnd() const, - "", ""); - - %pythoncode { end = property(GetEnd, SetEnd) } - - - DocDeclStr( - bool , IsOutside(const wxRichTextRange& range) const, - "Returns true if this range is completely outside 'range'", ""); - - - DocDeclStr( - bool , IsWithin(const wxRichTextRange& range) const, - "Returns true if this range is completely within 'range'", ""); - - - DocDeclStr( - bool , Contains(long pos) const, - "Returns true if the given position is within this range. Allow for the -possibility of an empty range - assume the position is within this -empty range.", ""); - - - DocDeclStr( - bool , LimitTo(const wxRichTextRange& range) , - "Limit this range to be within 'range'", ""); - - - DocDeclStr( - long , GetLength() const, - "Gets the length of the range", ""); - - - DocDeclStr( - void , Swap(), - "Swaps the start and end", ""); - - - %extend { - DocAStr(Get, - "Get() -> (start,end)", - "Returns the start and end properties as a tuple.", ""); - PyObject* Get() { - wxPyBlock_t blocked = wxPyBeginBlockThreads(); - PyObject* tup = PyTuple_New(2); - PyTuple_SET_ITEM(tup, 0, PyInt_FromLong(self->GetStart())); - PyTuple_SET_ITEM(tup, 1, PyInt_FromLong(self->GetEnd())); - wxPyEndBlockThreads(blocked); - return tup; - } - } - %pythoncode { - def __str__(self): return str(self.Get()) - def __repr__(self): return 'RichTextRange'+str(self.Get()) - def __len__(self): return len(self.Get()) - def __getitem__(self, index): return self.Get()[index] - def __setitem__(self, index, val): - if index == 0: self.start = val - elif index == 1: self.end = val - else: raise IndexError - def __nonzero__(self): return self.Get() != (0,0) - __safe_for_unpickling__ = True - def __reduce__(self): return (RichTextRange, self.Get()) - } - - %property(End, GetEnd, SetEnd, doc="See `GetEnd` and `SetEnd`"); - %property(Length, GetLength, doc="See `GetLength`"); - %property(Start, GetStart, SetStart, doc="See `GetStart` and `SetStart`"); -}; - - - -%{ - wxRichTextRange wxPy_RTR_ALL(wxRICHTEXT_ALL); - wxRichTextRange wxPy_RTR_NONE(wxRICHTEXT_NONE); -%} - -%rename(RICHTEXT_ALL) wxPy_RTR_ALL; -%rename(RICHTEXT_NONE) wxPy_RTR_NONE; - -%immutable; -wxRichTextRange wxPy_RTR_ALL; -wxRichTextRange wxPy_RTR_NONE; -%mutable; - -//---------------------------------------------------------------------- - -DocStr(wxRichTextAttr, -"The RichTextAttr class stored information about the various attributes -for a block of text, including font, colour, indents, alignments, and -etc.", ""); - -class wxRichTextAttr -{ -public: - - wxRichTextAttr(const wxColour& colText = wxNullColour, - const wxColour& colBack = wxNullColour, - wxTextAttrAlignment alignment = wxTEXT_ALIGNMENT_DEFAULT); - - ~wxRichTextAttr(); - -// // Making a wxTextAttrEx object. -// operator wxTextAttrEx () const ; - -// // Copy to a wxTextAttr -// void CopyTo(wxTextAttrEx& attr) const; - - - - // Create font from font attributes. - DocDeclStr( - wxFont , CreateFont() const, - "", ""); - - - // Get attributes from font. - bool GetFontAttributes(const wxFont& font); - - %pythoncode { - def GetFont(self): - return self.CreateFont() - def SetFont(self, font): - return self.GetFontAttributes(font) - } - - // setters - void SetTextColour(const wxColour& colText); - void SetBackgroundColour(const wxColour& colBack); - void SetAlignment(wxTextAttrAlignment alignment); - void SetTabs(const wxArrayInt& tabs); - void SetLeftIndent(int indent, int subIndent = 0); - void SetRightIndent(int indent); - - void SetFontSize(int pointSize); - void SetFontStyle(int fontStyle); - void SetFontWeight(int fontWeight); - void SetFontFaceName(const wxString& faceName); - void SetFontUnderlined(bool underlined); - - void SetFlags(long flags); - - void SetCharacterStyleName(const wxString& name); - void SetParagraphStyleName(const wxString& name); - void SetParagraphSpacingAfter(int spacing); - void SetParagraphSpacingBefore(int spacing); - void SetLineSpacing(int spacing); - void SetBulletStyle(int style); - void SetBulletNumber(int n); - void SetBulletText(wxChar symbol); - void SetBulletFont(const wxString& bulletFont); - - const wxColour& GetTextColour() const; - const wxColour& GetBackgroundColour() const; - wxTextAttrAlignment GetAlignment() const; - const wxArrayInt& GetTabs() const; - long GetLeftIndent() const; - long GetLeftSubIndent() const; - long GetRightIndent() const; - long GetFlags() const; - - int GetFontSize() const; - int GetFontStyle() const; - int GetFontWeight() const; - bool GetFontUnderlined() const; - const wxString& GetFontFaceName() const; - - const wxString& GetCharacterStyleName() const; - const wxString& GetParagraphStyleName() const; - int GetParagraphSpacingAfter() const; - int GetParagraphSpacingBefore() const; - int GetLineSpacing() const; - int GetBulletStyle() const; - int GetBulletNumber() const; - const wxString& GetBulletText() const; - const wxString& GetBulletFont() const; - - // accessors - bool HasTextColour() const; - bool HasBackgroundColour() const; - bool HasAlignment() const; - bool HasTabs() const; - bool HasLeftIndent() const; - bool HasRightIndent() const; -// bool HasWeight() const; -// bool HasSize() const; -// bool HasItalic() const; -// bool HasUnderlined() const; -// bool HasFaceName() const; - bool HasFont() const; - - bool HasParagraphSpacingAfter() const; - bool HasParagraphSpacingBefore() const; - bool HasLineSpacing() const; - bool HasCharacterStyleName() const; - bool HasParagraphStyleName() const; - bool HasBulletStyle() const; - bool HasBulletNumber() const; - bool HasBulletText() const; - - bool HasFlag(long flag) const; - - // Is this a character style? - bool IsCharacterStyle() const; - bool IsParagraphStyle() const; - - // returns false if we have any attributes set, true otherwise - bool IsDefault() const; - - -// // return the attribute having the valid font and colours: it uses the -// // attributes set in attr and falls back first to attrDefault and then to -// // the text control font/colours for those attributes which are not set -// static wxRichTextAttr Combine(const wxRichTextAttr& attr, -// const wxRichTextAttr& attrDef, -// const wxTextCtrlBase *text); - - - %property(Alignment, GetAlignment, SetAlignment, doc="See `GetAlignment` and `SetAlignment`"); - %property(BackgroundColour, GetBackgroundColour, SetBackgroundColour, doc="See `GetBackgroundColour` and `SetBackgroundColour`"); - %property(BulletFont, GetBulletFont, SetBulletFont, doc="See `GetBulletFont` and `SetBulletFont`"); - %property(BulletNumber, GetBulletNumber, SetBulletNumber, doc="See `GetBulletNumber` and `SetBulletNumber`"); - %property(BulletStyle, GetBulletStyle, SetBulletStyle, doc="See `GetBulletStyle` and `SetBulletStyle`"); - %property(BulletText, GetBulletText, SetBulletText, doc="See `GetBulletText` and `SetBulletText`"); - %property(CharacterStyleName, GetCharacterStyleName, SetCharacterStyleName, doc="See `GetCharacterStyleName` and `SetCharacterStyleName`"); - %property(Flags, GetFlags, SetFlags, doc="See `GetFlags` and `SetFlags`"); - %property(Font, GetFont, SetFont, doc="See `GetFont` and `SetFont`"); - %property(FontAttributes, GetFontAttributes, doc="See `GetFontAttributes`"); - %property(FontFaceName, GetFontFaceName, SetFontFaceName, doc="See `GetFontFaceName` and `SetFontFaceName`"); - %property(FontSize, GetFontSize, SetFontSize, doc="See `GetFontSize` and `SetFontSize`"); - %property(FontStyle, GetFontStyle, SetFontStyle, doc="See `GetFontStyle` and `SetFontStyle`"); - %property(FontUnderlined, GetFontUnderlined, SetFontUnderlined, doc="See `GetFontUnderlined` and `SetFontUnderlined`"); - %property(FontWeight, GetFontWeight, SetFontWeight, doc="See `GetFontWeight` and `SetFontWeight`"); - %property(LeftIndent, GetLeftIndent, SetLeftIndent, doc="See `GetLeftIndent` and `SetLeftIndent`"); - %property(LeftSubIndent, GetLeftSubIndent, doc="See `GetLeftSubIndent`"); - %property(LineSpacing, GetLineSpacing, SetLineSpacing, doc="See `GetLineSpacing` and `SetLineSpacing`"); - %property(ParagraphSpacingAfter, GetParagraphSpacingAfter, SetParagraphSpacingAfter, doc="See `GetParagraphSpacingAfter` and `SetParagraphSpacingAfter`"); - %property(ParagraphSpacingBefore, GetParagraphSpacingBefore, SetParagraphSpacingBefore, doc="See `GetParagraphSpacingBefore` and `SetParagraphSpacingBefore`"); - %property(ParagraphStyleName, GetParagraphStyleName, SetParagraphStyleName, doc="See `GetParagraphStyleName` and `SetParagraphStyleName`"); - %property(RightIndent, GetRightIndent, SetRightIndent, doc="See `GetRightIndent` and `SetRightIndent`"); - %property(Tabs, GetTabs, SetTabs, doc="See `GetTabs` and `SetTabs`"); - %property(TextColour, GetTextColour, SetTextColour, doc="See `GetTextColour` and `SetTextColour`"); -}; - - -enum { - wxTEXT_ATTR_CHARACTER, - wxTEXT_ATTR_PARAGRAPH, - wxTEXT_ATTR_ALL -}; - - -//---------------------------------------------------------------------- -//---------------------------------------------------------------------- - -MustHaveApp(wxRichTextCtrl); -DocStr(wxRichTextCtrl, -"", ""); - -class wxRichTextCtrl : public wxScrolledWindow -{ -public: - %pythonAppend wxRichTextCtrl "self._setOORInfo(self)" - %pythonAppend wxRichTextCtrl() "" - - wxRichTextCtrl( wxWindow* parent, - wxWindowID id = -1, - const wxString& value = wxPyEmptyString, - const wxPoint& pos = wxDefaultPosition, - const wxSize& size = wxDefaultSize, - long style = wxRE_MULTILINE ); - %RenameCtor(PreRichTextCtrl, wxRichTextCtrl()); - - - bool Create( wxWindow* parent, - wxWindowID id = -1, - const wxString& value = wxPyEmptyString, - const wxPoint& pos = wxDefaultPosition, - const wxSize& size = wxDefaultSize, - long style = wxRE_MULTILINE ); - - - DocDeclStr( - virtual wxString , GetValue() const, - "", ""); - - DocDeclStr( - virtual void , SetValue(const wxString& value), - "", ""); - - - DocDeclStr( - virtual wxString , GetRange(long from, long to) const, - "", ""); - - - DocDeclStr( - virtual int , GetLineLength(long lineNo) const , - "", ""); - - DocDeclStr( - virtual wxString , GetLineText(long lineNo) const , - "", ""); - - DocDeclStr( - virtual int , GetNumberOfLines() const , - "", ""); - - - DocDeclStr( - virtual bool , IsModified() const , - "", ""); - - DocDeclStr( - virtual bool , IsEditable() const , - "", ""); - - - // more readable flag testing methods - DocDeclStr( - bool , IsSingleLine() const, - "", ""); - - DocDeclStr( - bool , IsMultiLine() const, - "", ""); - - - DocDeclAStr( - virtual void , GetSelection(long* OUTPUT, long* OUTPUT) const, - "GetSelection() --> (start, end)", - "Returns the start and end positions of the current selection. If the -values are the same then there is no selection.", ""); - - - DocDeclStr( - virtual wxString , GetStringSelection() const, - "", ""); - - - DocDeclStr( - wxString , GetFilename() const, - "", ""); - - - DocDeclStr( - void , SetFilename(const wxString& filename), - "", ""); - - - DocDeclStr( - void , SetDelayedLayoutThreshold(long threshold), - "Set the threshold in character positions for doing layout optimization -during sizing.", ""); - - - DocDeclStr( - long , GetDelayedLayoutThreshold() const, - "Get the threshold in character positions for doing layout optimization -during sizing.", ""); - - - - DocDeclStr( - virtual void , Clear(), - "", ""); - - DocDeclStr( - virtual void , Replace(long from, long to, const wxString& value), - "", ""); - - DocDeclStr( - virtual void , Remove(long from, long to), - "", ""); - - - DocDeclStr( - virtual bool , LoadFile(const wxString& file, int type = wxRICHTEXT_TYPE_ANY), - "Load the contents of the document from the given filename.", ""); - - DocDeclStr( - virtual bool , SaveFile(const wxString& file = wxPyEmptyString, - int type = wxRICHTEXT_TYPE_ANY), - "Save the contents of the document to the given filename, or if the -empty string is passed then to the filename set with `SetFilename`.", ""); - - - DocDeclStr( - void , SetHandlerFlags(int flags), - "Set the handler flags, controlling loading and saving.", ""); - - DocDeclStr( - int , GetHandlerFlags() const, - "Get the handler flags, controlling loading and saving.", ""); - - // sets/clears the dirty flag - DocDeclStr( - virtual void , MarkDirty(), - "Sets the dirty flag, meaning that the contents of the control have -changed and need to be saved.", ""); - - DocDeclStr( - virtual void , DiscardEdits(), - "Clears the dirty flag. -:see: `MarkDirty`", ""); - - - DocDeclStr( - virtual void , SetMaxLength(unsigned long len), - "Set the max number of characters which may be entered in a single line -text control.", ""); - - - DocDeclStr( - virtual void , WriteText(const wxString& text), - "Insert text at the current position.", ""); - - DocDeclStr( - virtual void , AppendText(const wxString& text), - "Append text to the end of the document.", ""); - - - DocDeclStr( - virtual bool , SetStyle(const wxRichTextRange& range, const wxRichTextAttr& style), - "Set the style for the text in ``range`` to ``style``", ""); - - DocDeclStr( - virtual bool , SetStyleEx(const wxRichTextRange& range, const wxRichTextAttr& style, - int flags = wxRICHTEXT_SETSTYLE_WITH_UNDO), - "Extended style setting operation with flags including: -RICHTEXT_SETSTYLE_WITH_UNDO, RICHTEXT_SETSTYLE_OPTIMIZE, -RICHTEXT_SETSTYLE_PARAGRAPHS_ONLY, RICHTEXT_SETSTYLE_CHARACTERS_ONLY", ""); - - - - DocDeclStr( - virtual bool , GetStyle(long position, wxRichTextAttr& style), - "Retrieve the style used at the given position. Copies the style -values at ``position`` into the ``style`` parameter and returns ``True`` -if successful. Returns ``False`` otherwise.", ""); - - DocDeclStr( - virtual bool , GetUncombinedStyle(long position, wxRichTextAttr& style), - "Get the content (uncombined) attributes for this position. Copies the -style values at ``position`` into the ``style`` parameter and returns -``True`` if successful. Returns ``False`` otherwise.", ""); - - - DocDeclStr( - virtual bool , SetDefaultStyle(const wxRichTextAttr& style), - "Set the style used by default for the rich text document.", ""); - - - DocDeclStrName( - virtual const wxRichTextAttr , GetDefaultStyleEx() const, - "Retrieves a copy of the default style object.", "", - GetDefaultStyle); - - - DocDeclStr( - virtual long , XYToPosition(long x, long y) const, - "Translate a col,row coordinants into a document position.", ""); - - DocDeclAStr( - virtual void , PositionToXY(long pos, long *OUTPUT, long *OUTPUT) const, - "PositionToXY(self, long pos) --> (x, y)", - "Retrieves the col,row for the given position within the document", ""); - - - DocDeclStr( - virtual void , ShowPosition(long position), - "Ensure that the given position in the document is visible.", ""); - - - DocDeclAStr( - virtual wxTextCtrlHitTestResult , HitTest(const wxPoint& pt, long *OUTPUT) const, - "HitTest(self, Point pt) --> (result, pos)", - "Returns the character position at the given point in pixels. Note -that ``pt`` should be given in device coordinates, and not be adjusted -for the client area origin nor for scrolling. The return value is a -tuple of the hit test result and the position.", " - -Possible result values are a bitmask of these flags: - - ========================= ==================================== - RICHTEXT_HITTEST_NONE The point was not on this object. - RICHTEXT_HITTEST_BEFORE The point was before the position - returned from HitTest. - RICHTEXT_HITTEST_AFTER The point was after the position - returned from HitTest. - RICHTEXT_HITTEST_ON The point was on the position - returned from HitTest - ========================= ==================================== -"); - - DocDeclAStrName( - virtual wxTextCtrlHitTestResult , HitTest(const wxPoint& pt, - wxTextCoord *OUTPUT, - wxTextCoord *OUTPUT) const, - "HitTestRC(self, Point pt) --> (result, col, row)", - "Returns the column and row of the given point in pixels. Note that -``pt`` should be given in device coordinates, and not be adjusted for -the client area origin nor for scrolling. The return value is a tuple -of the hit test result and the column and row values.", " -:see: `HitTest`", - HitTestXY); - - - // Clipboard operations - DocDeclStr( - virtual void , Copy(), - "Copies the selected text to the clipboard.", ""); - - DocDeclStr( - virtual void , Cut(), - "Copies the selected text to the clipboard and removes the selection.", ""); - - DocDeclStr( - virtual void , Paste(), - "Pastes text from the clipboard into the document at the current -insertion point.", ""); - - DocDeclStr( - virtual void , DeleteSelection(), - "Remove the current selection.", ""); - - - DocDeclStr( - virtual bool , CanCopy() const, - "Returns ``True`` if the selection can be copied to the clipboard.", ""); - - DocDeclStr( - virtual bool , CanCut() const, - "Returns ``True`` if the selection can be cut to the clipboard.", ""); - - DocDeclStr( - virtual bool , CanPaste() const, - "Returns ``True`` if the current contents of the clipboard can be -pasted into the document.", ""); - - DocDeclStr( - virtual bool , CanDeleteSelection() const, - "Returns ``True`` if the selection can be removed from the document.", ""); - - - // Undo/redo - DocDeclStr( - virtual void , Undo(), - "If the last operation can be undone, undoes the last operation.", ""); - - DocDeclStr( - virtual void , Redo(), - "If the last operation can be redone, redoes the last operation.", ""); - - - DocDeclStr( - virtual bool , CanUndo() const, - "Returns ``True`` if the last operation can be undone.", ""); - - DocDeclStr( - virtual bool , CanRedo() const, - "Returns ``True`` if the last operation can be redone.", ""); - - - // Insertion point - DocDeclStr( - virtual void , SetInsertionPoint(long pos), - "Sets the insertion point at the given position.", ""); - - DocDeclStr( - virtual void , SetInsertionPointEnd(), - "Moves the insertion point to the end of the document.", ""); - - DocDeclStr( - virtual long , GetInsertionPoint() const, - "Returns the insertion point. This is defined as the zero based index -of the character position to the right of the insertion point.", ""); - - DocDeclStr( - virtual long , GetLastPosition() const, - "Returns the zero based index of the last position in the document.", ""); - - - DocDeclStr( - virtual void , SetSelection(long from, long to), - "Selects the text starting at the first position up to (but not -including) the character at the last position. If both parameters are -equal to -1 then all text in the control is selected.", ""); - - DocDeclStr( - virtual void , SelectAll(), - "Select all text in the document.", ""); - - DocDeclStr( - virtual void , SetEditable(bool editable), - "Makes the document editable or read-only, overriding the RE_READONLY -flag.", ""); - - -// /// Call Freeze to prevent refresh -// virtual void Freeze(); - -// /// Call Thaw to refresh -// virtual void Thaw(); - -// /// Call Thaw to refresh -// DocDeclStr( -// virtual bool , IsFrozen() const, -// "", ""); - - - DocDeclStr( - virtual bool , HasSelection() const, - "", ""); - - -///// Functionality specific to wxRichTextCtrl - - /// Write an image at the current insertion point. Supply optional type to use - /// for internal and file storage of the raw data. - DocDeclStr( - virtual bool , WriteImage(const wxImage& image, int bitmapType = wxBITMAP_TYPE_PNG), - "", ""); - - - /// Write a bitmap at the current insertion point. Supply optional type to use - /// for internal and file storage of the raw data. - DocDeclStrName( - virtual bool , WriteImage(const wxBitmap& bitmap, int bitmapType = wxBITMAP_TYPE_PNG), - "", "", - WriteBitmap); - - - /// Load an image from file and write at the current insertion point. - DocDeclStrName( - virtual bool , WriteImage(const wxString& filename, int bitmapType), - "", "", - WriteImageFile); - - - /// Write an image block at the current insertion point. - DocDeclStrName( - virtual bool , WriteImage(const wxRichTextImageBlock& imageBlock), - "", "", - WriteImageBlock); - - - /// Insert a newline (actually paragraph) at the current insertion point. - DocDeclStr( - virtual bool , Newline(), - "", ""); - - -#if USE_TEXTATTREX -/// Set basic (overall) style - DocDeclStr( - virtual void , SetBasicStyle(const wxTextAttrEx& style), - "", ""); -#endif - - DocDeclStr( - virtual void , SetBasicStyle(const wxRichTextAttr& style), - "", ""); - - -#if USE_TEXTATTREX - /// Get basic (overall) style - DocDeclStr( - virtual const wxTextAttrEx& , GetBasicStyle() const, - "", ""); - - - /// Begin using a style - DocDeclStr( - virtual bool , BeginStyle(const wxTextAttrEx& style), - "", ""); -#endif - - /// End the style - DocDeclStr( - virtual bool , EndStyle(), - "", ""); - - - /// End all styles - DocDeclStr( - virtual bool , EndAllStyles(), - "", ""); - - - /// Begin using bold - DocDeclStr( - bool , BeginBold(), - "", ""); - - - /// End using bold - DocDeclStr( - bool , EndBold(), - "", ""); - - - /// Begin using italic - DocDeclStr( - bool , BeginItalic(), - "", ""); - - - /// End using italic - DocDeclStr( - bool , EndItalic(), - "", ""); - - - /// Begin using underline - DocDeclStr( - bool , BeginUnderline(), - "", ""); - - - /// End using underline - DocDeclStr( - bool , EndUnderline(), - "", ""); - - - /// Begin using point size - DocDeclStr( - bool , BeginFontSize(int pointSize), - "", ""); - - - /// End using point size - DocDeclStr( - bool , EndFontSize(), - "", ""); - - - /// Begin using this font - DocDeclStr( - bool , BeginFont(const wxFont& font), - "", ""); - - - /// End using a font - DocDeclStr( - bool , EndFont(), - "", ""); - - - /// Begin using this colour - DocDeclStr( - bool , BeginTextColour(const wxColour& colour), - "", ""); - - - /// End using a colour - DocDeclStr( - bool , EndTextColour(), - "", ""); - - - /// Begin using alignment - DocDeclStr( - bool , BeginAlignment(wxTextAttrAlignment alignment), - "", ""); - - - /// End alignment - DocDeclStr( - bool , EndAlignment(), - "", ""); - - - /// Begin left indent - DocDeclStr( - bool , BeginLeftIndent(int leftIndent, int leftSubIndent = 0), - "", ""); - - - /// End left indent - DocDeclStr( - bool , EndLeftIndent(), - "", ""); - - - /// Begin right indent - DocDeclStr( - bool , BeginRightIndent(int rightIndent), - "", ""); - - - /// End right indent - DocDeclStr( - bool , EndRightIndent(), - "", ""); - - - /// Begin paragraph spacing - DocDeclStr( - bool , BeginParagraphSpacing(int before, int after), - "", ""); - - - /// End paragraph spacing - DocDeclStr( - bool , EndParagraphSpacing(), - "", ""); - - - /// Begin line spacing - DocDeclStr( - bool , BeginLineSpacing(int lineSpacing), - "", ""); - - - /// End line spacing - DocDeclStr( - bool , EndLineSpacing(), - "", ""); - - - /// Begin numbered bullet - DocDeclStr( - bool , BeginNumberedBullet(int bulletNumber, - int leftIndent, - int leftSubIndent, - int bulletStyle = wxTEXT_ATTR_BULLET_STYLE_ARABIC|wxTEXT_ATTR_BULLET_STYLE_PERIOD), - "", ""); - - - /// End numbered bullet - DocDeclStr( - bool , EndNumberedBullet(), - "", ""); - - - /// Begin symbol bullet - DocDeclStr( - bool , BeginSymbolBullet(const wxString& symbol, - int leftIndent, - int leftSubIndent, - int bulletStyle = wxTEXT_ATTR_BULLET_STYLE_SYMBOL), - "", ""); - - - /// End symbol bullet - DocDeclStr( - bool , EndSymbolBullet(), - "", ""); - - - /// Begin named character style - DocDeclStr( - bool , BeginCharacterStyle(const wxString& characterStyle), - "", ""); - - - /// End named character style - DocDeclStr( - bool , EndCharacterStyle(), - "", ""); - - - /// Begin named paragraph style - DocDeclStr( - bool , BeginParagraphStyle(const wxString& paragraphStyle), - "", ""); - - - /// End named character style - DocDeclStr( - bool , EndParagraphStyle(), - "", ""); - - - DocDeclStr( - bool , BeginListStyle(const wxString& listStyle, int level = 1, int number = 1), - "Begin named list style.", ""); - - DocDeclStr( - bool , EndListStyle(), "End named list style.", ""); - - DocDeclStr( - bool , BeginURL(const wxString& url, const wxString& characterStyle = wxEmptyString), - "Begin URL.", ""); - - DocDeclStr( - bool , EndURL(), "End URL.", ""); - - /// Sets the default style to the style under the cursor - DocDeclStr( - bool , SetDefaultStyleToCursorStyle(), - "", ""); - - - /// Clear the selection - DocDeclStr( - virtual void , SelectNone(), - "", ""); - - /// Select the word at the given character position - DocDeclStr( - virtual bool , SelectWord(long position), - "", ""); - - - /// Get/set the selection range in character positions. -1, -1 means no selection. - DocDeclStr( - wxRichTextRange , GetSelectionRange() const, - "", ""); - - DocDeclStr( - void , SetSelectionRange(const wxRichTextRange& range), - "", ""); - - /// Get/set the selection range in character positions. -1, -1 means no selection. - /// The range is in internal format, i.e. a single character selection is denoted - /// by (n, n) - DocDeclStr( - const wxRichTextRange& , GetInternalSelectionRange() const, - "", ""); - - DocDeclStr( - void , SetInternalSelectionRange(const wxRichTextRange& range), - "", ""); - - - - /// Add a new paragraph of text to the end of the buffer - DocDeclStr( - virtual wxRichTextRange , AddParagraph(const wxString& text), - "", ""); - - - /// Add an image - DocDeclStr( - virtual wxRichTextRange , AddImage(const wxImage& image), - "", ""); - - - /// Layout the buffer: which we must do before certain operations, such as - /// setting the caret position. - DocDeclStr( - virtual bool , LayoutContent(bool onlyVisibleRect = false), - "", ""); - - - /// Move the caret to the given character position - DocDeclStr( - virtual bool , MoveCaret(long pos, bool showAtLineStart = false), - "", ""); - - - /// Move right - DocDeclStr( - virtual bool , MoveRight(int noPositions = 1, int flags = 0), - "", ""); - - - /// Move left - DocDeclStr( - virtual bool , MoveLeft(int noPositions = 1, int flags = 0), - "", ""); - - - /// Move up - DocDeclStr( - virtual bool , MoveUp(int noLines = 1, int flags = 0), - "", ""); - - - /// Move up - DocDeclStr( - virtual bool , MoveDown(int noLines = 1, int flags = 0), - "", ""); - - - /// Move to the end of the line - DocDeclStr( - virtual bool , MoveToLineEnd(int flags = 0), - "", ""); - - - /// Move to the start of the line - DocDeclStr( - virtual bool , MoveToLineStart(int flags = 0), - "", ""); - - - /// Move to the end of the paragraph - DocDeclStr( - virtual bool , MoveToParagraphEnd(int flags = 0), - "", ""); - - - /// Move to the start of the paragraph - DocDeclStr( - virtual bool , MoveToParagraphStart(int flags = 0), - "", ""); - - - /// Move to the start of the buffer - DocDeclStr( - virtual bool , MoveHome(int flags = 0), - "", ""); - - - /// Move to the end of the buffer - DocDeclStr( - virtual bool , MoveEnd(int flags = 0), - "", ""); - - - /// Move n pages up - DocDeclStr( - virtual bool , PageUp(int noPages = 1, int flags = 0), - "", ""); - - - /// Move n pages down - DocDeclStr( - virtual bool , PageDown(int noPages = 1, int flags = 0), - "", ""); - - - /// Move n words left - DocDeclStr( - virtual bool , WordLeft(int noPages = 1, int flags = 0), - "", ""); - - - /// Move n words right - DocDeclStr( - virtual bool , WordRight(int noPages = 1, int flags = 0), - "", ""); - - - /// Returns the buffer associated with the control. -// wxRichTextBuffer& GetBuffer(); - DocDeclStr( - const wxRichTextBuffer& , GetBuffer() const, - "", ""); - - - /// Start batching undo history for commands. - DocDeclStr( - virtual bool , BeginBatchUndo(const wxString& cmdName), - "", ""); - - - /// End batching undo history for commands. - DocDeclStr( - virtual bool , EndBatchUndo(), - "", ""); - - - /// Are we batching undo history for commands? - DocDeclStr( - virtual bool , BatchingUndo() const, - "", ""); - - - /// Start suppressing undo history for commands. - DocDeclStr( - virtual bool , BeginSuppressUndo(), - "", ""); - - - /// End suppressing undo history for commands. - DocDeclStr( - virtual bool , EndSuppressUndo(), - "", ""); - - - /// Are we suppressing undo history for commands? - DocDeclStr( - virtual bool , SuppressingUndo() const, - "", ""); - - - /// Test if this whole range has character attributes of the specified kind. If any - /// of the attributes are different within the range, the test fails. You - /// can use this to implement, for example, bold button updating. style must have - /// flags indicating which attributes are of interest. -#if USE_TEXTATTREX - DocDeclStr( - virtual bool , HasCharacterAttributes(const wxRichTextRange& range, - const wxTextAttrEx& style) const, - "", ""); -#endif - - DocDeclStr( - virtual bool , HasCharacterAttributes(const wxRichTextRange& range, - const wxRichTextAttr& style) const, - "", ""); - - - - /// Test if this whole range has paragraph attributes of the specified kind. If any - /// of the attributes are different within the range, the test fails. You - /// can use this to implement, for example, centering button updating. style must have - /// flags indicating which attributes are of interest. -#if USE_TEXTATTREX - DocDeclStr( - virtual bool , HasParagraphAttributes(const wxRichTextRange& range, - const wxTextAttrEx& style) const, - "", ""); -#endif - - DocDeclStr( - virtual bool , HasParagraphAttributes(const wxRichTextRange& range, - const wxRichTextAttr& style) const, - "", ""); - - - - /// Is all of the selection bold? - DocDeclStr( - virtual bool , IsSelectionBold(), - "", ""); - - - /// Is all of the selection italics? - DocDeclStr( - virtual bool , IsSelectionItalics(), - "", ""); - - - /// Is all of the selection underlined? - DocDeclStr( - virtual bool , IsSelectionUnderlined(), - "", ""); - - - /// Is all of the selection aligned according to the specified flag? - DocDeclStr( - virtual bool , IsSelectionAligned(wxTextAttrAlignment alignment), - "", ""); - - - /// Apply bold to the selection - DocDeclStr( - virtual bool , ApplyBoldToSelection(), - "", ""); - - - /// Apply italic to the selection - DocDeclStr( - virtual bool , ApplyItalicToSelection(), - "", ""); - - - /// Apply underline to the selection - DocDeclStr( - virtual bool , ApplyUnderlineToSelection(), - "", ""); - - - /// Apply alignment to the selection - DocDeclStr( - virtual bool , ApplyAlignmentToSelection(wxTextAttrAlignment alignment), - "", ""); - - - /// Set style sheet, if any. - DocDeclStr( - void , SetStyleSheet(wxRichTextStyleSheet* styleSheet), - "", ""); - - DocDeclStr( - wxRichTextStyleSheet* , GetStyleSheet() const, - "", ""); - - /// Apply the style sheet to the buffer, for example if the styles have changed. - DocDeclStr( - bool , ApplyStyleSheet(wxRichTextStyleSheet* styleSheet = NULL), - "", ""); - - - - %property(Buffer, GetBuffer, doc="See `GetBuffer`"); - %property(DefaultStyle, GetDefaultStyle, SetDefaultStyle, doc="See `GetDefaultStyle` and `SetDefaultStyle`"); - %property(DelayedLayoutThreshold, GetDelayedLayoutThreshold, SetDelayedLayoutThreshold, doc="See `GetDelayedLayoutThreshold` and `SetDelayedLayoutThreshold`"); - %property(Filename, GetFilename, SetFilename, doc="See `GetFilename` and `SetFilename`"); - %property(InsertionPoint, GetInsertionPoint, SetInsertionPoint, doc="See `GetInsertionPoint` and `SetInsertionPoint`"); - %property(InternalSelectionRange, GetInternalSelectionRange, SetInternalSelectionRange, doc="See `GetInternalSelectionRange` and `SetInternalSelectionRange`"); - %property(LastPosition, GetLastPosition, doc="See `GetLastPosition`"); - %property(NumberOfLines, GetNumberOfLines, doc="See `GetNumberOfLines`"); - %property(Selection, GetSelection, SetSelectionRange, doc="See `GetSelection` and `SetSelection`"); - %property(SelectionRange, GetSelectionRange, SetSelectionRange, doc="See `GetSelectionRange` and `SetSelectionRange`"); - %property(StringSelection, GetStringSelection, doc="See `GetStringSelection`"); - %property(StyleSheet, GetStyleSheet, SetStyleSheet, doc="See `GetStyleSheet` and `SetStyleSheet`"); - %property(Value, GetValue, SetValue, doc="See `GetValue` and `SetValue`"); - -// Implementation -// TODO: Which of these should be exposed to Python? - -// /// Set font, and also default attributes -// virtual bool SetFont(const wxFont& font); - -// /// Set up scrollbars, e.g. after a resize -// virtual void SetupScrollbars(bool atTop = false); - -// /// Keyboard navigation -// virtual bool KeyboardNavigate(int keyCode, int flags); - -// /// Paint the background -// virtual void PaintBackground(wxDC& dc); - -// /// Recreate buffer bitmap if necessary -// virtual bool RecreateBuffer(const wxSize& size = wxDefaultSize); - -// /// Set the selection -// virtual void DoSetSelection(long from, long to, bool scrollCaret = true); - -// /// Write text -// virtual void DoWriteText(const wxString& value, bool selectionOnly = true); - -// /// Send an update event -// virtual bool SendUpdateEvent(); - -// /// Init command event -// void InitCommandEvent(wxCommandEvent& event) const; - -// /// do the window-specific processing after processing the update event -// // (duplicated code from wxTextCtrlBase) -// #if !wxRICHTEXT_DERIVES_FROM_TEXTCTRLBASE -// virtual void DoUpdateWindowUI(wxUpdateUIEvent& event); -// #endif - -// /// Should we inherit colours? -// virtual bool ShouldInheritColours() const; - -// /// Position the caret -// virtual void PositionCaret(); - -// /// Extend the selection, returning true if the selection was -// /// changed. Selections are in caret positions. -// virtual bool ExtendSelection(long oldPosition, long newPosition, int flags); - -// /// Scroll into view. This takes a _caret_ position. -// virtual bool ScrollIntoView(long position, int keyCode); - -// /// The caret position is the character position just before the caret. -// /// A value of -1 means the caret is at the start of the buffer. -// void SetCaretPosition(long position, bool showAtLineStart = false) ; -// long GetCaretPosition() const; - -// /// Move caret one visual step forward: this may mean setting a flag -// /// and keeping the same position if we're going from the end of one line -// /// to the start of the next, which may be the exact same caret position. -// void MoveCaretForward(long oldPosition) ; - -// /// Move caret one visual step forward: this may mean setting a flag -// /// and keeping the same position if we're going from the end of one line -// /// to the start of the next, which may be the exact same caret position. -// void MoveCaretBack(long oldPosition) ; - -// /// Get the caret height and position for the given character position -// bool GetCaretPositionForIndex(long position, wxRect& rect); - -// /// Gets the line for the visible caret position. If the caret is -// /// shown at the very end of the line, it means the next character is actually -// /// on the following line. So let's get the line we're expecting to find -// /// if this is the case. -// wxRichTextLine* GetVisibleLineForCaretPosition(long caretPosition) const; - -// /// Gets the command processor -// wxCommandProcessor* GetCommandProcessor() const; - -// /// Delete content if there is a selection, e.g. when pressing a key. -// /// Returns the new caret position in newPos, or leaves it if there -// /// was no action. -// bool DeleteSelectedContent(long* newPos= NULL); - -// /// Transform logical to physical -// wxPoint GetPhysicalPoint(const wxPoint& ptLogical) const; - -// /// Transform physical to logical -// wxPoint GetLogicalPoint(const wxPoint& ptPhysical) const; - -// /// Finds the caret position for the next word. Direction -// /// is 1 (forward) or -1 (backwards). -// virtual long FindNextWordPosition(int direction = 1) const; - -// /// Is the given position visible on the screen? -// bool IsPositionVisible(long pos) const; - -// /// Returns the first visible position in the current view -// long GetFirstVisiblePosition() const; -}; - - -//---------------------------------------------------------------------- - - -%constant wxEventType wxEVT_COMMAND_RICHTEXT_LEFT_CLICK; -%constant wxEventType wxEVT_COMMAND_RICHTEXT_RIGHT_CLICK; -%constant wxEventType wxEVT_COMMAND_RICHTEXT_MIDDLE_CLICK; -%constant wxEventType wxEVT_COMMAND_RICHTEXT_LEFT_DCLICK; -%constant wxEventType wxEVT_COMMAND_RICHTEXT_RETURN; -%constant wxEventType wxEVT_COMMAND_RICHTEXT_STYLESHEET_CHANGING; -%constant wxEventType wxEVT_COMMAND_RICHTEXT_STYLESHEET_CHANGED; -%constant wxEventType wxEVT_COMMAND_RICHTEXT_STYLESHEET_REPLACING; -%constant wxEventType wxEVT_COMMAND_RICHTEXT_STYLESHEET_REPLACED; -%constant wxEventType wxEVT_COMMAND_RICHTEXT_CHARACTER; -%constant wxEventType wxEVT_COMMAND_RICHTEXT_DELETE; - -%pythoncode { -EVT_RICHTEXT_LEFT_CLICK = wx.PyEventBinder(wxEVT_COMMAND_RICHTEXT_LEFT_CLICK, 1) -EVT_RICHTEXT_RIGHT_CLICK = wx.PyEventBinder(wxEVT_COMMAND_RICHTEXT_RIGHT_CLICK, 1) -EVT_RICHTEXT_MIDDLE_CLICK = wx.PyEventBinder(wxEVT_COMMAND_RICHTEXT_MIDDLE_CLICK, 1) -EVT_RICHTEXT_LEFT_DCLICK = wx.PyEventBinder(wxEVT_COMMAND_RICHTEXT_LEFT_DCLICK, 1) -EVT_RICHTEXT_RETURN = wx.PyEventBinder( wxEVT_COMMAND_RICHTEXT_RETURN, 1) -EVT_RICHTEXT_STYLESHEET_CHANGING = wx.PyEventBinder( wxEVT_COMMAND_RICHTEXT_STYLESHEET_CHANGING, 1) -EVT_RICHTEXT_STYLESHEET_CHANGED = wx.PyEventBinder( wxEVT_COMMAND_RICHTEXT_STYLESHEET_CHANGED, 1) -EVT_RICHTEXT_STYLESHEET_REPLACING = wx.PyEventBinder( wxEVT_COMMAND_RICHTEXT_STYLESHEET_REPLACING, 1) -EVT_RICHTEXT_STYLESHEET_REPLACED = wx.PyEventBinder( wxEVT_COMMAND_RICHTEXT_STYLESHEET_REPLACED, 1) -EVT_RICHTEXT_CHARACTER = wx.PyEventBinder( wxEVT_COMMAND_RICHTEXT_CHARACTER, 1) -EVT_RICHTEXT_DELETE = wx.PyEventBinder( wxEVT_COMMAND_RICHTEXT_DELETE, 1) -} - - -class wxRichTextEvent : public wxNotifyEvent -{ -public: - wxRichTextEvent(wxEventType commandType = wxEVT_NULL, int winid = 0); - - int GetPosition() const; - void SetPosition(int n); - - int GetFlags() const; - void SetFlags(int flags); - - %property(Flags, GetFlags, SetFlags, doc="See `GetFlags` and `SetFlags`"); - %property(Index, GetPosition, SetPosition, doc="See `GetPosition` and `SetPosition`"); -}; +%include _richtextbuffer.i +%include _richtextctrl.i +%include _richtexthtml.i +%include _richtextxml.i //---------------------------------------------------------------------- diff --git a/wxPython/wx/lib/buttonpanel.py b/wxPython/wx/lib/buttonpanel.py index 703474a94b..d47b9c9482 100644 --- a/wxPython/wx/lib/buttonpanel.py +++ b/wxPython/wx/lib/buttonpanel.py @@ -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} diff --git a/wxPython/wx/lib/colourselect.py b/wxPython/wx/lib/colourselect.py index 5edba11b67..4c39ece648 100644 --- a/wxPython/wx/lib/colourselect.py +++ b/wxPython/wx/lib/colourselect.py @@ -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() diff --git a/wxPython/wx/lib/flatnotebook.py b/wxPython/wx/lib/flatnotebook.py index 7b259ad4f7..f0915d1bec 100644 --- a/wxPython/wx/lib/flatnotebook.py +++ b/wxPython/wx/lib/flatnotebook.py @@ -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) diff --git a/wxPython/wx/lib/imagebrowser.py b/wxPython/wx/lib/imagebrowser.py index 72b1346d53..a9297794f6 100644 --- a/wxPython/wx/lib/imagebrowser.py +++ b/wxPython/wx/lib/imagebrowser.py @@ -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 GetCheckeredBitmap(blocksize=8,ntiles=4,rgb0='\xFF', rgb1='\xCC'): + """Creates a square RGB checkered bitmap using the two specified colors. -def GetSize(file_nm): # for scaling image values - image = ConvertBMP(file_nm) - bmp = image.ConvertToBitmap() - size = bmp.GetWidth(), bmp.GetHeight() - return size + 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 - def DrawImage(self, dc): - try: - image = self.image - except: - return + 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() - self.DrawBorder(dc) + def OnSize(self, event): + event.Skip() + self.Refresh() - if image is None: + 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 - try: - bmp = image.ConvertToBitmap() - except: + 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): + + if not hasattr(self,'image') or self.image is None: return - iwidth = bmp.GetWidth() # dimensions of image file - iheight = bmp.GetHeight() + 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() - 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 + # squeeze iwidth x iheight image into window, preserving aspect ratio - 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 + xfactor = float(wwidth) / iwidth + yfactor = float(wheight) / iheight - image.Rescale(iwidth, iheight) # rescale to fit the window - image.ConvertToBitmap() - bmp = image.ConvertToBitmap() - dc.DrawBitmap(bmp, diffx, diffy) # draw the image to window + if xfactor < 1.0 and xfactor < yfactor: + scale = xfactor + elif yfactor < 1.0 and yfactor < xfactor: + scale = yfactor + else: + scale = 1.0 + owidth = int(scale*iwidth) + oheight = int(scale*iheight) -class ImageDialog(wx.Dialog): - def __init__(self, parent, set_dir = None): - wx.Dialog.__init__(self, parent, -1, "Image Browser", wx.DefaultPosition, (400, 400)) + 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) - self.x_pos = 30 # initial display positions - self.y_pos = 20 - self.delta = 20 + 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) - size = wx.Size(80, -1) + 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) + + + +class ImageDialog(wx.Dialog): + def __init__(self, parent, set_dir = None): + 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) + + hbox_loc = wx.BoxSizer(wx.HORIZONTAL) + vbox_top.Add(hbox_loc, 0, wx.GROW|wx.ALIGN_LEFT|wx.ALL, 0) - self.y_pos = self.y_pos + self.delta + 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) - btn = wx.Button(self, 12331, ' Set Directory ', (self.x_pos, self.y_pos)) - self.Bind(wx.EVT_BUTTON, self.SetDirect, btn) + 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) - self.type_posy = self.y_pos # save the y position for the image type combo + 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) + + 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) - # 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.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" - ] - - self.fl_ext_types = { - "All Images": "All", - "Bmp": "*.bmp", - "Gif": "*.gif", - "Png": "*.png", - "Jpg": "*.jpg", - "Ico": "*.ico", - "Pnm": "*.pnm", - "Pcx": "*.pcx", - "Tif": "*.tif", - "All Files": "*.*" - } - - self.set_type = self.fl_types[0] # initial file filter setting - self.fl_ext = self.fl_ext_types[self.set_type] - - 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) - self.image_view = ImageView( self, pos=(image_posx, image_posy), - size=(image_sizex, image_sizey)) + 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.y_pos = self.y_pos + height + 20 + self.image_view = ImagePanel( split_right ) + vbox_right.Add(self.image_view, 1, wx.GROW|wx.ALL, 0) - btn = wx.Button(self, -1, ' Select ', (100, self.y_pos), size) - self.Bind(wx.EVT_BUTTON, self.OnOk, btn) + splitter.SplitVertically(split_left, split_right, 150) + vbox_top.Add(splitter, 1, wx.GROW|wx.ALL, 5) - wx.Button(self, wx.ID_CANCEL, 'Cancel', (250, self.y_pos), size) + hbox_btns = wx.BoxSizer(wx.HORIZONTAL) + vbox_top.Add(hbox_btns, 0, wx.ALIGN_RIGHT|wx.ALL, 5) - self.y_pos = self.y_pos + self.delta - fsize = (400, self.y_pos + 50) # resize dialog for final vertical position - self.SetSize(fsize) + 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) + + 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) - - -def OnFileDlg(self): - dlg = wx.FileDialog(self, "Choose an Image File", ".", "", - "Bmp (*.bmp)|*.bmp|JPEG (*.jpg)|*.jpg", wx.OPEN) + 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) - 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= '7.0': +if get_acroversion() >= 7.0: from wx.lib.activexwrapper import MakeActiveXClass import win32com.client.gencache diff --git a/wxPython/wx/py/shell.py b/wxPython/wx/py/shell.py index ec8d7f4dae..77963e712f 100644 --- a/wxPython/wx/py/shell.py +++ b/wxPython/wx/py/shell.py @@ -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 diff --git a/wxPython/wx/tools/XRCed/params.py b/wxPython/wx/tools/XRCed/params.py index fd7601985c..b4c7721c96 100644 --- a/wxPython/wx/tools/XRCed/params.py +++ b/wxPython/wx/tools/XRCed/params.py @@ -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: diff --git a/wxPython/wx/tools/XRCed/xxx.py b/wxPython/wx/tools/XRCed/xxx.py index 147240efc1..a78129dee9 100644 --- a/wxPython/wx/tools/XRCed/xxx.py +++ b/wxPython/wx/tools/XRCed/xxx.py @@ -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 diff --git a/wxPython/wxPython/html.py b/wxPython/wxPython/html.py index 44ac756993..82443ce7d3 100644 --- a/wxPython/wxPython/html.py +++ b/wxPython/wxPython/html.py @@ -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 -- 2.45.2