diff --git a/TODO.txt b/TODO.txt index af9fc370..64ce94fb 100644 --- a/TODO.txt +++ b/TODO.txt @@ -129,11 +129,6 @@ build.py unnecesary rebuilds. -Deprecated C++ items ---------------------- - * Does Doxygen have a standard way to mark items as deprecated - that will also be tagged as such in the XML? - wxProgressDialog ---------------- @@ -141,6 +136,25 @@ wxProgressDialog * and wxProgressDialog inherits from the generic version +Generated Unitests +------------------ + * Autogenerate a skeleton unittest module for each etg module. + * It can traverse the items in the module object and use a test + template based on what kind of item it is. Templates could + include toplevel window tests, non-toplevel window, event + binder, event class, etc. + * If the file already exists then don't overwrite it. Or perhaps + we could have a "# AUTOGENERATED" tag in the file that means that + it can be overwritten. If a human wants to take over the file and + add additional tests then they just need to remove that tag. + + + +Deprecated C++ items +--------------------- + * Does Doxygen have a standard way to mark items as deprecated + that will also be tagged as such in the XML? + other dev stuff --------------- @@ -160,48 +174,10 @@ other dev stuff * Word-wrap the briefDoc strings used for %Docstring directives - * For full coverage of what was in the Classic core modules we'll need ETG - files for the following: + * It looks like the code that is flattening the element nodes to + extract the briefDocs is not getting some spaces that should be in + there, probably where some tags are being removed. - * filesys, fs_mem, fs_inet, fs_arch (with wxZipFSHandler typedef) - * taskbar - * all missing common dialogs - * print (as in print framework classes) - * mdi (die mdi! die!) - * scrollbar - * toolbar - * listctrl - * treectrl - * dirctrl - * cshelp - * dragimag - * datectrl - * hyperlink - * pickerbase, clrpicker, filepicker, fontpicker - * filectrl - * infobar - * commandlinkbutton - * axbase - * settings - * sysopt - * tipdlg - * check for items missing from _functions.i and _misc.i - * joystick - * sound - * mimetype - * artprov - * datetime, or make it be a MappedType for Python date objects? - * clipbrd, dnd, finish dataobj - * power - * about - * uiaction - - - - * Divide Phoenix core into multiple modules. Perhaps using the same - divisions that a wx multi-lib build uses would be a good idea. - - @@ -291,6 +267,7 @@ way: * The tool should be able to be used to answer questions about the data for a single scan like: + * number of classes * list of all class names * list of methods in class Foo diff --git a/build.py b/build.py index 5583db8b..21da3ecb 100755 --- a/build.py +++ b/build.py @@ -19,6 +19,9 @@ import urllib2 from distutils.dep_util import newer, newer_group from buildtools.config import Config, msg, opj, posixjoin, loadETG, etg2sip, findCmd + +from sphinxtools.postprocess import SphinxIndexes, MakeHeadings, PostProcess, GenGallery + import buildtools.version as version # defaults @@ -36,11 +39,11 @@ unstable_series = (version.VER_MINOR % 2) == 1 # is the minor version odd or ev isWindows = sys.platform.startswith('win') isDarwin = sys.platform == "darwin" -sipCurrentVersion = '4.13.1-snapshot-7ab562ae0e39' +sipCurrentVersion = '4.13.1-snapshot-98421b9cc511' sipCurrentVersionMD5 = { - 'darwin' : '2da0cc2ba853b2787499da0596b4e8ac', - 'win32' : '45673b36d6885632ad0f273c496a1383', - 'linux2' : 'f7971044b97f7fc7650fef2189517937', + 'darwin' : '1d5ae7c54b768a77d951df3bae15a33e', + 'win32' : 'abe8ff9ff1804f9cf6def83712643187', + 'linux2' : 'fbab55f36f05dfbf31d4968ce187abb8', # TODO: linux build needs updated!! } toolsURL = 'http://wxpython.org/Phoenix/tools' @@ -59,6 +62,8 @@ Usage: ./build.py [command(s)] [options] next build etg Run the ETG scripts that are out of date to update their SIP files + sphinx Run the documentation building process using Sphinx (this + needs to be done after dox and etg) sip Run sip test Run the unit test suite test_* Run just one test module @@ -108,7 +113,8 @@ def main(args): testOne(cmd, options, args) elif cmd in ['dox', 'doxhtml', 'etg', 'sip', 'touch', 'test', 'build_wx', 'build_py', 'build', 'bdist', - 'clean', 'clean_wx', 'clean_py', 'cleanall']: + 'clean', 'clean_wx', 'clean_py', 'cleanall', + 'sphinx']: function = globals()[cmd] function(options, args) else: @@ -424,7 +430,7 @@ def dox(options, args): def doxhtml(options, args): msg('Running command: doxhtml') - #_doDox('html') + _doDox('html') _doDox('chm') @@ -432,6 +438,11 @@ def doxhtml(options, args): def etg(options, args): msg('Running command: etg') pwd = pushDir(phoenixDir()) + + sphinxDir = os.path.join(phoenixDir(), 'docs', 'sphinx') + + clean_sphinx(sphinxDir, full=True) + etgfiles = glob.glob('etg/_*.py') for script in etgfiles: sipfile = etg2sip(script) @@ -448,7 +459,65 @@ def etg(options, args): if newer_group(deps, sipfile): runcmd('%s %s --sip' % (PYTHON, script)) - + # Copy the rst files into txt files + restDir = os.path.join(sphinxDir, 'rest_substitutions', 'overviews') + rstFiles = glob.glob(restDir + '/*.rst') + + for rst in rstFiles: + rstName = os.path.split(rst)[1] + txt = os.path.join(sphinxDir, os.path.splitext(rstName)[0] + '.txt') + shutil.copyfile(rst, txt) + + SphinxIndexes(sphinxDir) + GenGallery() + + +def clean_sphinx(sphinxDir, full=True): + + sphinxfiles = [] + + if full: + sphinxfiles = glob.glob(sphinxDir + '/*.txt') + sphinxfiles += glob.glob(sphinxDir + '/*.inc') + + pklfiles = glob.glob(sphinxDir + '/*.pkl') + lstfiles = glob.glob(sphinxDir + '/*.lst') + + for f in sphinxfiles + pklfiles + lstfiles: + os.remove(f) + + +def sphinx(options, args): + + sphinxDir = os.path.join(phoenixDir(), 'docs', 'sphinx') + + if not os.path.isdir(sphinxDir): + raise Exception('Missing sphinx folder in the distribution') + + textFiles = glob.glob(sphinxDir + '/*.txt') + if not textFiles: + raise Exception('No documentation files found. Please run "build.py touch etg" first') + + todos = os.path.join(phoenixDir(), 'TODO.txt') + migration_guide = os.path.join(phoenixDir(), 'docs', 'MigrationGuide.txt') + + if os.path.isfile(migration_guide): + shutil.copy(migration_guide, sphinxDir) + + if os.path.isfile(todos): + shutil.copy(todos, sphinxDir) + + MakeHeadings() + + pwd = pushDir(sphinxDir) + runcmd('make html') + + buildDir = os.path.join(sphinxDir, 'build') + PostProcess(buildDir) + + clean_sphinx(sphinxDir, full=False) + + def sip(options, args): msg('Running command: sip') cfg = Config() @@ -894,7 +963,7 @@ def bdist(options, args): if environ_script: tarball.add(environ_script, os.path.join(rootname, os.path.basename(environ_script))) tarball.close() - + if options.upload_package: print "Preparing to upload package..." configfile = os.path.join(os.getenv("HOME"), "phoenix_package_server.cfg") @@ -917,7 +986,7 @@ def bdist(options, args): ftp.close() print "Upload complete!" - + print "Release built at %s" % tarfilename diff --git a/docs/sphinx/Makefile b/docs/sphinx/Makefile new file mode 100644 index 00000000..68b138ec --- /dev/null +++ b/docs/sphinx/Makefile @@ -0,0 +1,130 @@ +# Makefile for Sphinx documentation +# + +# You can set these variables from the command line. +SPHINXOPTS = +SPHINXBUILD = sphinx-build +PAPER = +BUILDDIR = build + +# Internal variables. +PAPEROPT_a4 = -D latex_paper_size=a4 +PAPEROPT_letter = -D latex_paper_size=letter +ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source + +.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest + +help: + @echo "Please use \`make ' where is one of" + @echo " html to make standalone HTML files" + @echo " dirhtml to make HTML files named index.html in directories" + @echo " singlehtml to make a single large HTML file" + @echo " pickle to make pickle files" + @echo " json to make JSON files" + @echo " htmlhelp to make HTML files and a HTML help project" + @echo " qthelp to make HTML files and a qthelp project" + @echo " devhelp to make HTML files and a Devhelp project" + @echo " epub to make an epub" + @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" + @echo " latexpdf to make LaTeX files and run them through pdflatex" + @echo " text to make text files" + @echo " man to make manual pages" + @echo " changes to make an overview of all changed/added/deprecated items" + @echo " linkcheck to check all external links for integrity" + @echo " doctest to run all doctests embedded in the documentation (if enabled)" + +clean: + -rm -rf $(BUILDDIR)/* + +html: + $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." + +dirhtml: + $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." + +singlehtml: + $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml + @echo + @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." + +pickle: + $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle + @echo + @echo "Build finished; now you can process the pickle files." + +json: + $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json + @echo + @echo "Build finished; now you can process the JSON files." + +htmlhelp: + $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp + @echo + @echo "Build finished; now you can run HTML Help Workshop with the" \ + ".hhp project file in $(BUILDDIR)/htmlhelp." + +qthelp: + $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp + @echo + @echo "Build finished; now you can run "qcollectiongenerator" with the" \ + ".qhcp project file in $(BUILDDIR)/qthelp, like this:" + @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/wxPythonPhoenix.qhcp" + @echo "To view the help file:" + @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/wxPythonPhoenix.qhc" + +devhelp: + $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp + @echo + @echo "Build finished." + @echo "To view the help file:" + @echo "# mkdir -p $$HOME/.local/share/devhelp/wxPythonPhoenix" + @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/wxPythonPhoenix" + @echo "# devhelp" + +epub: + $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub + @echo + @echo "Build finished. The epub file is in $(BUILDDIR)/epub." + +latex: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo + @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." + @echo "Run \`make' in that directory to run these through (pdf)latex" \ + "(use \`make latexpdf' here to do that automatically)." + +latexpdf: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo "Running LaTeX files through pdflatex..." + make -C $(BUILDDIR)/latex all-pdf + @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." + +text: + $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text + @echo + @echo "Build finished. The text files are in $(BUILDDIR)/text." + +man: + $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man + @echo + @echo "Build finished. The manual pages are in $(BUILDDIR)/man." + +changes: + $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes + @echo + @echo "The overview file is in $(BUILDDIR)/changes." + +linkcheck: + $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck + @echo + @echo "Link check complete; look for any errors in the above output " \ + "or in $(BUILDDIR)/linkcheck/output.txt." + +doctest: + $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest + @echo "Testing of doctests in the sources finished, look at the " \ + "results in $(BUILDDIR)/doctest/output.txt." diff --git a/docs/sphinx/_static/css/basic.css b/docs/sphinx/_static/css/basic.css new file mode 100644 index 00000000..a4ebd156 --- /dev/null +++ b/docs/sphinx/_static/css/basic.css @@ -0,0 +1,510 @@ +/* + * basic.css + * ~~~~~~~~~ + * + * Sphinx stylesheet -- basic theme. + * + * :copyright: Copyright 2007-2010 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +/* -- main layout ----------------------------------------------------------- */ + +div.clearer { + clear: both; +} + +/* -- relbar ---------------------------------------------------------------- */ + +div.related { + width: 100%; + font-size: 90%; +} + +div.related h3 { + display: none; +} + +div.related ul { + margin: 0; + padding: 0 0 0 10px; + list-style: none; +} + +div.related li { + display: inline; +} + +div.related li.right { + float: right; + margin-right: 5px; +} + +/* -- sidebar --------------------------------------------------------------- */ + +div.sphinxsidebarwrapper { + padding: 10px 5px 0 10px; +} + +div.sphinxsidebar { + float: left; + width: 230px; + margin-left: -100%; + font-size: 90%; +} + +div.sphinxsidebar ul { + list-style: none; +} + +div.sphinxsidebar ul ul, +div.sphinxsidebar ul.want-points { + margin-left: 20px; + list-style: square; +} + +div.sphinxsidebar ul ul { + margin-top: 0; + margin-bottom: 0; +} + +div.sphinxsidebar form { + margin-top: 10px; +} + +div.sphinxsidebar input { + border: 1px solid #98dbcc; + font-family: sans-serif; + font-size: 1em; +} + +img { + border: 0; + max-width: 100%; +} + +/* -- search page ----------------------------------------------------------- */ + +ul.search { + margin: 10px 0 0 20px; + padding: 0; +} + +ul.search li { + padding: 5px 0 5px 20px; + background-image: url(file.png); + background-repeat: no-repeat; + background-position: 0 7px; +} + +ul.search li a { + font-weight: bold; +} + +ul.search li div.context { + color: #888; + margin: 2px 0 0 30px; + text-align: left; +} + +ul.keywordmatches li.goodmatch a { + font-weight: bold; +} + +/* -- index page ------------------------------------------------------------ */ + +table.contentstable { + width: 90%; +} + +table.contentstable p.biglink { + line-height: 150%; +} + +a.biglink { + font-size: 1.3em; +} + +span.linkdescr { + font-style: italic; + padding-top: 5px; + font-size: 90%; +} + +/* -- general index --------------------------------------------------------- */ + +table.indextable { + width: 100%; +} + +table.indextable td { + text-align: left; + vertical-align: top; +} + +table.indextable dl, table.indextable dd { + margin-top: 0; + margin-bottom: 0; +} + +table.indextable tr.pcap { + height: 10px; +} + +table.indextable tr.cap { + margin-top: 10px; + background-color: #f2f2f2; +} + +img.toggler { + margin-right: 3px; + margin-top: 3px; + cursor: pointer; +} + +div.modindex-jumpbox { + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + margin: 1em 0 1em 0; + padding: 0.4em; +} + +div.genindex-jumpbox { + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + margin: 1em 0 1em 0; + padding: 0.4em; +} + +/* -- general body styles --------------------------------------------------- */ + +a.headerlink { + visibility: hidden; +} + +h1:hover > a.headerlink, +h2:hover > a.headerlink, +h3:hover > a.headerlink, +h4:hover > a.headerlink, +h5:hover > a.headerlink, +h6:hover > a.headerlink, +dt:hover > a.headerlink { + visibility: visible; +} + +div.body p.caption { + text-align: inherit; +} + +div.body td { + text-align: left; +} + +.field-list ul { + padding-left: 1em; +} + +.first { + margin-top: 0 !important; +} + +p.rubric { + margin-top: 30px; + font-weight: bold; +} + +.align-left { + text-align: left; +} + +.align-center { + clear: both; + text-align: center; +} + +.align-right { + text-align: right; +} + +/* -- sidebars -------------------------------------------------------------- */ + +div.sidebar { + margin: 0 0 0.5em 1em; + border: 1px solid #ddb; + padding: 7px 7px 0 7px; + background-color: #ffe; + width: 40%; + float: right; +} + +p.sidebar-title { + font-weight: bold; +} + +/* -- topics ---------------------------------------------------------------- */ + +div.topic { + border: 1px solid #ccc; + padding: 7px 7px 0 7px; + margin: 10px 0 10px 0; +} + +p.topic-title { + font-size: 1.1em; + font-weight: bold; + margin-top: 10px; +} + +/* -- admonitions ----------------------------------------------------------- */ + +div.admonition { + margin-top: 10px; + margin-bottom: 10px; + padding: 7px; +} + +div.admonition dt { + font-weight: bold; +} + +div.admonition dl { + margin-bottom: 0; +} + +p.admonition-title { + margin: 0px 10px 5px 0px; + font-weight: bold; +} + +div.body p.centered { + text-align: center; + margin-top: 25px; +} + +/* -- tables ---------------------------------------------------------------- */ + +table.docutils { + border: 0; + border-collapse: collapse; +} + +table.docutils td, table.docutils th { + padding: 1px 8px 1px 5px; + border-top: 0; + border-left: 0; + border-right: 0; + border-bottom: 1px solid #aaa; +} + +table.field-list td, table.field-list th { + border: 0 !important; +} + +table.footnote td, table.footnote th { + border: 0 !important; +} + +th { + text-align: left; + padding-right: 5px; +} + +table.citation { + border-left: solid 1px gray; + margin-left: 1px; +} + +table.citation td { + border-bottom: none; +} + +/* -- other body styles ----------------------------------------------------- */ + +ol.arabic { + list-style: decimal; +} + +ol.loweralpha { + list-style: lower-alpha; +} + +ol.upperalpha { + list-style: upper-alpha; +} + +ol.lowerroman { + list-style: lower-roman; +} + +ol.upperroman { + list-style: upper-roman; +} + +dl { + margin-bottom: 15px; +} + +dd p { + margin-top: 0px; +} + +dd ul, dd table { + margin-bottom: 10px; +} + +dd { + margin-top: 3px; + margin-bottom: 10px; + margin-left: 30px; +} + +dt:target, .highlighted { + background-color: #fbe54e; +} + +dl.glossary dt { + font-weight: bold; + font-size: 1.1em; +} + +.field-list ul { + margin: 0; + padding-left: 1em; +} + +.field-list p { + margin: 0; +} + +.refcount { + color: #060; +} + +.optional { + font-size: 1.3em; +} + +.versionmodified { + font-style: italic; +} + +.system-message { + background-color: #fda; + padding: 5px; + border: 3px solid red; +} + +.footnote:target { + background-color: #ffa +} + +.line-block { + display: block; + margin-top: 1em; + margin-bottom: 1em; +} + +.line-block .line-block { + margin-top: 0; + margin-bottom: 0; + margin-left: 1.5em; +} + +.guilabel, .menuselection { + font-family: sans-serif; +} + +.accelerator { + text-decoration: underline; +} + +.classifier { + font-style: oblique; +} + +/* -- code displays --------------------------------------------------------- */ + +pre { + overflow: auto; +} + +td.linenos pre { + padding: 5px 0px; + border: 0; + background-color: transparent; + color: #aaa; +} + +table.highlighttable { + margin-left: 0.5em; +} + +table.highlighttable td { + padding: 0 0.5em 0 0.5em; +} + +tt.descname { + background-color: transparent; + font-weight: bold; + font-size: 1.2em; +} + +tt.descclassname { + background-color: transparent; +} + +tt.xref, a tt { + background-color: transparent; + font-weight: bold; +} + +h1 tt, h2 tt, h3 tt, h4 tt, h5 tt, h6 tt { + background-color: transparent; +} + +.viewcode-link { + float: right; +} + +.viewcode-back { + float: right; + font-family: sans-serif; +} + +div.viewcode-block:target { + margin: -1px -10px; + padding: 0 10px; +} + +/* -- math display ---------------------------------------------------------- */ + +img.math { + vertical-align: middle; +} + +div.body div.math p { + text-align: center; +} + +span.eqno { + float: right; +} + +/* -- printout stylesheet --------------------------------------------------- */ + +@media print { + div.document, + div.documentwrapper, + div.bodywrapper { + margin: 0 !important; + width: 100%; + } + + div.sphinxsidebar, + div.related, + div.footer, + #top-link { + display: none; + } +} diff --git a/docs/sphinx/_static/css/default.css b/docs/sphinx/_static/css/default.css new file mode 100644 index 00000000..59dad367 --- /dev/null +++ b/docs/sphinx/_static/css/default.css @@ -0,0 +1,227 @@ +/** + * Sphinx stylesheet -- default theme + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + */ + +@import url("basic.css"); + +/* -- page layout ----------------------------------------------------------- */ + +body { + font-family: sans-serif; + font-size: 100%; + background-color: #11303d; + color: #000; + margin: 0; + padding: 0; +} + +div.document { + background-color: #1c4e63; +} + +div.documentwrapper { + float: left; + width: 100%; +} + +div.bodywrapper { + margin: 0 0 0 230px; +} + +div.body { + background-color: #ffffff; + color: #000000; + padding: 0 20px 30px 20px; +} + +div.footer { + color: #ffffff; + width: 100%; + padding: 9px 0 9px 0; + text-align: center; + font-size: 75%; +} + +div.footer a { + color: #ffffff; + text-decoration: underline; +} + +div.related { + background-color: #133f52; + line-height: 30px; + color: #ffffff; +} + +div.related a { + color: #ffffff; +} + +div.sphinxsidebarwrapper { + padding: 10px 5px 0 10px; +} + +div.sphinxsidebar { + float: left; + width: 230px; + margin-left: -100%; + font-size: 90%; +} + +div.sphinxsidebar h3 { + font-family: 'Trebuchet MS', sans-serif; + color: #ffffff; + font-size: 1.4em; + font-weight: normal; + margin: 0; + padding: 0; +} + +div.sphinxsidebar h3 a { + color: #ffffff; +} + +div.sphinxsidebar h4 { + font-family: 'Trebuchet MS', sans-serif; + color: #ffffff; + font-size: 1.3em; + font-weight: normal; + margin: 5px 0 0 0; + padding: 0; +} + +div.sphinxsidebar p { + color: #ffffff; +} + +div.sphinxsidebar p.topless { + margin: 5px 10px 10px 10px; +} + +div.sphinxsidebar ul { + margin: 10px; + padding: 0; + color: #ffffff; +} + +div.sphinxsidebar a { + color: #98dbcc; +} + +div.sphinxsidebar input { + border: 1px solid #98dbcc; + font-family: sans-serif; + font-size: 1em; +} + +/* -- body styles ----------------------------------------------------------- */ + +a { + color: #355f7c; + text-decoration: none; +} + +a:visited { + color: #355f7c; + text-decoration: none; +} + +a:hover { + text-decoration: underline; +} + +div.body p, div.body dd, div.body li { + text-align: justify; + line-height: 130%; +} + +div.body h1, +div.body h2, +div.body h3, +div.body h4, +div.body h5, +div.body h6 { + font-family: 'Trebuchet MS', sans-serif; + background-color: #f2f2f2; + font-weight: normal; + color: #20435c; + border-bottom: 1px solid #ccc; + margin: 20px -20px 10px -20px; + padding: 3px 0 3px 10px; +} + +div.body h1 { margin-top: 0; font-size: 200%; } +div.body h2 { font-size: 160%; } +div.body h3 { font-size: 140%; } +div.body h4 { font-size: 120%; } +div.body h5 { font-size: 110%; } +div.body h6 { font-size: 100%; } + +a.headerlink { + color: #c60f0f; + font-size: 0.8em; + padding: 0 4px 0 4px; + text-decoration: none; +} + +a.headerlink:hover { + background-color: #c60f0f; + color: white; +} + +div.body p, div.body dd, div.body li { + text-align: justify; + line-height: 130%; +} + +div.admonition p.admonition-title + p { + display: inline; +} + +div.note { + background-color: #eee; + border: 1px solid #ccc; +} + +div.seealso { + background-color: #ffc; + border: 1px solid #ff6; +} + +div.topic { + background-color: #eee; +} + +div.warning { + background-color: #ffe4e4; + border: 1px solid #f66; +} + +p.admonition-title { + display: inline; +} + +p.admonition-title:after { + content: ":"; +} + +pre { + padding: 5px; + background-color: #eeffcc; + color: #333333; + line-height: 120%; + border: 1px solid #ac9; + border-left: none; + border-right: none; +} + +tt { + background-color: #ecf0f3; + padding: 0 1px 0 1px; + font-size: 0.95em; +} + +th { + background-color: #ede; +} \ No newline at end of file diff --git a/docs/sphinx/_static/css/gallery.css b/docs/sphinx/_static/css/gallery.css new file mode 100644 index 00000000..ed4d3f9e --- /dev/null +++ b/docs/sphinx/_static/css/gallery.css @@ -0,0 +1,47 @@ + \ No newline at end of file diff --git a/docs/sphinx/_static/css/phoenix.css b/docs/sphinx/_static/css/phoenix.css new file mode 100644 index 00000000..9ae04ea7 --- /dev/null +++ b/docs/sphinx/_static/css/phoenix.css @@ -0,0 +1,640 @@ +@import "default.css"; +@import "tables.css"; + +img { + border: 0; + max-width: 100%; + horizontal-align: center; +} + +/** + * Spacing fixes + */ + +div.body p, div.body dd, div.body li { + line-height: 125%; +} + +ul.simple { + margin-top: 0; + margin-bottom: 0; + padding-top: 0; + padding-bottom: 0; +} + +/* spacing around blockquoted fields in parameters/attributes/returns */ +td.field-body > blockquote { + margin-top: 0.1em; + margin-bottom: 0.5em; +} + +/* spacing around example code */ +div.highlight > pre { + padding: 2px 5px 2px 5px; +} + +/* spacing in see also definition lists */ +dl.last > dd { + margin-top: 1px; + margin-bottom: 5px; + margin-left: 30px; +} + +div.quotebar { + background-color: #f8f8f8; + max-width: 250px; + float: right; + padding: 2px 7px; + border: 1px solid #ccc; +} + +/** + * Hide dummy toctrees + */ + +ul { + padding-top: 0; + padding-bottom: 0; + margin-top: 0; + margin-bottom: 0; +} +ul li { + padding-top: 0; + padding-bottom: 0; + margin-top: 0; + margin-bottom: 0; +} +ul li a.reference { + padding-top: 0; + padding-bottom: 0; + margin-top: 0; + margin-bottom: 0; +} + +/** + * Make high-level subsections easier to distinguish from top-level ones + */ +div.body h3 { + background-color: transparent; +} + +div.body h4 { + border: none; + background-color: transparent; +} + +/** + * Scipy colors + */ + +body { + background-color: rgb(100,135,220); +} + +div.document { + background-color: rgb(230,230,230); + position: relative; + z-index: 0; + top: 30px; +} + +div.sphinxsidebar { + background-color: rgb(230,230,230); + z-index: 1; + left: 0; + top: 30px; + bottom: 0; +} + +div.related { + font-size: 1em; + position: fixed; + line-height: 30px; + position: fixed; + height: 30px; + z-index: 1; + left: 0; + right: 0; + top: 0; +} + +div.related ul { + background-image: url('../images/sphinxdocs/navigation.png'); + height: 2em; + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + color: rgb(100, 100, 100); +} + +div.related ul li { + margin: 0; + padding: 0; + height: 2em; + float: left; +} + +div.related ul li.right { + float: right; + margin-right: 5px; +} + +div.related ul li a { + margin: 0; + padding: 0 5px 0 5px; + line-height: 1.75em; + color: #EE9816; +} + +div.related ul li a:hover { + color: #3CA8E7; +} + +div.sphinxsidebar h3 { + color: rgb(0,102,204); +} + +div.sphinxsidebar h3 a { + color: rgb(0,102,204); +} + +div.sphinxsidebar h4 { + color: rgb(0,82,194); +} + +div.sphinxsidebar p { + color: black; +} + +div.sphinxsidebar a { + color: #355f7c; +} + +div.sphinxsidebar ul.want-points { + list-style: disc; +} + +.field-list th { + color: rgb(0,102,204); +} + +.floatleft { + position: relative; + float:left; + text-align:center; +} + +.floatcenter { + position:relative; + float:none; + text-align:center; +} + +.floatright { + position: relative; + float:right; + text-align:center; +} + +/** + * Extra admonitions + */ + +div.return { + color: rgb(0,0,255); +} + +div.tip { + background-color: #ffffe4; + border: 1px solid #ee6; +} + +div.availability { + background-color: #e8f7c4; + border: 1px solid #adff2f; +} + +div.plot-output { + clear-after: both; +} + +div.plot-output .figure { + float: center; + text-align: center; + margin-bottom: 0; + padding-bottom: 0; +} + +div.plot-output .caption { + margin-top: 2; + padding-top: 0; +} + +div.plot-output p.admonition-title { + display: none; +} + +div.plot-output:after { + content: ""; + display: block; + height: 0; + clear: both; +} + +.doctodo { + background-color: #ccccff; + padding: 10px; + margin: 0 -20px 0 -20px; + border-bottom: 1px solid #cc99ff; +} + +.docwarning { + background-color: #ffe4e4; + padding: 10px; + margin: 0 -20px 0 -20px; + border-bottom: 1px solid #f66; +} + +.doccaution { + background-color: #ff9900; + padding: 10px; + margin: 0 -20px 0 -20px; + border-bottom: 1px solid #f66; +} + +.docimportant { + background-color: #ffcc33; + padding: 10px; + margin: 0 -20px 0 -20px; + border-bottom: 1px solid #f66; +} + +.doctip { + background-color: #ccff66; + padding: 10px; + margin: 0 -20px 0 -20px; + border-bottom: 1px solid #f66; +} + +.docavailability { + background-color: #e8f7c4; + padding: 10px; + margin: 0 -20px 0 -20px; + border-bottom: 1px solid #adff2f; +} + +div.admonition p { + display: inline; +} + +div.admonition { + background-color: #98F5FF; + border: 1px solid #00B2EE; + text-align: justify; + background-image: url('../images/sphinxdocs/todo.png'); + background-repeat: no-repeat; + background-position: 5px 5px; + padding-left: 33px; +} + +.admonition tt { + background: #98F5FF; +} + +div.seealso { + background-color: #ffc; + border: 1px solid #ff6; + text-align: justify; + background-image: url('../images/sphinxdocs/seealso.png'); + background-repeat: no-repeat; + background-position: 5px 5px; + padding-left: 33px; +} + +.seealso tt { + background: #ffc; +} + +div.warning { + background-color: #ffe4e4; + border: 1px solid #f66; + text-align: justify; + background-image: url('../images/sphinxdocs/warning.png'); + background-repeat: no-repeat; + background-position: 5px 5px; + padding-left: 33px; +} + +.warning tt { + background: #ffe4e4; +} + +div.todo { + background-color: #ccccff; + border: 1px solid #cc99ff; + text-align: justify; + background-image: url('../images/sphinxdocs/todo.png'); + background-repeat: no-repeat; + background-position: 5px 5px; + padding-left: 33px; +} + +.todo tt { + background: #ccccff; +} + +div.caution { + background-color: #ccffff; + border: 1px solid #99ccff; + text-align: justify; +} + +.caution tt { + background: #ccccff; +} + +div.important { + background-color: #ffcc33; + border: 1px solid #ff9900; + text-align: justify; +} + +.important tt { + background: #ffcc33; +} + +div.tip { + background-color: #ccff33; + border: 1px solid #33cc33; + text-align: justify; +} + +.tip tt { + background: #ccff33; +} + + +div.note { + background-color: #eee; + border: 1px solid #ccc; + text-align: justify; + background-image: url('../images/sphinxdocs/info.png'); + background-repeat: no-repeat; + background-position: 5px 5px; + padding-left: 33px; +} + +.note tt { + background: #eee; +} + +div.availability { + background-color: #e8f7c4; + border: 1px solid #adff2f; + text-align: justify; + background-image: url('../images/sphinxdocs/available.png'); + background-repeat: no-repeat; + background-position: 5px 5px; + padding-left: 33px; +} + +.availability tt { + background: #e8f7c4; +} + + + p.admonition-title { + margin: 10px 10px 5px 0px; + font-weight: bold; +} + + .gallery_class table { float: left; + margin: 0 5px 20px 0; } + .gallery_class table { border-collapse: collapse; } + .gallery_class table td { padding: 0; } + .gallery_class table caption { font-size: 80%; } + .gallery .caption { height: 4em; vertical-align: top; } + .gallery table { width: 200px; } + + +/** + * Styling for field lists + */ + +table.field-list th { + border-left: 1px solid #aaa !important; + padding-left: 5px; +} + +table.field-list { + border-collapse: separate; + border-spacing: 10px; +} + +/** + * Styling for footnotes + */ + +table.footnote td, table.footnote th { + border: none; +} + +pre { + font-family: 'Consolas', 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', 'Trebuchet MS', monospace; + font-size: 0.95em; + letter-spacing: 0.015em; + padding: 0.5em; + border: 1px solid #ccc; + background-color: #f8f8f8; +} + +cite, code, tt { + font-family: 'Consolas', 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', 'Trebuchet MS', monospace; + font-size: 0.95em; + letter-spacing: 0.01em; +} + +a.headerlink { + color: #c60f0f; + font-size: 0.8em; + padding: 0 4px 0 4px; + text-decoration: none; + visibility: hidden; +} + +h1:hover > a.headerlink, +h2:hover > a.headerlink, +h3:hover > a.headerlink, +h4:hover > a.headerlink, +h5:hover > a.headerlink, +h6:hover > a.headerlink, +dt:hover > a.headerlink { + visibility: visible; +} + + +a em { + color: #CA7900; + background-color: transparent; + font-family: 'Consolas', 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', 'Trebuchet MS', monospace; + font-weight: bold; + border: 0; + letter-spacing: 0.01em; + font-style: normal; + font-size: 0.95em; + letter-spacing: 0.01em; +} + +a em:hover { + color: #2491CF; +} + +a:hover { + color: #2491CF; +} + +a.headerlink:hover { + background-color: #c60f0f; + color: white; +} + +a tt { + background-color: transparent; + font-weight: bold; + border: 0; + color: #CA7900; +} + +a tt:hover { + color: #2491CF; +} + +.panel { +position: fixed; +top: 60px; +right: 0; +display: none; +background: #000000; +border:1px solid #111111; +font-family: 'Calibri', 'Deja Vu Sans', 'Bitstream Vera Sans', 'Trebuchet MS', monospace; +-moz-border-radius-topleft: 20px; +-webkit-border-top-left-radius: 20px; +-moz-border-radius-bottomleft: 20px; +-webkit-border-bottom-left-radius: 20px; +width: 200px; +height: auto; +padding: 20px 30px 30px 30px; +filter: alpha(opacity=85); +opacity: .85; +} + +.panel p{ +margin: 0 0 15px 0; +padding: 0; +color: #cccccc; +} + +.panel a, .panel a:visited{ +margin: 0; +padding: 0; +color: #CA7900; +text-decoration: none; +border-bottom: 1px solid #CA7900; +} + +.panel a:hover, .panel a:visited:hover{ +margin: 0; +padding: 0; +color: #2491CF; +text-decoration: none; +border-bottom: 1px solid #2491CF; +} + +a.trigger{ +position: fixed; +text-decoration: none; +top: 80px; right: 0; +font-size: 20px; +letter-spacing:-1px; +font-family: 'Consolas', 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', 'Trebuchet MS', monospace; +color:#fff; +padding: 20px 40px 20px 15px; +font-weight: 700; +background:#333333 url('../images/sphinxdocs/plus2.png') 85% 55% no-repeat; +border:1px solid #444444; +-moz-border-radius-topleft: 20px; +-webkit-border-top-left-radius: 20px; +-moz-border-radius-bottomleft: 20px; +-webkit-border-bottom-left-radius: 20px; +-moz-border-radius-bottomright: 0px; +-webkit-border-bottom-right-radius: 0px; +display: block; +} + +a.trigger:hover{ +position: fixed; +text-decoration: none; +top: 80px; right: 0; +font-size: 20px; +letter-spacing:-1px; +font-family: 'Consolas', 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', 'Trebuchet MS', monospace; +color:#fff; +padding: 20px 40px 20px 20px; +font-weight: 700; +background:#222222 url('../images/sphinxdocs/plus2.png') 85% 55% no-repeat; +border:1px solid #444444; +-moz-border-radius-topright: 20px; +-webkit-border-top-right-radius: 20px; +-moz-border-radius-bottomright: 20px; +-webkit-border-bottom-right-radius: 20px; +-moz-border-radius-bottomleft: 0px; +-webkit-border-bottom-left-radius: 0px; +display: block; +} + +a.active.trigger { +background:#222222 url('../images/sphinxdocs/minus2.png') 85% 55% no-repeat; +} + +.columns{ +clear: both; +width: 330px; +padding: 0 0 20px 0; +line-height: 22px; +} + +.colleft{ +float: left; +width: 130px; +line-height: 22px; +} + +.colright{ +float: right; +width: 130px; +line-height: 22px; +} + +/** + * Code block. + * The border colour should be a darker shade of the background colour. + * The hex code #E8D898 used below is a pale, light grayish amber. + */ +pre { + padding: 5px; + background-color: #FFFFE5; + color: #333333; + line-height: 120%; + border: 1px solid #E8D898; + border-left: none; + border-right: none; +} + +/** + * Commands or code within text. The hex code #EAEAF8 used below is a + * pale, light grayish blue. + */ +tt { + background-color: #EAEAF8; + padding: 0 1px 0 1px; + font-size: 0.95em; +} \ No newline at end of file diff --git a/docs/sphinx/_static/css/pygments.css b/docs/sphinx/_static/css/pygments.css new file mode 100644 index 00000000..79da57be --- /dev/null +++ b/docs/sphinx/_static/css/pygments.css @@ -0,0 +1,61 @@ +.hll { background-color: #ffffcc } +.c { color: #408090; font-style: italic } /* Comment */ +.err { border: 1px solid #FF0000 } /* Error */ +.k { color: #007020; font-weight: bold } /* Keyword */ +.o { color: #666666 } /* Operator */ +.cm { color: #408090; font-style: italic } /* Comment.Multiline */ +.cp { color: #007020 } /* Comment.Preproc */ +.c1 { color: #408090; font-style: italic } /* Comment.Single */ +.cs { color: #408090; background-color: #fff0f0 } /* Comment.Special */ +.gd { color: #A00000 } /* Generic.Deleted */ +.ge { font-style: italic } /* Generic.Emph */ +.gr { color: #FF0000 } /* Generic.Error */ +.gh { color: #000080; font-weight: bold } /* Generic.Heading */ +.gi { color: #00A000 } /* Generic.Inserted */ +.go { color: #303030 } /* Generic.Output */ +.gp { color: #c65d09; font-weight: bold } /* Generic.Prompt */ +.gs { font-weight: bold } /* Generic.Strong */ +.gu { color: #800080; font-weight: bold } /* Generic.Subheading */ +.gt { color: #0040D0 } /* Generic.Traceback */ +.kc { color: #007020; font-weight: bold } /* Keyword.Constant */ +.kd { color: #007020; font-weight: bold } /* Keyword.Declaration */ +.kn { color: #007020; font-weight: bold } /* Keyword.Namespace */ +.kp { color: #007020 } /* Keyword.Pseudo */ +.kr { color: #007020; font-weight: bold } /* Keyword.Reserved */ +.kt { color: #902000 } /* Keyword.Type */ +.m { color: #208050 } /* Literal.Number */ +.s { color: #4070a0 } /* Literal.String */ +.na { color: #4070a0 } /* Name.Attribute */ +.nb { color: #007020 } /* Name.Builtin */ +.nc { color: #0e84b5; font-weight: bold } /* Name.Class */ +.no { color: #60add5 } /* Name.Constant */ +.nd { color: #555555; font-weight: bold } /* Name.Decorator */ +.ni { color: #d55537; font-weight: bold } /* Name.Entity */ +.ne { color: #007020 } /* Name.Exception */ +.nf { color: #06287e } /* Name.Function */ +.nl { color: #002070; font-weight: bold } /* Name.Label */ +.nn { color: #0e84b5; font-weight: bold } /* Name.Namespace */ +.nt { color: #062873; font-weight: bold } /* Name.Tag */ +.nv { color: #bb60d5 } /* Name.Variable */ +.ow { color: #007020; font-weight: bold } /* Operator.Word */ +.w { color: #bbbbbb } /* Text.Whitespace */ +.mf { color: #208050 } /* Literal.Number.Float */ +.mh { color: #208050 } /* Literal.Number.Hex */ +.mi { color: #208050 } /* Literal.Number.Integer */ +.mo { color: #208050 } /* Literal.Number.Oct */ +.sb { color: #4070a0 } /* Literal.String.Backtick */ +.sc { color: #4070a0 } /* Literal.String.Char */ +.sd { color: #4070a0; font-style: italic } /* Literal.String.Doc */ +.s2 { color: #4070a0 } /* Literal.String.Double */ +.se { color: #4070a0; font-weight: bold } /* Literal.String.Escape */ +.sh { color: #4070a0 } /* Literal.String.Heredoc */ +.si { color: #70a0d0; font-style: italic } /* Literal.String.Interpol */ +.sx { color: #c65d09 } /* Literal.String.Other */ +.sr { color: #235388 } /* Literal.String.Regex */ +.s1 { color: #4070a0 } /* Literal.String.Single */ +.ss { color: #517918 } /* Literal.String.Symbol */ +.bp { color: #007020 } /* Name.Builtin.Pseudo */ +.vc { color: #bb60d5 } /* Name.Variable.Class */ +.vg { color: #bb60d5 } /* Name.Variable.Global */ +.vi { color: #bb60d5 } /* Name.Variable.Instance */ +.il { color: #208050 } /* Literal.Number.Integer.Long */ \ No newline at end of file diff --git a/docs/sphinx/_static/css/tables.css b/docs/sphinx/_static/css/tables.css new file mode 100644 index 00000000..38ebf751 --- /dev/null +++ b/docs/sphinx/_static/css/tables.css @@ -0,0 +1,57 @@ + +.pretty-table { + font-family: verdana,arial,sans-serif; + color:#333333; + border-width: 1px; + border-color: #999999; + border-collapse: collapse; +} +.pretty-table th { + background:#b5cfd2 url('../images/sphinxdocs/cell-blue.jpg'); + border-width: 1px; + padding: 8px; + vertical-align: middle; + border-style: solid; + border-color: #999999; +} +.pretty-table td { + background:#dcddc0 url('../images/sphinxdocs/cell-grey.jpg'); + border-width: 1px; + padding: 3px; + vertical-align: middle; + border-style: solid; + border-color: #999999; +} + +.pretty-table caption +{ + caption-side: bottom; + font-size: 0.9em; + font-style: italic; + text-align: right; + padding: 0.5em 0; +} + +.pretty-table tr:hover th, .pretty-table tr:hover td +{ + background-color: #632a2a; + color: #0000ff; + background:#b5cfd2 url('../images/sphinxdocs/orange_gradient.png'); +} + +.pretty-table tr:hover th[class=head] +{ + background:#b5cfd2 url('../images/sphinxdocs/cell-blue.jpg'); + color:#0066CC; +} + +.pretty-table tr:hover tt, .pretty-table tr:hover tt +{ + background-color: #632a2a; + background:#b5cfd2 url('../images/sphinxdocs/orange_gradient.png'); +} + +.pretty-table td tt +{ + background: #E0E0E0 url('../images/sphinxdocs/cell-grey.jpg'); +} diff --git a/docs/sphinx/_static/images/overviews/evthandler_unlink_after.png b/docs/sphinx/_static/images/overviews/evthandler_unlink_after.png new file mode 100644 index 00000000..f96ffcc7 Binary files /dev/null and b/docs/sphinx/_static/images/overviews/evthandler_unlink_after.png differ diff --git a/docs/sphinx/_static/images/overviews/evthandler_unlink_before.png b/docs/sphinx/_static/images/overviews/evthandler_unlink_before.png new file mode 100644 index 00000000..fa4c931f Binary files /dev/null and b/docs/sphinx/_static/images/overviews/evthandler_unlink_before.png differ diff --git a/docs/sphinx/_static/images/overviews/overview_events_chain.png b/docs/sphinx/_static/images/overviews/overview_events_chain.png new file mode 100644 index 00000000..fa4c931f Binary files /dev/null and b/docs/sphinx/_static/images/overviews/overview_events_chain.png differ diff --git a/docs/sphinx/_static/images/overviews/overview_events_winstack.png b/docs/sphinx/_static/images/overviews/overview_events_winstack.png new file mode 100644 index 00000000..397a97cb Binary files /dev/null and b/docs/sphinx/_static/images/overviews/overview_events_winstack.png differ diff --git a/docs/sphinx/_static/images/overviews/overview_sizer_00.png b/docs/sphinx/_static/images/overviews/overview_sizer_00.png new file mode 100644 index 00000000..26750c35 Binary files /dev/null and b/docs/sphinx/_static/images/overviews/overview_sizer_00.png differ diff --git a/docs/sphinx/_static/images/overviews/overview_sizer_01.png b/docs/sphinx/_static/images/overviews/overview_sizer_01.png new file mode 100644 index 00000000..27786690 Binary files /dev/null and b/docs/sphinx/_static/images/overviews/overview_sizer_01.png differ diff --git a/docs/sphinx/_static/images/overviews/overview_sizer_02.png b/docs/sphinx/_static/images/overviews/overview_sizer_02.png new file mode 100644 index 00000000..4635cd05 Binary files /dev/null and b/docs/sphinx/_static/images/overviews/overview_sizer_02.png differ diff --git a/docs/sphinx/_static/images/overviews/overview_sizer_03.png b/docs/sphinx/_static/images/overviews/overview_sizer_03.png new file mode 100644 index 00000000..359fdf60 Binary files /dev/null and b/docs/sphinx/_static/images/overviews/overview_sizer_03.png differ diff --git a/docs/sphinx/_static/images/overviews/overview_sizer_04.png b/docs/sphinx/_static/images/overviews/overview_sizer_04.png new file mode 100644 index 00000000..dccfd3c3 Binary files /dev/null and b/docs/sphinx/_static/images/overviews/overview_sizer_04.png differ diff --git a/docs/sphinx/_static/images/overviews/overview_sizer_05.png b/docs/sphinx/_static/images/overviews/overview_sizer_05.png new file mode 100644 index 00000000..4066f51b Binary files /dev/null and b/docs/sphinx/_static/images/overviews/overview_sizer_05.png differ diff --git a/docs/sphinx/_static/images/overviews/overview_sizer_06.png b/docs/sphinx/_static/images/overviews/overview_sizer_06.png new file mode 100644 index 00000000..e24a67e6 Binary files /dev/null and b/docs/sphinx/_static/images/overviews/overview_sizer_06.png differ diff --git a/docs/sphinx/_static/images/overviews/overview_sizer_07.png b/docs/sphinx/_static/images/overviews/overview_sizer_07.png new file mode 100644 index 00000000..006c0caa Binary files /dev/null and b/docs/sphinx/_static/images/overviews/overview_sizer_07.png differ diff --git a/docs/sphinx/_static/images/overviews/overview_sizer_08.png b/docs/sphinx/_static/images/overviews/overview_sizer_08.png new file mode 100644 index 00000000..63a50a68 Binary files /dev/null and b/docs/sphinx/_static/images/overviews/overview_sizer_08.png differ diff --git a/docs/sphinx/_static/images/overviews/overview_sizer_09.png b/docs/sphinx/_static/images/overviews/overview_sizer_09.png new file mode 100644 index 00000000..943d2ee1 Binary files /dev/null and b/docs/sphinx/_static/images/overviews/overview_sizer_09.png differ diff --git a/docs/sphinx/_static/images/overviews/overview_sizer_10.png b/docs/sphinx/_static/images/overviews/overview_sizer_10.png new file mode 100644 index 00000000..884807c2 Binary files /dev/null and b/docs/sphinx/_static/images/overviews/overview_sizer_10.png differ diff --git a/docs/sphinx/_static/images/overviews/overview_sizer_11.png b/docs/sphinx/_static/images/overviews/overview_sizer_11.png new file mode 100644 index 00000000..f7f353c4 Binary files /dev/null and b/docs/sphinx/_static/images/overviews/overview_sizer_11.png differ diff --git a/docs/sphinx/_static/images/overviews/overview_splitter_3d.png b/docs/sphinx/_static/images/overviews/overview_splitter_3d.png new file mode 100644 index 00000000..de35ed39 Binary files /dev/null and b/docs/sphinx/_static/images/overviews/overview_splitter_3d.png differ diff --git a/docs/sphinx/_static/images/sphinxdocs/api.png b/docs/sphinx/_static/images/sphinxdocs/api.png new file mode 100644 index 00000000..8e3eee09 Binary files /dev/null and b/docs/sphinx/_static/images/sphinxdocs/api.png differ diff --git a/docs/sphinx/_static/images/sphinxdocs/appearance.png b/docs/sphinx/_static/images/sphinxdocs/appearance.png new file mode 100644 index 00000000..2e807159 Binary files /dev/null and b/docs/sphinx/_static/images/sphinxdocs/appearance.png differ diff --git a/docs/sphinx/_static/images/sphinxdocs/available.png b/docs/sphinx/_static/images/sphinxdocs/available.png new file mode 100644 index 00000000..dcc42aaf Binary files /dev/null and b/docs/sphinx/_static/images/sphinxdocs/available.png differ diff --git a/docs/sphinx/_static/images/sphinxdocs/background.png b/docs/sphinx/_static/images/sphinxdocs/background.png new file mode 100644 index 00000000..284ae3fc Binary files /dev/null and b/docs/sphinx/_static/images/sphinxdocs/background.png differ diff --git a/docs/sphinx/_static/images/sphinxdocs/base.png b/docs/sphinx/_static/images/sphinxdocs/base.png new file mode 100644 index 00000000..0fdf6371 Binary files /dev/null and b/docs/sphinx/_static/images/sphinxdocs/base.png differ diff --git a/docs/sphinx/_static/images/sphinxdocs/cell_blue.jpg b/docs/sphinx/_static/images/sphinxdocs/cell_blue.jpg new file mode 100644 index 00000000..d1debb90 Binary files /dev/null and b/docs/sphinx/_static/images/sphinxdocs/cell_blue.jpg differ diff --git a/docs/sphinx/_static/images/sphinxdocs/cell_grey.jpg b/docs/sphinx/_static/images/sphinxdocs/cell_grey.jpg new file mode 100644 index 00000000..3dac9e16 Binary files /dev/null and b/docs/sphinx/_static/images/sphinxdocs/cell_grey.jpg differ diff --git a/docs/sphinx/_static/images/sphinxdocs/cell_grey.png b/docs/sphinx/_static/images/sphinxdocs/cell_grey.png new file mode 100644 index 00000000..8313efa3 Binary files /dev/null and b/docs/sphinx/_static/images/sphinxdocs/cell_grey.png differ diff --git a/docs/sphinx/_static/images/sphinxdocs/central_bar.png b/docs/sphinx/_static/images/sphinxdocs/central_bar.png new file mode 100644 index 00000000..ad4cfd25 Binary files /dev/null and b/docs/sphinx/_static/images/sphinxdocs/central_bar.png differ diff --git a/docs/sphinx/_static/images/sphinxdocs/class_hierarchy.png b/docs/sphinx/_static/images/sphinxdocs/class_hierarchy.png new file mode 100644 index 00000000..8be40148 Binary files /dev/null and b/docs/sphinx/_static/images/sphinxdocs/class_hierarchy.png differ diff --git a/docs/sphinx/_static/images/sphinxdocs/class_summary.png b/docs/sphinx/_static/images/sphinxdocs/class_summary.png new file mode 100644 index 00000000..ac1ce5c8 Binary files /dev/null and b/docs/sphinx/_static/images/sphinxdocs/class_summary.png differ diff --git a/docs/sphinx/_static/images/sphinxdocs/description.png b/docs/sphinx/_static/images/sphinxdocs/description.png new file mode 100644 index 00000000..7ba99472 Binary files /dev/null and b/docs/sphinx/_static/images/sphinxdocs/description.png differ diff --git a/docs/sphinx/_static/images/sphinxdocs/events.png b/docs/sphinx/_static/images/sphinxdocs/events.png new file mode 100644 index 00000000..871385f4 Binary files /dev/null and b/docs/sphinx/_static/images/sphinxdocs/events.png differ diff --git a/docs/sphinx/_static/images/sphinxdocs/extra_styles.png b/docs/sphinx/_static/images/sphinxdocs/extra_styles.png new file mode 100644 index 00000000..607f76fd Binary files /dev/null and b/docs/sphinx/_static/images/sphinxdocs/extra_styles.png differ diff --git a/docs/sphinx/_static/images/sphinxdocs/file_info.png b/docs/sphinx/_static/images/sphinxdocs/file_info.png new file mode 100644 index 00000000..124c84e5 Binary files /dev/null and b/docs/sphinx/_static/images/sphinxdocs/file_info.png differ diff --git a/docs/sphinx/_static/images/sphinxdocs/globals.png b/docs/sphinx/_static/images/sphinxdocs/globals.png new file mode 100644 index 00000000..7ea95e90 Binary files /dev/null and b/docs/sphinx/_static/images/sphinxdocs/globals.png differ diff --git a/docs/sphinx/_static/images/sphinxdocs/indices.png b/docs/sphinx/_static/images/sphinxdocs/indices.png new file mode 100644 index 00000000..f802ab70 Binary files /dev/null and b/docs/sphinx/_static/images/sphinxdocs/indices.png differ diff --git a/docs/sphinx/_static/images/sphinxdocs/info.png b/docs/sphinx/_static/images/sphinxdocs/info.png new file mode 100644 index 00000000..3b6e1072 Binary files /dev/null and b/docs/sphinx/_static/images/sphinxdocs/info.png differ diff --git a/docs/sphinx/_static/images/sphinxdocs/layout.png b/docs/sphinx/_static/images/sphinxdocs/layout.png new file mode 100644 index 00000000..1ca50bc9 Binary files /dev/null and b/docs/sphinx/_static/images/sphinxdocs/layout.png differ diff --git a/docs/sphinx/_static/images/sphinxdocs/license.png b/docs/sphinx/_static/images/sphinxdocs/license.png new file mode 100644 index 00000000..5bbfe439 Binary files /dev/null and b/docs/sphinx/_static/images/sphinxdocs/license.png differ diff --git a/docs/sphinx/_static/images/sphinxdocs/link.png b/docs/sphinx/_static/images/sphinxdocs/link.png new file mode 100644 index 00000000..34f11bb4 Binary files /dev/null and b/docs/sphinx/_static/images/sphinxdocs/link.png differ diff --git a/docs/sphinx/_static/images/sphinxdocs/method_summary.png b/docs/sphinx/_static/images/sphinxdocs/method_summary.png new file mode 100644 index 00000000..12c77741 Binary files /dev/null and b/docs/sphinx/_static/images/sphinxdocs/method_summary.png differ diff --git a/docs/sphinx/_static/images/sphinxdocs/minus2.png b/docs/sphinx/_static/images/sphinxdocs/minus2.png new file mode 100644 index 00000000..cf72f391 Binary files /dev/null and b/docs/sphinx/_static/images/sphinxdocs/minus2.png differ diff --git a/docs/sphinx/_static/images/sphinxdocs/navigation.png b/docs/sphinx/_static/images/sphinxdocs/navigation.png new file mode 100644 index 00000000..1081dc14 Binary files /dev/null and b/docs/sphinx/_static/images/sphinxdocs/navigation.png differ diff --git a/docs/sphinx/_static/images/sphinxdocs/note.png b/docs/sphinx/_static/images/sphinxdocs/note.png new file mode 100644 index 00000000..d3f2b385 Binary files /dev/null and b/docs/sphinx/_static/images/sphinxdocs/note.png differ diff --git a/docs/sphinx/_static/images/sphinxdocs/orange_gradient.png b/docs/sphinx/_static/images/sphinxdocs/orange_gradient.png new file mode 100644 index 00000000..8c1a4169 Binary files /dev/null and b/docs/sphinx/_static/images/sphinxdocs/orange_gradient.png differ diff --git a/docs/sphinx/_static/images/sphinxdocs/other_info.png b/docs/sphinx/_static/images/sphinxdocs/other_info.png new file mode 100644 index 00000000..ab75f4ca Binary files /dev/null and b/docs/sphinx/_static/images/sphinxdocs/other_info.png differ diff --git a/docs/sphinx/_static/images/sphinxdocs/overload.png b/docs/sphinx/_static/images/sphinxdocs/overload.png new file mode 100644 index 00000000..b2a42817 Binary files /dev/null and b/docs/sphinx/_static/images/sphinxdocs/overload.png differ diff --git a/docs/sphinx/_static/images/sphinxdocs/phoenix_main.png b/docs/sphinx/_static/images/sphinxdocs/phoenix_main.png new file mode 100644 index 00000000..a16468ba Binary files /dev/null and b/docs/sphinx/_static/images/sphinxdocs/phoenix_main.png differ diff --git a/docs/sphinx/_static/images/sphinxdocs/phoenix_small.ico b/docs/sphinx/_static/images/sphinxdocs/phoenix_small.ico new file mode 100644 index 00000000..3ed4f08c Binary files /dev/null and b/docs/sphinx/_static/images/sphinxdocs/phoenix_small.ico differ diff --git a/docs/sphinx/_static/images/sphinxdocs/phoenix_small.png b/docs/sphinx/_static/images/sphinxdocs/phoenix_small.png new file mode 100644 index 00000000..087d1a7e Binary files /dev/null and b/docs/sphinx/_static/images/sphinxdocs/phoenix_small.png differ diff --git a/docs/sphinx/_static/images/sphinxdocs/phoenix_title.png b/docs/sphinx/_static/images/sphinxdocs/phoenix_title.png new file mode 100644 index 00000000..5bf83d85 Binary files /dev/null and b/docs/sphinx/_static/images/sphinxdocs/phoenix_title.png differ diff --git a/docs/sphinx/_static/images/sphinxdocs/phoenix_top.png b/docs/sphinx/_static/images/sphinxdocs/phoenix_top.png new file mode 100644 index 00000000..5faccd0d Binary files /dev/null and b/docs/sphinx/_static/images/sphinxdocs/phoenix_top.png differ diff --git a/docs/sphinx/_static/images/sphinxdocs/platforms.png b/docs/sphinx/_static/images/sphinxdocs/platforms.png new file mode 100644 index 00000000..e5327968 Binary files /dev/null and b/docs/sphinx/_static/images/sphinxdocs/platforms.png differ diff --git a/docs/sphinx/_static/images/sphinxdocs/plus2.png b/docs/sphinx/_static/images/sphinxdocs/plus2.png new file mode 100644 index 00000000..ebcd27d8 Binary files /dev/null and b/docs/sphinx/_static/images/sphinxdocs/plus2.png differ diff --git a/docs/sphinx/_static/images/sphinxdocs/property_summary.png b/docs/sphinx/_static/images/sphinxdocs/property_summary.png new file mode 100644 index 00000000..9d8565af Binary files /dev/null and b/docs/sphinx/_static/images/sphinxdocs/property_summary.png differ diff --git a/docs/sphinx/_static/images/sphinxdocs/python.png b/docs/sphinx/_static/images/sphinxdocs/python.png new file mode 100644 index 00000000..34d3fdd6 Binary files /dev/null and b/docs/sphinx/_static/images/sphinxdocs/python.png differ diff --git a/docs/sphinx/_static/images/sphinxdocs/seealso.png b/docs/sphinx/_static/images/sphinxdocs/seealso.png new file mode 100644 index 00000000..59845270 Binary files /dev/null and b/docs/sphinx/_static/images/sphinxdocs/seealso.png differ diff --git a/docs/sphinx/_static/images/sphinxdocs/settings.png b/docs/sphinx/_static/images/sphinxdocs/settings.png new file mode 100644 index 00000000..1f04d857 Binary files /dev/null and b/docs/sphinx/_static/images/sphinxdocs/settings.png differ diff --git a/docs/sphinx/_static/images/sphinxdocs/styles.png b/docs/sphinx/_static/images/sphinxdocs/styles.png new file mode 100644 index 00000000..2e29a93a Binary files /dev/null and b/docs/sphinx/_static/images/sphinxdocs/styles.png differ diff --git a/docs/sphinx/_static/images/sphinxdocs/sub_classes.png b/docs/sphinx/_static/images/sphinxdocs/sub_classes.png new file mode 100644 index 00000000..31154a2b Binary files /dev/null and b/docs/sphinx/_static/images/sphinxdocs/sub_classes.png differ diff --git a/docs/sphinx/_static/images/sphinxdocs/super_classes.png b/docs/sphinx/_static/images/sphinxdocs/super_classes.png new file mode 100644 index 00000000..f35fc53b Binary files /dev/null and b/docs/sphinx/_static/images/sphinxdocs/super_classes.png differ diff --git a/docs/sphinx/_static/images/sphinxdocs/table_contents.png b/docs/sphinx/_static/images/sphinxdocs/table_contents.png new file mode 100644 index 00000000..2e86079c Binary files /dev/null and b/docs/sphinx/_static/images/sphinxdocs/table_contents.png differ diff --git a/docs/sphinx/_static/images/sphinxdocs/ticks_green.png b/docs/sphinx/_static/images/sphinxdocs/ticks_green.png new file mode 100644 index 00000000..f4e49913 Binary files /dev/null and b/docs/sphinx/_static/images/sphinxdocs/ticks_green.png differ diff --git a/docs/sphinx/_static/images/sphinxdocs/ticks_red.png b/docs/sphinx/_static/images/sphinxdocs/ticks_red.png new file mode 100644 index 00000000..9754ef6d Binary files /dev/null and b/docs/sphinx/_static/images/sphinxdocs/ticks_red.png differ diff --git a/docs/sphinx/_static/images/sphinxdocs/todo.png b/docs/sphinx/_static/images/sphinxdocs/todo.png new file mode 100644 index 00000000..dfdd3892 Binary files /dev/null and b/docs/sphinx/_static/images/sphinxdocs/todo.png differ diff --git a/docs/sphinx/_static/images/sphinxdocs/todo_big.png b/docs/sphinx/_static/images/sphinxdocs/todo_big.png new file mode 100644 index 00000000..2235e0e4 Binary files /dev/null and b/docs/sphinx/_static/images/sphinxdocs/todo_big.png differ diff --git a/docs/sphinx/_static/images/sphinxdocs/usage.png b/docs/sphinx/_static/images/sphinxdocs/usage.png new file mode 100644 index 00000000..db6bdeb7 Binary files /dev/null and b/docs/sphinx/_static/images/sphinxdocs/usage.png differ diff --git a/docs/sphinx/_static/images/sphinxdocs/viewmag.png b/docs/sphinx/_static/images/sphinxdocs/viewmag.png new file mode 100644 index 00000000..de5ef3a1 Binary files /dev/null and b/docs/sphinx/_static/images/sphinxdocs/viewmag.png differ diff --git a/docs/sphinx/_static/images/sphinxdocs/warning.png b/docs/sphinx/_static/images/sphinxdocs/warning.png new file mode 100644 index 00000000..d98aa433 Binary files /dev/null and b/docs/sphinx/_static/images/sphinxdocs/warning.png differ diff --git a/docs/sphinx/_static/images/sphinxdocs/whatsnew.png b/docs/sphinx/_static/images/sphinxdocs/whatsnew.png new file mode 100644 index 00000000..b7bfad2e Binary files /dev/null and b/docs/sphinx/_static/images/sphinxdocs/whatsnew.png differ diff --git a/docs/sphinx/_static/images/stock/gtk-about.png b/docs/sphinx/_static/images/stock/gtk-about.png new file mode 100644 index 00000000..010d294a Binary files /dev/null and b/docs/sphinx/_static/images/stock/gtk-about.png differ diff --git a/docs/sphinx/_static/images/stock/gtk-add.png b/docs/sphinx/_static/images/stock/gtk-add.png new file mode 100644 index 00000000..9cd9e5cf Binary files /dev/null and b/docs/sphinx/_static/images/stock/gtk-add.png differ diff --git a/docs/sphinx/_static/images/stock/gtk-apply.png b/docs/sphinx/_static/images/stock/gtk-apply.png new file mode 100644 index 00000000..afca0732 Binary files /dev/null and b/docs/sphinx/_static/images/stock/gtk-apply.png differ diff --git a/docs/sphinx/_static/images/stock/gtk-bold.png b/docs/sphinx/_static/images/stock/gtk-bold.png new file mode 100644 index 00000000..7e2c5dba Binary files /dev/null and b/docs/sphinx/_static/images/stock/gtk-bold.png differ diff --git a/docs/sphinx/_static/images/stock/gtk-cancel.png b/docs/sphinx/_static/images/stock/gtk-cancel.png new file mode 100644 index 00000000..0a395c09 Binary files /dev/null and b/docs/sphinx/_static/images/stock/gtk-cancel.png differ diff --git a/docs/sphinx/_static/images/stock/gtk-cdrom.png b/docs/sphinx/_static/images/stock/gtk-cdrom.png new file mode 100644 index 00000000..922f452f Binary files /dev/null and b/docs/sphinx/_static/images/stock/gtk-cdrom.png differ diff --git a/docs/sphinx/_static/images/stock/gtk-clear.png b/docs/sphinx/_static/images/stock/gtk-clear.png new file mode 100644 index 00000000..1556dfee Binary files /dev/null and b/docs/sphinx/_static/images/stock/gtk-clear.png differ diff --git a/docs/sphinx/_static/images/stock/gtk-close.png b/docs/sphinx/_static/images/stock/gtk-close.png new file mode 100644 index 00000000..52f58630 Binary files /dev/null and b/docs/sphinx/_static/images/stock/gtk-close.png differ diff --git a/docs/sphinx/_static/images/stock/gtk-convert.png b/docs/sphinx/_static/images/stock/gtk-convert.png new file mode 100644 index 00000000..e4d91257 Binary files /dev/null and b/docs/sphinx/_static/images/stock/gtk-convert.png differ diff --git a/docs/sphinx/_static/images/stock/gtk-copy.png b/docs/sphinx/_static/images/stock/gtk-copy.png new file mode 100644 index 00000000..8dd48c49 Binary files /dev/null and b/docs/sphinx/_static/images/stock/gtk-copy.png differ diff --git a/docs/sphinx/_static/images/stock/gtk-cut.png b/docs/sphinx/_static/images/stock/gtk-cut.png new file mode 100644 index 00000000..ff87558f Binary files /dev/null and b/docs/sphinx/_static/images/stock/gtk-cut.png differ diff --git a/docs/sphinx/_static/images/stock/gtk-delete.png b/docs/sphinx/_static/images/stock/gtk-delete.png new file mode 100644 index 00000000..2c5a4673 Binary files /dev/null and b/docs/sphinx/_static/images/stock/gtk-delete.png differ diff --git a/docs/sphinx/_static/images/stock/gtk-edit.png b/docs/sphinx/_static/images/stock/gtk-edit.png new file mode 100644 index 00000000..c5da3f9f Binary files /dev/null and b/docs/sphinx/_static/images/stock/gtk-edit.png differ diff --git a/docs/sphinx/_static/images/stock/gtk-execute.png b/docs/sphinx/_static/images/stock/gtk-execute.png new file mode 100644 index 00000000..c9c48d6a Binary files /dev/null and b/docs/sphinx/_static/images/stock/gtk-execute.png differ diff --git a/docs/sphinx/_static/images/stock/gtk-file.png b/docs/sphinx/_static/images/stock/gtk-file.png new file mode 100644 index 00000000..7cd94435 Binary files /dev/null and b/docs/sphinx/_static/images/stock/gtk-file.png differ diff --git a/docs/sphinx/_static/images/stock/gtk-find-and-replace.png b/docs/sphinx/_static/images/stock/gtk-find-and-replace.png new file mode 100644 index 00000000..fca34f52 Binary files /dev/null and b/docs/sphinx/_static/images/stock/gtk-find-and-replace.png differ diff --git a/docs/sphinx/_static/images/stock/gtk-find.png b/docs/sphinx/_static/images/stock/gtk-find.png new file mode 100644 index 00000000..e9a40950 Binary files /dev/null and b/docs/sphinx/_static/images/stock/gtk-find.png differ diff --git a/docs/sphinx/_static/images/stock/gtk-floppy.png b/docs/sphinx/_static/images/stock/gtk-floppy.png new file mode 100644 index 00000000..18b7d241 Binary files /dev/null and b/docs/sphinx/_static/images/stock/gtk-floppy.png differ diff --git a/docs/sphinx/_static/images/stock/gtk-go-back-ltr.png b/docs/sphinx/_static/images/stock/gtk-go-back-ltr.png new file mode 100644 index 00000000..9e77ac2e Binary files /dev/null and b/docs/sphinx/_static/images/stock/gtk-go-back-ltr.png differ diff --git a/docs/sphinx/_static/images/stock/gtk-go-down.png b/docs/sphinx/_static/images/stock/gtk-go-down.png new file mode 100644 index 00000000..dcde30f0 Binary files /dev/null and b/docs/sphinx/_static/images/stock/gtk-go-down.png differ diff --git a/docs/sphinx/_static/images/stock/gtk-go-forward-ltr.png b/docs/sphinx/_static/images/stock/gtk-go-forward-ltr.png new file mode 100644 index 00000000..5b9e3f0d Binary files /dev/null and b/docs/sphinx/_static/images/stock/gtk-go-forward-ltr.png differ diff --git a/docs/sphinx/_static/images/stock/gtk-go-up.png b/docs/sphinx/_static/images/stock/gtk-go-up.png new file mode 100644 index 00000000..432225f5 Binary files /dev/null and b/docs/sphinx/_static/images/stock/gtk-go-up.png differ diff --git a/docs/sphinx/_static/images/stock/gtk-goto-bottom.png b/docs/sphinx/_static/images/stock/gtk-goto-bottom.png new file mode 100644 index 00000000..69aaafc2 Binary files /dev/null and b/docs/sphinx/_static/images/stock/gtk-goto-bottom.png differ diff --git a/docs/sphinx/_static/images/stock/gtk-goto-first-ltr.png b/docs/sphinx/_static/images/stock/gtk-goto-first-ltr.png new file mode 100644 index 00000000..689ba0a9 Binary files /dev/null and b/docs/sphinx/_static/images/stock/gtk-goto-first-ltr.png differ diff --git a/docs/sphinx/_static/images/stock/gtk-goto-last-ltr.png b/docs/sphinx/_static/images/stock/gtk-goto-last-ltr.png new file mode 100644 index 00000000..a653e10e Binary files /dev/null and b/docs/sphinx/_static/images/stock/gtk-goto-last-ltr.png differ diff --git a/docs/sphinx/_static/images/stock/gtk-goto-top.png b/docs/sphinx/_static/images/stock/gtk-goto-top.png new file mode 100644 index 00000000..0a3b1bfb Binary files /dev/null and b/docs/sphinx/_static/images/stock/gtk-goto-top.png differ diff --git a/docs/sphinx/_static/images/stock/gtk-harddisk.png b/docs/sphinx/_static/images/stock/gtk-harddisk.png new file mode 100644 index 00000000..b714d86e Binary files /dev/null and b/docs/sphinx/_static/images/stock/gtk-harddisk.png differ diff --git a/docs/sphinx/_static/images/stock/gtk-help.png b/docs/sphinx/_static/images/stock/gtk-help.png new file mode 100644 index 00000000..20ae955c Binary files /dev/null and b/docs/sphinx/_static/images/stock/gtk-help.png differ diff --git a/docs/sphinx/_static/images/stock/gtk-home.png b/docs/sphinx/_static/images/stock/gtk-home.png new file mode 100644 index 00000000..fadd43dc Binary files /dev/null and b/docs/sphinx/_static/images/stock/gtk-home.png differ diff --git a/docs/sphinx/_static/images/stock/gtk-indent-ltr.png b/docs/sphinx/_static/images/stock/gtk-indent-ltr.png new file mode 100644 index 00000000..b00e2184 Binary files /dev/null and b/docs/sphinx/_static/images/stock/gtk-indent-ltr.png differ diff --git a/docs/sphinx/_static/images/stock/gtk-index.png b/docs/sphinx/_static/images/stock/gtk-index.png new file mode 100644 index 00000000..0967a61c Binary files /dev/null and b/docs/sphinx/_static/images/stock/gtk-index.png differ diff --git a/docs/sphinx/_static/images/stock/gtk-info.png b/docs/sphinx/_static/images/stock/gtk-info.png new file mode 100644 index 00000000..df87def2 Binary files /dev/null and b/docs/sphinx/_static/images/stock/gtk-info.png differ diff --git a/docs/sphinx/_static/images/stock/gtk-italic.png b/docs/sphinx/_static/images/stock/gtk-italic.png new file mode 100644 index 00000000..867df5de Binary files /dev/null and b/docs/sphinx/_static/images/stock/gtk-italic.png differ diff --git a/docs/sphinx/_static/images/stock/gtk-jump-to-ltr.png b/docs/sphinx/_static/images/stock/gtk-jump-to-ltr.png new file mode 100644 index 00000000..0f0f57a1 Binary files /dev/null and b/docs/sphinx/_static/images/stock/gtk-jump-to-ltr.png differ diff --git a/docs/sphinx/_static/images/stock/gtk-justify-center.png b/docs/sphinx/_static/images/stock/gtk-justify-center.png new file mode 100644 index 00000000..57d6a0e3 Binary files /dev/null and b/docs/sphinx/_static/images/stock/gtk-justify-center.png differ diff --git a/docs/sphinx/_static/images/stock/gtk-justify-fill.png b/docs/sphinx/_static/images/stock/gtk-justify-fill.png new file mode 100644 index 00000000..a416b25a Binary files /dev/null and b/docs/sphinx/_static/images/stock/gtk-justify-fill.png differ diff --git a/docs/sphinx/_static/images/stock/gtk-justify-left.png b/docs/sphinx/_static/images/stock/gtk-justify-left.png new file mode 100644 index 00000000..9a7abf7f Binary files /dev/null and b/docs/sphinx/_static/images/stock/gtk-justify-left.png differ diff --git a/docs/sphinx/_static/images/stock/gtk-justify-right.png b/docs/sphinx/_static/images/stock/gtk-justify-right.png new file mode 100644 index 00000000..15b50733 Binary files /dev/null and b/docs/sphinx/_static/images/stock/gtk-justify-right.png differ diff --git a/docs/sphinx/_static/images/stock/gtk-network.png b/docs/sphinx/_static/images/stock/gtk-network.png new file mode 100644 index 00000000..e74e060e Binary files /dev/null and b/docs/sphinx/_static/images/stock/gtk-network.png differ diff --git a/docs/sphinx/_static/images/stock/gtk-new.png b/docs/sphinx/_static/images/stock/gtk-new.png new file mode 100644 index 00000000..7cd94435 Binary files /dev/null and b/docs/sphinx/_static/images/stock/gtk-new.png differ diff --git a/docs/sphinx/_static/images/stock/gtk-no.png b/docs/sphinx/_static/images/stock/gtk-no.png new file mode 100644 index 00000000..2a7da6e2 Binary files /dev/null and b/docs/sphinx/_static/images/stock/gtk-no.png differ diff --git a/docs/sphinx/_static/images/stock/gtk-ok.png b/docs/sphinx/_static/images/stock/gtk-ok.png new file mode 100644 index 00000000..c08115f6 Binary files /dev/null and b/docs/sphinx/_static/images/stock/gtk-ok.png differ diff --git a/docs/sphinx/_static/images/stock/gtk-open.png b/docs/sphinx/_static/images/stock/gtk-open.png new file mode 100644 index 00000000..47618537 Binary files /dev/null and b/docs/sphinx/_static/images/stock/gtk-open.png differ diff --git a/docs/sphinx/_static/images/stock/gtk-paste.png b/docs/sphinx/_static/images/stock/gtk-paste.png new file mode 100644 index 00000000..24588a3a Binary files /dev/null and b/docs/sphinx/_static/images/stock/gtk-paste.png differ diff --git a/docs/sphinx/_static/images/stock/gtk-preferences.png b/docs/sphinx/_static/images/stock/gtk-preferences.png new file mode 100644 index 00000000..9703a40d Binary files /dev/null and b/docs/sphinx/_static/images/stock/gtk-preferences.png differ diff --git a/docs/sphinx/_static/images/stock/gtk-print-preview.png b/docs/sphinx/_static/images/stock/gtk-print-preview.png new file mode 100644 index 00000000..45b44f32 Binary files /dev/null and b/docs/sphinx/_static/images/stock/gtk-print-preview.png differ diff --git a/docs/sphinx/_static/images/stock/gtk-print.png b/docs/sphinx/_static/images/stock/gtk-print.png new file mode 100644 index 00000000..5997b922 Binary files /dev/null and b/docs/sphinx/_static/images/stock/gtk-print.png differ diff --git a/docs/sphinx/_static/images/stock/gtk-properties.png b/docs/sphinx/_static/images/stock/gtk-properties.png new file mode 100644 index 00000000..65d22e4f Binary files /dev/null and b/docs/sphinx/_static/images/stock/gtk-properties.png differ diff --git a/docs/sphinx/_static/images/stock/gtk-quit.png b/docs/sphinx/_static/images/stock/gtk-quit.png new file mode 100644 index 00000000..d070809f Binary files /dev/null and b/docs/sphinx/_static/images/stock/gtk-quit.png differ diff --git a/docs/sphinx/_static/images/stock/gtk-redo-ltr.png b/docs/sphinx/_static/images/stock/gtk-redo-ltr.png new file mode 100644 index 00000000..f7923083 Binary files /dev/null and b/docs/sphinx/_static/images/stock/gtk-redo-ltr.png differ diff --git a/docs/sphinx/_static/images/stock/gtk-refresh.png b/docs/sphinx/_static/images/stock/gtk-refresh.png new file mode 100644 index 00000000..e9ea8c4e Binary files /dev/null and b/docs/sphinx/_static/images/stock/gtk-refresh.png differ diff --git a/docs/sphinx/_static/images/stock/gtk-remove.png b/docs/sphinx/_static/images/stock/gtk-remove.png new file mode 100644 index 00000000..0ed9c221 Binary files /dev/null and b/docs/sphinx/_static/images/stock/gtk-remove.png differ diff --git a/docs/sphinx/_static/images/stock/gtk-revert-to-saved-ltr.png b/docs/sphinx/_static/images/stock/gtk-revert-to-saved-ltr.png new file mode 100644 index 00000000..026014ca Binary files /dev/null and b/docs/sphinx/_static/images/stock/gtk-revert-to-saved-ltr.png differ diff --git a/docs/sphinx/_static/images/stock/gtk-save-as.png b/docs/sphinx/_static/images/stock/gtk-save-as.png new file mode 100644 index 00000000..3409adc7 Binary files /dev/null and b/docs/sphinx/_static/images/stock/gtk-save-as.png differ diff --git a/docs/sphinx/_static/images/stock/gtk-save.png b/docs/sphinx/_static/images/stock/gtk-save.png new file mode 100644 index 00000000..18b7d241 Binary files /dev/null and b/docs/sphinx/_static/images/stock/gtk-save.png differ diff --git a/docs/sphinx/_static/images/stock/gtk-select-all.png b/docs/sphinx/_static/images/stock/gtk-select-all.png new file mode 100644 index 00000000..e3bd4ba7 Binary files /dev/null and b/docs/sphinx/_static/images/stock/gtk-select-all.png differ diff --git a/docs/sphinx/_static/images/stock/gtk-select-color.png b/docs/sphinx/_static/images/stock/gtk-select-color.png new file mode 100644 index 00000000..2c764b37 Binary files /dev/null and b/docs/sphinx/_static/images/stock/gtk-select-color.png differ diff --git a/docs/sphinx/_static/images/stock/gtk-select-font.png b/docs/sphinx/_static/images/stock/gtk-select-font.png new file mode 100644 index 00000000..2514b616 Binary files /dev/null and b/docs/sphinx/_static/images/stock/gtk-select-font.png differ diff --git a/docs/sphinx/_static/images/stock/gtk-sort-ascending.png b/docs/sphinx/_static/images/stock/gtk-sort-ascending.png new file mode 100644 index 00000000..3f8fd257 Binary files /dev/null and b/docs/sphinx/_static/images/stock/gtk-sort-ascending.png differ diff --git a/docs/sphinx/_static/images/stock/gtk-sort-descending.png b/docs/sphinx/_static/images/stock/gtk-sort-descending.png new file mode 100644 index 00000000..a8aa7058 Binary files /dev/null and b/docs/sphinx/_static/images/stock/gtk-sort-descending.png differ diff --git a/docs/sphinx/_static/images/stock/gtk-spell-check.png b/docs/sphinx/_static/images/stock/gtk-spell-check.png new file mode 100644 index 00000000..32dcc2e6 Binary files /dev/null and b/docs/sphinx/_static/images/stock/gtk-spell-check.png differ diff --git a/docs/sphinx/_static/images/stock/gtk-stop.png b/docs/sphinx/_static/images/stock/gtk-stop.png new file mode 100644 index 00000000..d88fed70 Binary files /dev/null and b/docs/sphinx/_static/images/stock/gtk-stop.png differ diff --git a/docs/sphinx/_static/images/stock/gtk-strikethrough.png b/docs/sphinx/_static/images/stock/gtk-strikethrough.png new file mode 100644 index 00000000..8a844a3a Binary files /dev/null and b/docs/sphinx/_static/images/stock/gtk-strikethrough.png differ diff --git a/docs/sphinx/_static/images/stock/gtk-undelete-ltr.png b/docs/sphinx/_static/images/stock/gtk-undelete-ltr.png new file mode 100644 index 00000000..cc58d0fb Binary files /dev/null and b/docs/sphinx/_static/images/stock/gtk-undelete-ltr.png differ diff --git a/docs/sphinx/_static/images/stock/gtk-underline.png b/docs/sphinx/_static/images/stock/gtk-underline.png new file mode 100644 index 00000000..35bcc812 Binary files /dev/null and b/docs/sphinx/_static/images/stock/gtk-underline.png differ diff --git a/docs/sphinx/_static/images/stock/gtk-undo-ltr.png b/docs/sphinx/_static/images/stock/gtk-undo-ltr.png new file mode 100644 index 00000000..b0c8a48d Binary files /dev/null and b/docs/sphinx/_static/images/stock/gtk-undo-ltr.png differ diff --git a/docs/sphinx/_static/images/stock/gtk-unindent-ltr.png b/docs/sphinx/_static/images/stock/gtk-unindent-ltr.png new file mode 100644 index 00000000..776f5767 Binary files /dev/null and b/docs/sphinx/_static/images/stock/gtk-unindent-ltr.png differ diff --git a/docs/sphinx/_static/images/stock/gtk-yes.png b/docs/sphinx/_static/images/stock/gtk-yes.png new file mode 100644 index 00000000..e5623663 Binary files /dev/null and b/docs/sphinx/_static/images/stock/gtk-yes.png differ diff --git a/docs/sphinx/_static/images/stock/gtk-zoom-100.png b/docs/sphinx/_static/images/stock/gtk-zoom-100.png new file mode 100644 index 00000000..92dddd2e Binary files /dev/null and b/docs/sphinx/_static/images/stock/gtk-zoom-100.png differ diff --git a/docs/sphinx/_static/images/stock/gtk-zoom-fit.png b/docs/sphinx/_static/images/stock/gtk-zoom-fit.png new file mode 100644 index 00000000..adbf7f3a Binary files /dev/null and b/docs/sphinx/_static/images/stock/gtk-zoom-fit.png differ diff --git a/docs/sphinx/_static/images/stock/gtk-zoom-in.png b/docs/sphinx/_static/images/stock/gtk-zoom-in.png new file mode 100644 index 00000000..6b1b9433 Binary files /dev/null and b/docs/sphinx/_static/images/stock/gtk-zoom-in.png differ diff --git a/docs/sphinx/_static/images/stock/gtk-zoom-out.png b/docs/sphinx/_static/images/stock/gtk-zoom-out.png new file mode 100644 index 00000000..ddc1eb13 Binary files /dev/null and b/docs/sphinx/_static/images/stock/gtk-zoom-out.png differ diff --git a/docs/sphinx/_static/images/widgets/fullsize/no_appearance.png b/docs/sphinx/_static/images/widgets/fullsize/no_appearance.png new file mode 100644 index 00000000..b4538d21 Binary files /dev/null and b/docs/sphinx/_static/images/widgets/fullsize/no_appearance.png differ diff --git a/docs/sphinx/_static/images/widgets/fullsize/wxgtk/bitmapbutton.png b/docs/sphinx/_static/images/widgets/fullsize/wxgtk/bitmapbutton.png new file mode 100644 index 00000000..7dbc6659 Binary files /dev/null and b/docs/sphinx/_static/images/widgets/fullsize/wxgtk/bitmapbutton.png differ diff --git a/docs/sphinx/_static/images/widgets/fullsize/wxgtk/button.png b/docs/sphinx/_static/images/widgets/fullsize/wxgtk/button.png new file mode 100644 index 00000000..77517a19 Binary files /dev/null and b/docs/sphinx/_static/images/widgets/fullsize/wxgtk/button.png differ diff --git a/docs/sphinx/_static/images/widgets/fullsize/wxgtk/checkbox.png b/docs/sphinx/_static/images/widgets/fullsize/wxgtk/checkbox.png new file mode 100644 index 00000000..54ceec04 Binary files /dev/null and b/docs/sphinx/_static/images/widgets/fullsize/wxgtk/checkbox.png differ diff --git a/docs/sphinx/_static/images/widgets/fullsize/wxgtk/checklistbox.png b/docs/sphinx/_static/images/widgets/fullsize/wxgtk/checklistbox.png new file mode 100644 index 00000000..9d008c32 Binary files /dev/null and b/docs/sphinx/_static/images/widgets/fullsize/wxgtk/checklistbox.png differ diff --git a/docs/sphinx/_static/images/widgets/fullsize/wxgtk/choice.png b/docs/sphinx/_static/images/widgets/fullsize/wxgtk/choice.png new file mode 100644 index 00000000..794dc9fe Binary files /dev/null and b/docs/sphinx/_static/images/widgets/fullsize/wxgtk/choice.png differ diff --git a/docs/sphinx/_static/images/widgets/fullsize/wxgtk/collapsiblepane.png b/docs/sphinx/_static/images/widgets/fullsize/wxgtk/collapsiblepane.png new file mode 100644 index 00000000..950f6cb1 Binary files /dev/null and b/docs/sphinx/_static/images/widgets/fullsize/wxgtk/collapsiblepane.png differ diff --git a/docs/sphinx/_static/images/widgets/fullsize/wxgtk/combobox.png b/docs/sphinx/_static/images/widgets/fullsize/wxgtk/combobox.png new file mode 100644 index 00000000..6d1c73b8 Binary files /dev/null and b/docs/sphinx/_static/images/widgets/fullsize/wxgtk/combobox.png differ diff --git a/docs/sphinx/_static/images/widgets/fullsize/wxgtk/dataview.dataviewctrl.png b/docs/sphinx/_static/images/widgets/fullsize/wxgtk/dataview.dataviewctrl.png new file mode 100644 index 00000000..f352a7d8 Binary files /dev/null and b/docs/sphinx/_static/images/widgets/fullsize/wxgtk/dataview.dataviewctrl.png differ diff --git a/docs/sphinx/_static/images/widgets/fullsize/wxgtk/gauge.png b/docs/sphinx/_static/images/widgets/fullsize/wxgtk/gauge.png new file mode 100644 index 00000000..926254f7 Binary files /dev/null and b/docs/sphinx/_static/images/widgets/fullsize/wxgtk/gauge.png differ diff --git a/docs/sphinx/_static/images/widgets/fullsize/wxgtk/listbox.png b/docs/sphinx/_static/images/widgets/fullsize/wxgtk/listbox.png new file mode 100644 index 00000000..ff8edfdd Binary files /dev/null and b/docs/sphinx/_static/images/widgets/fullsize/wxgtk/listbox.png differ diff --git a/docs/sphinx/_static/images/widgets/fullsize/wxgtk/notebook.png b/docs/sphinx/_static/images/widgets/fullsize/wxgtk/notebook.png new file mode 100644 index 00000000..47af9721 Binary files /dev/null and b/docs/sphinx/_static/images/widgets/fullsize/wxgtk/notebook.png differ diff --git a/docs/sphinx/_static/images/widgets/fullsize/wxgtk/radiobox.png b/docs/sphinx/_static/images/widgets/fullsize/wxgtk/radiobox.png new file mode 100644 index 00000000..d76a0cae Binary files /dev/null and b/docs/sphinx/_static/images/widgets/fullsize/wxgtk/radiobox.png differ diff --git a/docs/sphinx/_static/images/widgets/fullsize/wxgtk/radiobutton.png b/docs/sphinx/_static/images/widgets/fullsize/wxgtk/radiobutton.png new file mode 100644 index 00000000..32a2ffb3 Binary files /dev/null and b/docs/sphinx/_static/images/widgets/fullsize/wxgtk/radiobutton.png differ diff --git a/docs/sphinx/_static/images/widgets/fullsize/wxgtk/searchctrl.png b/docs/sphinx/_static/images/widgets/fullsize/wxgtk/searchctrl.png new file mode 100644 index 00000000..429478d5 Binary files /dev/null and b/docs/sphinx/_static/images/widgets/fullsize/wxgtk/searchctrl.png differ diff --git a/docs/sphinx/_static/images/widgets/fullsize/wxgtk/slider.png b/docs/sphinx/_static/images/widgets/fullsize/wxgtk/slider.png new file mode 100644 index 00000000..dfb09437 Binary files /dev/null and b/docs/sphinx/_static/images/widgets/fullsize/wxgtk/slider.png differ diff --git a/docs/sphinx/_static/images/widgets/fullsize/wxgtk/spinbutton.png b/docs/sphinx/_static/images/widgets/fullsize/wxgtk/spinbutton.png new file mode 100644 index 00000000..18cadf66 Binary files /dev/null and b/docs/sphinx/_static/images/widgets/fullsize/wxgtk/spinbutton.png differ diff --git a/docs/sphinx/_static/images/widgets/fullsize/wxgtk/spinctrl.png b/docs/sphinx/_static/images/widgets/fullsize/wxgtk/spinctrl.png new file mode 100644 index 00000000..50e1b432 Binary files /dev/null and b/docs/sphinx/_static/images/widgets/fullsize/wxgtk/spinctrl.png differ diff --git a/docs/sphinx/_static/images/widgets/fullsize/wxgtk/spinctrldouble.png b/docs/sphinx/_static/images/widgets/fullsize/wxgtk/spinctrldouble.png new file mode 100644 index 00000000..d37b9a3a Binary files /dev/null and b/docs/sphinx/_static/images/widgets/fullsize/wxgtk/spinctrldouble.png differ diff --git a/docs/sphinx/_static/images/widgets/fullsize/wxgtk/staticbitmap.png b/docs/sphinx/_static/images/widgets/fullsize/wxgtk/staticbitmap.png new file mode 100644 index 00000000..cd2c86f8 Binary files /dev/null and b/docs/sphinx/_static/images/widgets/fullsize/wxgtk/staticbitmap.png differ diff --git a/docs/sphinx/_static/images/widgets/fullsize/wxgtk/staticbox.png b/docs/sphinx/_static/images/widgets/fullsize/wxgtk/staticbox.png new file mode 100644 index 00000000..4a9055f6 Binary files /dev/null and b/docs/sphinx/_static/images/widgets/fullsize/wxgtk/staticbox.png differ diff --git a/docs/sphinx/_static/images/widgets/fullsize/wxgtk/statictext.png b/docs/sphinx/_static/images/widgets/fullsize/wxgtk/statictext.png new file mode 100644 index 00000000..9db980da Binary files /dev/null and b/docs/sphinx/_static/images/widgets/fullsize/wxgtk/statictext.png differ diff --git a/docs/sphinx/_static/images/widgets/fullsize/wxgtk/textctrl.png b/docs/sphinx/_static/images/widgets/fullsize/wxgtk/textctrl.png new file mode 100644 index 00000000..dfbd8486 Binary files /dev/null and b/docs/sphinx/_static/images/widgets/fullsize/wxgtk/textctrl.png differ diff --git a/docs/sphinx/_static/images/widgets/fullsize/wxgtk/togglebutton.png b/docs/sphinx/_static/images/widgets/fullsize/wxgtk/togglebutton.png new file mode 100644 index 00000000..2790f5de Binary files /dev/null and b/docs/sphinx/_static/images/widgets/fullsize/wxgtk/togglebutton.png differ diff --git a/docs/sphinx/_static/images/widgets/fullsize/wxmac/bitmapbutton.png b/docs/sphinx/_static/images/widgets/fullsize/wxmac/bitmapbutton.png new file mode 100644 index 00000000..0a6b8a43 Binary files /dev/null and b/docs/sphinx/_static/images/widgets/fullsize/wxmac/bitmapbutton.png differ diff --git a/docs/sphinx/_static/images/widgets/fullsize/wxmac/button.png b/docs/sphinx/_static/images/widgets/fullsize/wxmac/button.png new file mode 100644 index 00000000..78755128 Binary files /dev/null and b/docs/sphinx/_static/images/widgets/fullsize/wxmac/button.png differ diff --git a/docs/sphinx/_static/images/widgets/fullsize/wxmac/checkbox.png b/docs/sphinx/_static/images/widgets/fullsize/wxmac/checkbox.png new file mode 100644 index 00000000..63b083bd Binary files /dev/null and b/docs/sphinx/_static/images/widgets/fullsize/wxmac/checkbox.png differ diff --git a/docs/sphinx/_static/images/widgets/fullsize/wxmac/checklistbox.png b/docs/sphinx/_static/images/widgets/fullsize/wxmac/checklistbox.png new file mode 100644 index 00000000..8e848e0f Binary files /dev/null and b/docs/sphinx/_static/images/widgets/fullsize/wxmac/checklistbox.png differ diff --git a/docs/sphinx/_static/images/widgets/fullsize/wxmac/choice.png b/docs/sphinx/_static/images/widgets/fullsize/wxmac/choice.png new file mode 100644 index 00000000..85bef69a Binary files /dev/null and b/docs/sphinx/_static/images/widgets/fullsize/wxmac/choice.png differ diff --git a/docs/sphinx/_static/images/widgets/fullsize/wxmac/collapsiblepane.png b/docs/sphinx/_static/images/widgets/fullsize/wxmac/collapsiblepane.png new file mode 100644 index 00000000..7b7ac2b9 Binary files /dev/null and b/docs/sphinx/_static/images/widgets/fullsize/wxmac/collapsiblepane.png differ diff --git a/docs/sphinx/_static/images/widgets/fullsize/wxmac/combobox.png b/docs/sphinx/_static/images/widgets/fullsize/wxmac/combobox.png new file mode 100644 index 00000000..b939e2f7 Binary files /dev/null and b/docs/sphinx/_static/images/widgets/fullsize/wxmac/combobox.png differ diff --git a/docs/sphinx/_static/images/widgets/fullsize/wxmac/dataview.dataviewctrl.png b/docs/sphinx/_static/images/widgets/fullsize/wxmac/dataview.dataviewctrl.png new file mode 100644 index 00000000..6cf948d3 Binary files /dev/null and b/docs/sphinx/_static/images/widgets/fullsize/wxmac/dataview.dataviewctrl.png differ diff --git a/docs/sphinx/_static/images/widgets/fullsize/wxmac/gauge.png b/docs/sphinx/_static/images/widgets/fullsize/wxmac/gauge.png new file mode 100644 index 00000000..f6e69ac2 Binary files /dev/null and b/docs/sphinx/_static/images/widgets/fullsize/wxmac/gauge.png differ diff --git a/docs/sphinx/_static/images/widgets/fullsize/wxmac/listbox.png b/docs/sphinx/_static/images/widgets/fullsize/wxmac/listbox.png new file mode 100644 index 00000000..d1cd3e82 Binary files /dev/null and b/docs/sphinx/_static/images/widgets/fullsize/wxmac/listbox.png differ diff --git a/docs/sphinx/_static/images/widgets/fullsize/wxmac/notebook.png b/docs/sphinx/_static/images/widgets/fullsize/wxmac/notebook.png new file mode 100644 index 00000000..99de7c10 Binary files /dev/null and b/docs/sphinx/_static/images/widgets/fullsize/wxmac/notebook.png differ diff --git a/docs/sphinx/_static/images/widgets/fullsize/wxmac/radiobox.png b/docs/sphinx/_static/images/widgets/fullsize/wxmac/radiobox.png new file mode 100644 index 00000000..09d7886e Binary files /dev/null and b/docs/sphinx/_static/images/widgets/fullsize/wxmac/radiobox.png differ diff --git a/docs/sphinx/_static/images/widgets/fullsize/wxmac/radiobutton.png b/docs/sphinx/_static/images/widgets/fullsize/wxmac/radiobutton.png new file mode 100644 index 00000000..bda87e9c Binary files /dev/null and b/docs/sphinx/_static/images/widgets/fullsize/wxmac/radiobutton.png differ diff --git a/docs/sphinx/_static/images/widgets/fullsize/wxmac/searchctrl.png b/docs/sphinx/_static/images/widgets/fullsize/wxmac/searchctrl.png new file mode 100644 index 00000000..8088f713 Binary files /dev/null and b/docs/sphinx/_static/images/widgets/fullsize/wxmac/searchctrl.png differ diff --git a/docs/sphinx/_static/images/widgets/fullsize/wxmac/slider.png b/docs/sphinx/_static/images/widgets/fullsize/wxmac/slider.png new file mode 100644 index 00000000..30985824 Binary files /dev/null and b/docs/sphinx/_static/images/widgets/fullsize/wxmac/slider.png differ diff --git a/docs/sphinx/_static/images/widgets/fullsize/wxmac/spinbutton.png b/docs/sphinx/_static/images/widgets/fullsize/wxmac/spinbutton.png new file mode 100644 index 00000000..f3dd7ab4 Binary files /dev/null and b/docs/sphinx/_static/images/widgets/fullsize/wxmac/spinbutton.png differ diff --git a/docs/sphinx/_static/images/widgets/fullsize/wxmac/spinctrl.png b/docs/sphinx/_static/images/widgets/fullsize/wxmac/spinctrl.png new file mode 100644 index 00000000..94c8660d Binary files /dev/null and b/docs/sphinx/_static/images/widgets/fullsize/wxmac/spinctrl.png differ diff --git a/docs/sphinx/_static/images/widgets/fullsize/wxmac/spinctrldouble.png b/docs/sphinx/_static/images/widgets/fullsize/wxmac/spinctrldouble.png new file mode 100644 index 00000000..3d4d62b5 Binary files /dev/null and b/docs/sphinx/_static/images/widgets/fullsize/wxmac/spinctrldouble.png differ diff --git a/docs/sphinx/_static/images/widgets/fullsize/wxmac/staticbitmap.png b/docs/sphinx/_static/images/widgets/fullsize/wxmac/staticbitmap.png new file mode 100644 index 00000000..4da6fe8c Binary files /dev/null and b/docs/sphinx/_static/images/widgets/fullsize/wxmac/staticbitmap.png differ diff --git a/docs/sphinx/_static/images/widgets/fullsize/wxmac/staticbox.png b/docs/sphinx/_static/images/widgets/fullsize/wxmac/staticbox.png new file mode 100644 index 00000000..be20e095 Binary files /dev/null and b/docs/sphinx/_static/images/widgets/fullsize/wxmac/staticbox.png differ diff --git a/docs/sphinx/_static/images/widgets/fullsize/wxmac/statictext.png b/docs/sphinx/_static/images/widgets/fullsize/wxmac/statictext.png new file mode 100644 index 00000000..26b7b4cd Binary files /dev/null and b/docs/sphinx/_static/images/widgets/fullsize/wxmac/statictext.png differ diff --git a/docs/sphinx/_static/images/widgets/fullsize/wxmac/textctrl.png b/docs/sphinx/_static/images/widgets/fullsize/wxmac/textctrl.png new file mode 100644 index 00000000..40132acb Binary files /dev/null and b/docs/sphinx/_static/images/widgets/fullsize/wxmac/textctrl.png differ diff --git a/docs/sphinx/_static/images/widgets/fullsize/wxmac/togglebutton.png b/docs/sphinx/_static/images/widgets/fullsize/wxmac/togglebutton.png new file mode 100644 index 00000000..a20aa879 Binary files /dev/null and b/docs/sphinx/_static/images/widgets/fullsize/wxmac/togglebutton.png differ diff --git a/docs/sphinx/_static/images/widgets/fullsize/wxmsw/aui.auimdiparentframe.png b/docs/sphinx/_static/images/widgets/fullsize/wxmsw/aui.auimdiparentframe.png new file mode 100644 index 00000000..57b8ff49 Binary files /dev/null and b/docs/sphinx/_static/images/widgets/fullsize/wxmsw/aui.auimdiparentframe.png differ diff --git a/docs/sphinx/_static/images/widgets/fullsize/wxmsw/aui.framemanager.png b/docs/sphinx/_static/images/widgets/fullsize/wxmsw/aui.framemanager.png new file mode 100644 index 00000000..e0f2fa4b Binary files /dev/null and b/docs/sphinx/_static/images/widgets/fullsize/wxmsw/aui.framemanager.png differ diff --git a/docs/sphinx/_static/images/widgets/fullsize/wxmsw/bitmapbutton.png b/docs/sphinx/_static/images/widgets/fullsize/wxmsw/bitmapbutton.png new file mode 100644 index 00000000..c9128420 Binary files /dev/null and b/docs/sphinx/_static/images/widgets/fullsize/wxmsw/bitmapbutton.png differ diff --git a/docs/sphinx/_static/images/widgets/fullsize/wxmsw/button.png b/docs/sphinx/_static/images/widgets/fullsize/wxmsw/button.png new file mode 100644 index 00000000..592e17d7 Binary files /dev/null and b/docs/sphinx/_static/images/widgets/fullsize/wxmsw/button.png differ diff --git a/docs/sphinx/_static/images/widgets/fullsize/wxmsw/checkbox.png b/docs/sphinx/_static/images/widgets/fullsize/wxmsw/checkbox.png new file mode 100644 index 00000000..42b0f5cb Binary files /dev/null and b/docs/sphinx/_static/images/widgets/fullsize/wxmsw/checkbox.png differ diff --git a/docs/sphinx/_static/images/widgets/fullsize/wxmsw/checklistbox.png b/docs/sphinx/_static/images/widgets/fullsize/wxmsw/checklistbox.png new file mode 100644 index 00000000..d2f5714c Binary files /dev/null and b/docs/sphinx/_static/images/widgets/fullsize/wxmsw/checklistbox.png differ diff --git a/docs/sphinx/_static/images/widgets/fullsize/wxmsw/choice.png b/docs/sphinx/_static/images/widgets/fullsize/wxmsw/choice.png new file mode 100644 index 00000000..b9ccdcbf Binary files /dev/null and b/docs/sphinx/_static/images/widgets/fullsize/wxmsw/choice.png differ diff --git a/docs/sphinx/_static/images/widgets/fullsize/wxmsw/collapsiblepane.png b/docs/sphinx/_static/images/widgets/fullsize/wxmsw/collapsiblepane.png new file mode 100644 index 00000000..17f093d6 Binary files /dev/null and b/docs/sphinx/_static/images/widgets/fullsize/wxmsw/collapsiblepane.png differ diff --git a/docs/sphinx/_static/images/widgets/fullsize/wxmsw/combobox.png b/docs/sphinx/_static/images/widgets/fullsize/wxmsw/combobox.png new file mode 100644 index 00000000..98a9f6fc Binary files /dev/null and b/docs/sphinx/_static/images/widgets/fullsize/wxmsw/combobox.png differ diff --git a/docs/sphinx/_static/images/widgets/fullsize/wxmsw/dataview.dataviewctrl.png b/docs/sphinx/_static/images/widgets/fullsize/wxmsw/dataview.dataviewctrl.png new file mode 100644 index 00000000..01828e6d Binary files /dev/null and b/docs/sphinx/_static/images/widgets/fullsize/wxmsw/dataview.dataviewctrl.png differ diff --git a/docs/sphinx/_static/images/widgets/fullsize/wxmsw/dialog.png b/docs/sphinx/_static/images/widgets/fullsize/wxmsw/dialog.png new file mode 100644 index 00000000..f15b7a89 Binary files /dev/null and b/docs/sphinx/_static/images/widgets/fullsize/wxmsw/dialog.png differ diff --git a/docs/sphinx/_static/images/widgets/fullsize/wxmsw/frame.png b/docs/sphinx/_static/images/widgets/fullsize/wxmsw/frame.png new file mode 100644 index 00000000..df41b897 Binary files /dev/null and b/docs/sphinx/_static/images/widgets/fullsize/wxmsw/frame.png differ diff --git a/docs/sphinx/_static/images/widgets/fullsize/wxmsw/gauge.png b/docs/sphinx/_static/images/widgets/fullsize/wxmsw/gauge.png new file mode 100644 index 00000000..0d47c62b Binary files /dev/null and b/docs/sphinx/_static/images/widgets/fullsize/wxmsw/gauge.png differ diff --git a/docs/sphinx/_static/images/widgets/fullsize/wxmsw/listbox.png b/docs/sphinx/_static/images/widgets/fullsize/wxmsw/listbox.png new file mode 100644 index 00000000..a8a6ed7e Binary files /dev/null and b/docs/sphinx/_static/images/widgets/fullsize/wxmsw/listbox.png differ diff --git a/docs/sphinx/_static/images/widgets/fullsize/wxmsw/miniframe.png b/docs/sphinx/_static/images/widgets/fullsize/wxmsw/miniframe.png new file mode 100644 index 00000000..e28bfca1 Binary files /dev/null and b/docs/sphinx/_static/images/widgets/fullsize/wxmsw/miniframe.png differ diff --git a/docs/sphinx/_static/images/widgets/fullsize/wxmsw/notebook.png b/docs/sphinx/_static/images/widgets/fullsize/wxmsw/notebook.png new file mode 100644 index 00000000..16f88dff Binary files /dev/null and b/docs/sphinx/_static/images/widgets/fullsize/wxmsw/notebook.png differ diff --git a/docs/sphinx/_static/images/widgets/fullsize/wxmsw/radiobox.png b/docs/sphinx/_static/images/widgets/fullsize/wxmsw/radiobox.png new file mode 100644 index 00000000..014aacba Binary files /dev/null and b/docs/sphinx/_static/images/widgets/fullsize/wxmsw/radiobox.png differ diff --git a/docs/sphinx/_static/images/widgets/fullsize/wxmsw/radiobutton.png b/docs/sphinx/_static/images/widgets/fullsize/wxmsw/radiobutton.png new file mode 100644 index 00000000..39d7af8e Binary files /dev/null and b/docs/sphinx/_static/images/widgets/fullsize/wxmsw/radiobutton.png differ diff --git a/docs/sphinx/_static/images/widgets/fullsize/wxmsw/searchctrl.png b/docs/sphinx/_static/images/widgets/fullsize/wxmsw/searchctrl.png new file mode 100644 index 00000000..045f35a9 Binary files /dev/null and b/docs/sphinx/_static/images/widgets/fullsize/wxmsw/searchctrl.png differ diff --git a/docs/sphinx/_static/images/widgets/fullsize/wxmsw/slider.png b/docs/sphinx/_static/images/widgets/fullsize/wxmsw/slider.png new file mode 100644 index 00000000..03fd6380 Binary files /dev/null and b/docs/sphinx/_static/images/widgets/fullsize/wxmsw/slider.png differ diff --git a/docs/sphinx/_static/images/widgets/fullsize/wxmsw/spinbutton.png b/docs/sphinx/_static/images/widgets/fullsize/wxmsw/spinbutton.png new file mode 100644 index 00000000..beeef736 Binary files /dev/null and b/docs/sphinx/_static/images/widgets/fullsize/wxmsw/spinbutton.png differ diff --git a/docs/sphinx/_static/images/widgets/fullsize/wxmsw/spinctrl.png b/docs/sphinx/_static/images/widgets/fullsize/wxmsw/spinctrl.png new file mode 100644 index 00000000..abf9f91c Binary files /dev/null and b/docs/sphinx/_static/images/widgets/fullsize/wxmsw/spinctrl.png differ diff --git a/docs/sphinx/_static/images/widgets/fullsize/wxmsw/spinctrldouble.png b/docs/sphinx/_static/images/widgets/fullsize/wxmsw/spinctrldouble.png new file mode 100644 index 00000000..73b167de Binary files /dev/null and b/docs/sphinx/_static/images/widgets/fullsize/wxmsw/spinctrldouble.png differ diff --git a/docs/sphinx/_static/images/widgets/fullsize/wxmsw/staticbitmap.png b/docs/sphinx/_static/images/widgets/fullsize/wxmsw/staticbitmap.png new file mode 100644 index 00000000..2e260f27 Binary files /dev/null and b/docs/sphinx/_static/images/widgets/fullsize/wxmsw/staticbitmap.png differ diff --git a/docs/sphinx/_static/images/widgets/fullsize/wxmsw/staticbox.png b/docs/sphinx/_static/images/widgets/fullsize/wxmsw/staticbox.png new file mode 100644 index 00000000..a075b469 Binary files /dev/null and b/docs/sphinx/_static/images/widgets/fullsize/wxmsw/staticbox.png differ diff --git a/docs/sphinx/_static/images/widgets/fullsize/wxmsw/statictext.png b/docs/sphinx/_static/images/widgets/fullsize/wxmsw/statictext.png new file mode 100644 index 00000000..378f2023 Binary files /dev/null and b/docs/sphinx/_static/images/widgets/fullsize/wxmsw/statictext.png differ diff --git a/docs/sphinx/_static/images/widgets/fullsize/wxmsw/textctrl.png b/docs/sphinx/_static/images/widgets/fullsize/wxmsw/textctrl.png new file mode 100644 index 00000000..35df2017 Binary files /dev/null and b/docs/sphinx/_static/images/widgets/fullsize/wxmsw/textctrl.png differ diff --git a/docs/sphinx/_static/images/widgets/fullsize/wxmsw/togglebutton.png b/docs/sphinx/_static/images/widgets/fullsize/wxmsw/togglebutton.png new file mode 100644 index 00000000..b77c07bc Binary files /dev/null and b/docs/sphinx/_static/images/widgets/fullsize/wxmsw/togglebutton.png differ diff --git a/docs/sphinx/_static/images/widgets/fullsize/wxmsw/wizard.pywizardpage.png b/docs/sphinx/_static/images/widgets/fullsize/wxmsw/wizard.pywizardpage.png new file mode 100644 index 00000000..1d0b2815 Binary files /dev/null and b/docs/sphinx/_static/images/widgets/fullsize/wxmsw/wizard.pywizardpage.png differ diff --git a/docs/sphinx/_static/images/widgets/fullsize/wxmsw/wizard.wizardpagesimple.png b/docs/sphinx/_static/images/widgets/fullsize/wxmsw/wizard.wizardpagesimple.png new file mode 100644 index 00000000..a8f18a65 Binary files /dev/null and b/docs/sphinx/_static/images/widgets/fullsize/wxmsw/wizard.wizardpagesimple.png differ diff --git a/docs/sphinx/_static/javascript/header.js b/docs/sphinx/_static/javascript/header.js new file mode 100644 index 00000000..e01b2c79 --- /dev/null +++ b/docs/sphinx/_static/javascript/header.js @@ -0,0 +1,50 @@ +/* + * header.js + * ~~~~~~~~~ + * + * This script fixes a problem with internal links caused by a fixed header. + * + * Contributed for the TurboGears docs theme by Christoph Zwerschke. + * + * :copyright: Copyright 2010 by by Christoph Zwerschke. + * :license: BSD, see LICENSE for details. + * + */ + +$(function() { + if ($('div.related').css('position') != 'fixed') + return; + var header_height = $('div.related').height(); + if (!header_height) + return; + var current_hash = null; + + function on_hash_change() { + if (current_hash.length < 2 || current_hash.substr(0, 1) != '#') + return; + hash_element = $(document.getElementById && 0 ? + document.getElementById(current_hash.substr(1)) : + current_hash.replace(/[;&,.+*~':"!\^$\[\]()=>|\/@\\]/g,'\\$&')); + if (!hash_element.length) + return; + if (hash_element.offset().top - $(window).scrollTop() < header_height) + window.scrollBy(0, -header_height); + } + + function check_hash_change() { + if (document.location.hash != current_hash) { + current_hash = document.location.hash; + if (current_hash) + window.setTimeout(on_hash_change, 100); + } + } + + check_hash_change(); + if ('onhashchange' in window) + $(window).bind('hashchange', check_hash_change); + else + $(window).scroll(check_hash_change); + + /* remove CSS trick for fixing the header problem */ + $('div.headerfix').removeClass('headerfix'); +}); diff --git a/docs/sphinx/_templates/gallery.html b/docs/sphinx/_templates/gallery.html new file mode 100644 index 00000000..26405dba --- /dev/null +++ b/docs/sphinx/_templates/gallery.html @@ -0,0 +1,196 @@ + + +{% extends "layout.html" %} +{% set title = "Thumbnail gallery" %} + + +{% block body %} + +

Click on any image to go to the relevant documentation

+
+The gallery is generated by randomly choosing a widget image between the 3 main +available ports of wxPython, namely wxMSW, wxGTK and wxMAC every +time the Phoenix documentation is built. + +
+
+
+
+
+ + +
+ +{% endblock %} diff --git a/docs/sphinx/_templates/indexsidebar.html b/docs/sphinx/_templates/indexsidebar.html new file mode 100644 index 00000000..5a476393 --- /dev/null +++ b/docs/sphinx/_templates/indexsidebar.html @@ -0,0 +1,15 @@ +

Download

+

Current version: 2.9.3.74

+

Get the latest wxPython library from the wxPython website +, or view the latest modifications using Viewvc. + +

Questions? Suggestions?

+ +

Send your questions to the wxPython mailing list:

+
+ + +
+

You can also open an issue at the + tracker.

\ No newline at end of file diff --git a/docs/sphinx/_templates/layout.html b/docs/sphinx/_templates/layout.html new file mode 100644 index 00000000..eacf8cd3 --- /dev/null +++ b/docs/sphinx/_templates/layout.html @@ -0,0 +1,22 @@ + +{% extends "!layout.html" %} + +{%- block relbaritems %} +
  • {{ title }}
  • +{% endblock %} + +{% block rootrellink %} + +
  • +
  • Home
  • +
  • Search
  • +
  • Gallery
  • +
  • Documentation »
  • + +{% endblock %} + +{% block header %} +
    +Phoenix Logo +
    +{% endblock %} diff --git a/docs/sphinx/_templates/main.html b/docs/sphinx/_templates/main.html new file mode 100644 index 00000000..073961c5 --- /dev/null +++ b/docs/sphinx/_templates/main.html @@ -0,0 +1,84 @@ +{% extends "layout.html" %} +{% set title = 'Documentation' %} +{% block body %} +

    Welcome to wxPython (Phoenix)'s documentation!

    + +
    +

    SVN Revisions

    +

    “Built with wxWidgets & wxPython SVN revision |SVN|

    +
    + +

    + Welcome! This is the documentation for wxPython {{ release }}, last updated |TODAY|. +

    + +

    + This is the first, very-alpha release of this set of documentation. Documentation TODOs: + +

    +

    +

    +
    + Phoenix is the code name of for the new version of wxPython. Robin Dunn called this the Phoenix project + because in the process of doing this project wxPython's implementation will be utterly destroyed and then reborn + in a new and marvelous way, much like the mythical Phoenix rising from the ashes of its former self. +

    + +

    + For wxPython many things about how the wrapper/bindings code is produced will be changing, and we'll also be + eliminating some other crud along the way. +

    + +

    + Some interesting documents about the current status or the Phoenix project and its development: +

    + + +

    + The Phoenix documentation has been built automatically starting from XML files representing the + wxWidgets C++ documentation (generated using Doxygen). +

    + +

    + I developed a set of Python routines to translate this XML hell into + reStructuredText. Then, Sphinx + has been used to generate the final set of documentation for Phoenix. +

    +
    + +

    Documentation

    + + + +
    + + + + +

    +

    + +
    + + +{% endblock %} \ No newline at end of file diff --git a/docs/sphinx/availability.py b/docs/sphinx/availability.py new file mode 100644 index 00000000..d6d187b6 --- /dev/null +++ b/docs/sphinx/availability.py @@ -0,0 +1,198 @@ +# -*- coding: utf-8 -*- + +""" +Allow "availability" admonitions to be inserted into your documentation. +Inclusion of availabilities can be switched of by a configuration variable. +The availabilitylist directive collects all availabilities of your project +and lists them along with a backlink to the original location. +""" + +from docutils import nodes + +from sphinx.locale import _ +from sphinx.environment import NoUri +from sphinx.util.nodes import set_source_info +from sphinx.util.compat import Directive, make_admonition + +# ----------------------------------------------------------------------- # +class availability_node(nodes.Admonition, nodes.Element): pass + +# ----------------------------------------------------------------------- # +class availabilitylist(nodes.General, nodes.Element): pass + +# ----------------------------------------------------------------------- # + + +class Availability(Directive): + """ + An "availability" entry, displayed (if configured) in the form of an admonition. + """ + + has_content = True + required_arguments = 0 + optional_arguments = 0 + final_argument_whitespace = False + option_spec = {} + + + # ----------------------------------------------------------------------- # + + def run(self): + env = self.state.document.settings.env + targetid = 'index-%s' % env.new_serialno('index') + targetnode = nodes.target('', '', ids=[targetid]) + + ad = make_admonition(availability_node, self.name, [_('Availability')], self.options, + self.content, self.lineno, self.content_offset, + self.block_text, self.state, self.state_machine) + set_source_info(self, ad[0]) + return [targetnode] + ad + + + +# ----------------------------------------------------------------------- # + +def process_availabilities(app, doctree): + # collect all availabilities in the environment + # this is not done in the directive itself because it some transformations + # must have already been run, e.g. substitutions + env = app.builder.env + if not hasattr(env, 'availability_all_availabilities'): + env.availability_all_availabilities = [] + for node in doctree.traverse(availability_node): + try: + targetnode = node.parent[node.parent.index(node) - 1] + if not isinstance(targetnode, nodes.target): + raise IndexError + except IndexError: + targetnode = None + env.availability_all_availabilities.append({ + 'docname': env.docname, + 'source': node.source or env.doc2path(env.docname), + 'lineno': node.line, + 'availability': node.deepcopy(), + 'target': targetnode, + }) + + +# ----------------------------------------------------------------------- # + +class AvailabilityList(Directive): + """ + A list of all availability entries. + """ + + has_content = False + required_arguments = 0 + optional_arguments = 0 + final_argument_whitespace = False + option_spec = {} + + + # ----------------------------------------------------------------------- # + + def run(self): + # Simply insert an empty availabilitylist node which will be replaced later + # when process_availability_nodes is called + return [availabilitylist('')] + + +# ----------------------------------------------------------------------- # + +def process_availability_nodes(app, doctree, fromdocname): + if not app.config['availability_include_availabilities']: + for node in doctree.traverse(availability_node): + node.parent.remove(node) + + # Replace all availabilitylist nodes with a list of the collected availabilities. + # Augment each availability with a backlink to the original location. + env = app.builder.env + + if not hasattr(env, 'availability_all_availabilities'): + env.availability_all_availabilities = [] + + for node in doctree.traverse(availabilitylist): + if not app.config['availability_include_availabilities']: + node.replace_self([]) + continue + + content = [] + + for availability_info in env.availability_all_availabilities: + para = nodes.paragraph(classes=['availability-source']) + description = _('(The <> is located in ' + ' %s, line %d.)') % \ + (availability_info['source'], availability_info['lineno']) + desc1 = description[:description.find('<<')] + desc2 = description[description.find('>>')+2:] + para += nodes.Text(desc1, desc1) + + # Create a reference + newnode = nodes.reference('', '', internal=True) + innernode = nodes.emphasis(_('original entry'), _('original entry')) + try: + newnode['refuri'] = app.builder.get_relative_uri( + fromdocname, availability_info['docname']) + newnode['refuri'] += '#' + availability_info['target']['refid'] + except NoUri: + # ignore if no URI can be determined, e.g. for LaTeX output + pass + newnode.append(innernode) + para += newnode + para += nodes.Text(desc2, desc2) + + # (Recursively) resolve references in the availability content + availability_entry = availability_info['availability'] + env.resolve_references(availability_entry, availability_info['docname'], + app.builder) + + # Insert into the availabilitylist + content.append(availability_entry) + content.append(para) + + node.replace_self(content) + + +# ----------------------------------------------------------------------- # + +def purge_availabilities(app, env, docname): + if not hasattr(env, 'availability_all_availabilities'): + return + env.availability_all_availabilities = [availability for availability in env.availability_all_availabilities + if availability['docname'] != docname] + + +# ----------------------------------------------------------------------- # + +def visit_availability_node(self, node): + self.visit_admonition(node) + + +# ----------------------------------------------------------------------- # + +def depart_availability_node(self, node): + self.depart_admonition(node) + + +# ----------------------------------------------------------------------- # + +def setup(app): + app.add_javascript('javascript/header.js') + app.add_config_value('availability_include_availabilities', False, False) + + app.add_node(availabilitylist) + app.add_node(availability_node, + html=(visit_availability_node, depart_availability_node), + latex=(visit_availability_node, depart_availability_node), + text=(visit_availability_node, depart_availability_node), + man=(visit_availability_node, depart_availability_node), + texinfo=(visit_availability_node, depart_availability_node)) + + app.add_directive('availability', Availability) + app.add_directive('availabilitylist', AvailabilityList) + app.connect('doctree-read', process_availabilities) + app.connect('doctree-resolved', process_availability_nodes) + app.connect('env-purge-doc', purge_availabilities) + + +# ----------------------------------------------------------------------- # diff --git a/docs/sphinx/conf.py b/docs/sphinx/conf.py new file mode 100644 index 00000000..9a627039 --- /dev/null +++ b/docs/sphinx/conf.py @@ -0,0 +1,278 @@ +# -*- coding: utf-8 -*- +# +# Phoenix documentation build configuration file, created by +# sphinx-quickstart on Mon Jun 22 09:32:57 2009. +# +# This file is execfile()d with the current directory set to its containing dir. +# +# Note that not all possible configuration values are present in this +# autogenerated file. +# +# All configuration values have a default; values that are commented out +# serve to show the default. + +import sys, os + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +sys.path.append(os.path.abspath('.')) +sys.path.append('..') + +# -- General configuration ----------------------------------------------------- + +# Add any Sphinx extension module names here, as strings. They can be extensions +# coming with Sphinx (named 'sphinx.ext.*') or your custom ones. +extensions = ['sphinx.ext.todo', 'sphinx.ext.autodoc', + 'sphinx.ext.autosummary', 'sphinx.ext.coverage', + 'availability'] + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] + +# The suffix of source filenames. +source_suffix = '.txt' + +todo_include_todos = True +todo_all_todos = True + +availability_include_availabilities = True +availability_all_availabilities = True + +# The encoding of source files. +#source_encoding = 'utf-8-sig' + +# The master toctree document. +master_doc = 'index' + +# General information about the project. +project = u'wxPython (Phoenix)' +copyright = u'2011, Andrea Gavana' + +# The version info for the project you're documenting, acts as replacement for +# |version| and |release|, also used in various other places throughout the +# built documents. +# +# The short X.Y version. +version = '2.9' +# The full version, including alpha/beta/rc tags. +release = '2.9.3.74 (Phoenix)' + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +#language = None + +# There are two options for replacing |today|: either, you set today to some +# non-false value, then it is used: +#today = '' +# Else, today_fmt is used as the format for a strftime call. +today_fmt = '%d %B %Y' + +# List of documents that shouldn't be included in the build. +#unused_docs = [] + +# List of directories, relative to source directory, that shouldn't be searched +# for source files. +exclude_trees = ['_build'] + +# The reST default role (used for this markup: `text`) to use for all documents. +default_role = 'autolink' + +# If true, '()' will be appended to :func: etc. cross-reference text. +add_function_parentheses = False + +# If true, the current module name will be prepended to all description +# unit titles (such as .. function::). +add_module_names = False + +# If true, sectionauthor and moduleauthor directives will be shown in the +# output. They are ignored by default. +show_authors = True + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = 'sphinx' + +# A list of ignored prefixes for module index sorting. +#modindex_common_prefix = [] + + +# -- Options for HTML output --------------------------------------------------- + +# The theme to use for HTML and HTML Help pages. Major themes that come with +# Sphinx are currently 'default' and 'sphinxdoc'. +html_theme = 'default' + +# Theme options are theme-specific and customize the look and feel of a theme +# further. For a list of options available for each theme, see the +# documentation. +html_theme_options = {'stickysidebar': 'true'} + +# Add any paths that contain custom themes here, relative to this directory. +#html_theme_path = [] + +# The name for this set of Sphinx documents. If None, it defaults to +# " v documentation". +#html_title = None + +# A shorter title for the navigation bar. Default is the same as html_title. +html_short_title = 'Phoenix Docs' + +# The name of an image file (relative to this directory) to place at the top +# of the sidebar. +html_logo = '_static/images/sphinxdocs/phoenix_main.png' + +# The name of an image file (within the static path) to use as favicon of the +# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 +# pixels large. +html_favicon = '_static/images/sphinxdocs/phoenix_small.ico' + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ['_static'] + +html_style = 'css/phoenix.css' + +# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, +# using the given strftime format. +#html_last_updated_fmt = '%b %d, %Y' + +# If true, SmartyPants will be used to convert quotes and dashes to +# typographically correct entities. +#html_use_smartypants = True + +# Custom sidebar templates, maps document names to template names. +html_sidebars = {'index': 'indexsidebar.html'} + +# Additional templates that should be rendered to pages, maps page names to +# template names. +html_additional_pages = {'gallery': 'gallery.html', 'main': 'main.html'} + +# If false, no module index is generated. +html_use_modindex = True + +# If false, no index is generated. +html_use_index = True + +# If true, the index is split into individual pages for each letter. +html_split_index = True + +# If true, links to the reST sources are added to the pages. +html_show_sourcelink = False + +# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. +#html_show_sphinx = True + +# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. +#html_show_copyright = True + +# If true, an OpenSearch description file will be output, and all pages will +# contain a tag referring to it. The value of this option must be the +# base URL from which the finished HTML is served. +#html_use_opensearch = '' + +# If nonempty, this is the file name suffix for HTML files (e.g. ".xhtml"). +#html_file_suffix = '' + +# Output file base name for HTML help builder. +htmlhelp_basename = 'PhoenixDocs' + +# -- Options for LaTeX output -------------------------------------------------- + +# The paper size ('letter' or 'a4'). +#latex_paper_size = 'letter' + +# The font size ('10pt', '11pt' or '12pt'). +#latex_font_size = '10pt' + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, author, documentclass [howto/manual]). +latex_documents = [ + ('index', 'PhoenixDocs.tex', u'wxPython (Phoenix) Documentation', + u'Andrea Gavana', 'manual'), +] + +# The name of an image file (relative to this directory) to place at the top of +# the title page. +#latex_logo = None + +# For "manual" documents, if this is true, then toplevel headings are parts, +# not chapters. +#latex_use_parts = False + +# Additional stuff for the LaTeX preamble. +#latex_preamble = '' + +# Documents to append as an appendix to all manuals. +#latex_appendices = [] + +# If false, no module index is generated. +#latex_use_modindex = True + +# -- Options for PDF output -------------------------------------------------- +# Grouping the document tree into PDF files. List of tuples +# (source start file, target name, title, author, options). +# +# If there is more than one author, separate them with \\. +# For example: r'Guido van Rossum\\Fred L. Drake, Jr., editor' +# +# The options element is a dictionary that lets you override +# this config per-document. +# For example, +# ('index', u'MyProject', u'My Project', u'Author Name', +# dict(pdf_compressed = True)) +# would mean that specific document would be compressed +# regardless of the global pdf_compressed setting. +pdf_documents = [('index', u'PhoenixDocs', u'wxPython (Phoenix) Documentation', u'Andrea Gavana'),] + +# A comma-separated list of custom stylesheets. Example: +# pdf_stylesheets = ['sphinx', 'kerning', 'a4', "C:\\AGW\\agw\\fonts\\sphinx.json"] +# Create a compressed PDF +# Use True/False or 1/0 +# Example: compressed=True +#pdf_compressed = False +# A colon-separated list of folders to search for fonts. Example: +#pdf_font_path = ['E:\\AGW\\agw\\fonts', 'C:\\Windows\\Fonts'] +# Language to be used for hyphenation support +#pdf_language = "en_US" +# Mode for literal blocks wider than the frame. Can be +# overflow, shrink or truncate +#pdf_fit_mode = "shrink" +# Section level that forces a break page. +# For example: 1 means top-level sections start in a new page +# 0 means disabled +#pdf_break_level = 0 +# When a section starts in a new page, force it to be 'even', 'odd', +# or just use 'any' +#pdf_breakside = 'any' +# Insert footnotes where they are defined instead of +# at the end. +#pdf_inline_footnotes = True +# verbosity level. 0 1 or 2 +pdf_verbosity = 2 +# If false, no index is generated. +#pdf_use_index = True +# If false, no modindex is generated. +#pdf_use_modindex = True +# If false, no coverpage is generated. +#pdf_use_coverpage = True +# Documents to append as an appendix to all manuals. +#pdf_appendices = [] +# Enable experimental feature to split table cells. Use it +# if you get "DelayedTable too big" errors +pdf_splittables = True + +##def process_docstring(app, what, name, obj, options, lines): +## +## if what == "data": +## +## fid = open("autodata_docstrings.pkl", "rb") +## autodata_dict = cPickle.load(fid) +## fid.close() +## +## if name in autodata_dict: +## lines[:] = [autodata_dict[name].strip()] +## +## +##def setup(app): +## app.connect('autodoc-process-docstring', process_docstring) diff --git a/docs/sphinx/make.bat b/docs/sphinx/make.bat new file mode 100644 index 00000000..98ae5c5f --- /dev/null +++ b/docs/sphinx/make.bat @@ -0,0 +1,176 @@ +@ECHO OFF + +REM Command file for Sphinx documentation + +if "%SPHINXBUILD%" == "" ( + set SPHINXBUILD=sphinx-build +) +set BUILDDIR=build +set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% . +if NOT "%PAPER%" == "" ( + set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% +) + +if "%1" == "" goto help + +if "%1" == "help" ( + :help + echo.Please use `make ^` where ^ is one of + echo. html to make standalone HTML files + echo. dirhtml to make HTML files named index.html in directories + echo. singlehtml to make a single large HTML file + echo. pickle to make pickle files + echo. json to make JSON files + echo. htmlhelp to make HTML files and a HTML help project + echo. qthelp to make HTML files and a qthelp project + echo. devhelp to make HTML files and a Devhelp project + echo. epub to make an epub + echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter + echo. text to make text files + echo. man to make manual pages + echo. changes to make an overview over all changed/added/deprecated items + echo. linkcheck to check all external links for integrity + echo. doctest to run all doctests embedded in the documentation if enabled + goto end +) + +if "%1" == "clean" ( + for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i + del /q /s %BUILDDIR%\* + goto end +) + +if "%1" == "html" ( + %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The HTML pages are in %BUILDDIR%/html. + goto end +) + +if "%1" == "dirhtml" ( + %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml. + goto end +) + +if "%1" == "singlehtml" ( + %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml. + goto end +) + +if "%1" == "pickle" ( + %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; now you can process the pickle files. + goto end +) + +if "%1" == "json" ( + %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; now you can process the JSON files. + goto end +) + +if "%1" == "htmlhelp" ( + %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; now you can run HTML Help Workshop with the ^ +.hhp project file in %BUILDDIR%/htmlhelp. + goto end +) + +if "%1" == "qthelp" ( + %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; now you can run "qcollectiongenerator" with the ^ +.qhcp project file in %BUILDDIR%/qthelp, like this: + echo.^> qcollectiongenerator %BUILDDIR%\qthelp\wxPythonPhoenix.qhcp + echo.To view the help file: + echo.^> assistant -collectionFile %BUILDDIR%\qthelp\wxPythonPhoenix.ghc + goto end +) + +if "%1" == "devhelp" ( + %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. + goto end +) + +if "%1" == "epub" ( + %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The epub file is in %BUILDDIR%/epub. + goto end +) + +if "%1" == "latex" ( + %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; the LaTeX files are in %BUILDDIR%/latex. + goto end +) + +if "%1" == "text" ( + %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The text files are in %BUILDDIR%/text. + goto end +) + +if "%1" == "man" ( + %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The manual pages are in %BUILDDIR%/man. + goto end +) + +if "%1" == "changes" ( + %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes + if errorlevel 1 exit /b 1 + echo. + echo.The overview file is in %BUILDDIR%/changes. + goto end +) + +if "%1" == "linkcheck" ( + %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck + if errorlevel 1 exit /b 1 + echo. + echo.Link check complete; look for any errors in the above output ^ +or in %BUILDDIR%/linkcheck/output.txt. + goto end +) + +if "%1" == "doctest" ( + %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest + if errorlevel 1 exit /b 1 + echo. + echo.Testing of doctests in the sources finished, look at the ^ +results in %BUILDDIR%/doctest/output.txt. + goto end +) + +if "%1" == "pdf" ( + %SPHINXBUILD% -b pdf %ALLSPHINXOPTS% %BUILDDIR%/pdf + echo. + echo.Build finished. The PDF files are in %BUILDDIR%/pdf + goto end + ) +:end diff --git a/docs/sphinx/rest_substitutions/overviews/app_overview.rst b/docs/sphinx/rest_substitutions/overviews/app_overview.rst new file mode 100644 index 00000000..5555a4ae --- /dev/null +++ b/docs/sphinx/rest_substitutions/overviews/app_overview.rst @@ -0,0 +1,58 @@ +.. include:: headings.inc + + +.. _app overview: + +================================= +|phoenix_title| **App Overview** +================================= + + +Introduction +------------ + +A wxPython application does not have a main procedure; the equivalent is the :meth:`AppConsole.OnInit` member defined for a class derived from :ref:`App`. + +`OnInit` will usually create a top window as a bare minimum. Unlike in earlier versions of wxPython, `OnInit` does not return a frame. +Instead it returns a boolean value which indicates whether processing should continue (``True``) or not (``False``). + +An application closes by destroying all windows. Because all frames must be destroyed for the application to exit, it is advisable to use +parent frames wherever possible when creating new frames, so that deleting the top level frame will automatically delete child frames. +The alternative is to explicitly delete child frames in the top-level frame's :ref:`CloseEvent` handler. + +In emergencies the :func:`Exit` function can be called to kill the application however normally the application shuts down automatically, +see :ref:`Application Shutdown `. + +An example of defining an application follows:: + + + class DerivedApp(wx.App): + + def OnInit(self): + + the_frame = wx.Frame(None, -1) + + # Other initialization code... + + the_frame.Show(True) + + return True + + + +.. _application shutdown: + +Application Shutdown +-------------------- + +The application normally shuts down when the last of its top level windows is closed. This is normally the expected behaviour and means +that it is enough to call :meth:`Window.Close` () in response to the "Exit" menu command if your program has a single top level window. +If this behaviour is not desirable :meth:`PyApp.SetExitOnFrameDelete` can be called to change it. + +.. note:: Note that such logic doesn't apply for the windows shown before the program enters the main loop: in other words, you can + safely show a dialog from :meth:`AppConsole.OnInit` and not be afraid that your application terminates when this dialog -- which is the last + top level window for the moment -- is closed. + + +Another aspect of the application shutdown is :meth:`AppConsole.OnExit` which is called when the application exits but before wxPython cleans up +its internal structures. diff --git a/docs/sphinx/rest_substitutions/overviews/bitmap_overview.rst b/docs/sphinx/rest_substitutions/overviews/bitmap_overview.rst new file mode 100644 index 00000000..6c27991b --- /dev/null +++ b/docs/sphinx/rest_substitutions/overviews/bitmap_overview.rst @@ -0,0 +1,103 @@ +.. include:: headings.inc + + +.. _bitmaps and icons: + +=============================================== +|phoenix_title| **Bitmaps and Icons** +=============================================== + + +The :ref:`Bitmap` class encapsulates the concept of a platform-dependent bitmap, either monochrome or colour. +Platform-specific methods for creating a :ref:`Bitmap` object from an existing file are catered for. + +A bitmap created dynamically or loaded from a file can be selected into a memory device context (instance of +:ref:`MemoryDC`). This enables the bitmap to be copied to a window or memory device context using :meth:`DC.Blit` (), +or to be used as a drawing surface. + +.. seealso:: :ref:`MemoryDC` for an example of drawing onto a bitmap. + + +All wxPython platforms support XPMs for small bitmaps and icons. + + + +.. _supported bitmap file formats: + +Supported Bitmap File Formats +----------------------------- + +The following lists the formats handled on different platforms. Note that missing or partially-implemented +formats are automatically supplemented by using :ref:`Image` to load the data, and then converting it to :ref:`Bitmap` +form. Note that using :ref:`Image` is the preferred way to load images in wxPython, with the exception of resources +(XPM-files or native Windows resources). + + +Bitmap +^^^^^^ + +Under Windows, :ref:`Bitmap` may load the following formats: + +- Windows bitmap resource (``BITMAP_TYPE_BMP_RESOURCE``) +- Windows bitmap file (``BITMAP_TYPE_BMP``) +- XPM data and file (``BITMAP_TYPE_XPM``) +- All formats that are supported by the :ref:`Image` class. + + +Under wxGTK, :ref:`Bitmap` may load the following formats: + +- XPM data and file (``BITMAP_TYPE_XPM``) +- All formats that are supported by the :ref:`Image` class. + + +Under wxMotif and wxX11, :ref:`Bitmap` may load the following formats: + +- XBM data and file (``BITMAP_TYPE_XBM``) +- XPM data and file (``BITMAP_TYPE_XPM``) +- All formats that are supported by the :ref:`Image` class. + + +Icon +^^^^ + +Under Windows, :ref:`Icon` may load the following formats: + +- Windows icon resource (``BITMAP_TYPE_ICO_RESOURCE``) +- Windows icon file (``BITMAP_TYPE_ICO``) +- XPM data and file (``BITMAP_TYPE_XPM``) + + +Under wxGTK, :ref:`Icon` may load the following formats: + +- XPM data and file (``BITMAP_TYPE_XPM``) +- All formats that are supported by the :ref:`Image` class. + + +Under wxMotif and wxX11, :ref:`Icon` may load the following formats: + +- XBM data and file (``BITMAP_TYPE_XBM``) +- XPM data and file (``BITMAP_TYPE_XPM``) +- All formats that are supported by the :ref:`Image` class. + + +Cursor +^^^^^^ + +Under Windows, :ref:`Cursor` may load the following formats: + +- Windows cursor resource (``BITMAP_TYPE_CUR_RESOURCE``) +- Windows cursor file (``BITMAP_TYPE_CUR``) +- Windows icon file (``BITMAP_TYPE_ICO``) +- Windows bitmap file (``BITMAP_TYPE_BMP``) + + +Under wxGTK, :ref:`Cursor` may load the following formats (in addition to stock cursors): + +- None (stock cursors only). + + +Under wxMotif and wxX11, :ref:`Cursor` may load the following formats: + +- XBM data and file (``BITMAP_TYPE_XBM``) + + diff --git a/docs/sphinx/rest_substitutions/overviews/bookctrl_overview.rst b/docs/sphinx/rest_substitutions/overviews/bookctrl_overview.rst new file mode 100644 index 00000000..b8de5b28 --- /dev/null +++ b/docs/sphinx/rest_substitutions/overviews/bookctrl_overview.rst @@ -0,0 +1,48 @@ +.. include:: headings.inc + + +.. _bookctrl overview: + +=============================================== +|phoenix_title| **BookCtrl Overview** +=============================================== + + +Introduction +------------ + +A book control is a convenient way of displaying multiple pages of information, displayed one page at a time. +wxPython has five variants of this control: + +- :ref:`Choicebook`: controlled by a :ref:`Choice` +- :ref:`Listbook`: controlled by a :ref:`ListCtrl` +- :ref:`Notebook`: uses a row of tabs +- :ref:`Treebook`: controlled by a :ref:`TreeCtrl` +- :ref:`Toolbook`: controlled by a :ref:`ToolBar` + + + +Best Book +--------- + +:ref:`BookCtrl` is mapped to the class best suited for a given platform. Currently it provides :ref:`Choicebook` +for smartphones equipped with WinCE, and :ref:`Notebook` for all other platforms. The mapping consists of: + +=============================================== ================================================== +`BookCtrl` `Choicebook` or `Notebook` +=============================================== ================================================== +``wxEVT_COMMAND_BOOKCTRL_PAGE_CHANGED`` ``wxEVT_COMMAND_CHOICEBOOK_PAGE_CHANGED`` or ``wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED`` +``wxEVT_COMMAND_BOOKCTRL_PAGE_CHANGING`` ``wxEVT_COMMAND_CHOICEBOOK_PAGE_CHANGING`` or ``wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGING`` +EVT_BOOKCTRL_PAGE_CHANGED EVT_CHOICEBOOK_PAGE_CHANGED or EVT_NOTEBOOK_PAGE_CHANGED +EVT_BOOKCTRL_PAGE_CHANGING EVT_CHOICEBOOK_PAGE_CHANGING or EVT_NOTEBOOK_PAGE_CHANGING +=============================================== ================================================== + + +For orientation of the book controller, use following flags in style: + +- ``BK_TOP``: controller above pages +- ``BK_BOTTOM``: controller below pages +- ``BK_LEFT``: controller on the left +- ``BK_RIGHT``: controller on the right +- ``BK_DEFAULT``: native controller placement + diff --git a/docs/sphinx/rest_substitutions/overviews/common_dialogs_overview.rst b/docs/sphinx/rest_substitutions/overviews/common_dialogs_overview.rst new file mode 100644 index 00000000..09a33c72 --- /dev/null +++ b/docs/sphinx/rest_substitutions/overviews/common_dialogs_overview.rst @@ -0,0 +1,226 @@ +.. include:: headings.inc + + +.. _common dialogs: + +=============================================== +|phoenix_title| **Common Dialogs** +=============================================== + + +Common dialog classes and functions encapsulate commonly-needed dialog box requirements. They are all 'modal', +grabbing the flow of control until the user dismisses the dialog, to make them easy to use within an application. + +Some dialogs have both platform-dependent and platform-independent implementations, so that if underlying windowing +systems do not provide the required functionality, the generic classes and functions can stand in. For example, +under MS Windows, :ref:`ColourDialog` uses the standard colour selector. There is also an equivalent called +`GenericColourDialog` for other platforms, and a macro defines :ref:`ColourDialog` to be the same as +`GenericColourDialog` on non-MS Windows platforms. However, under MS Windows, the generic dialog can also be used, +for testing or other purposes. + + + +.. _colourdialog overview: + +ColourDialog Overview +--------------------- + +The :ref:`ColourDialog` presents a colour selector to the user, and returns with colour information. + + +The MS Windows Colour Selector +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Under Windows, the native colour selector common dialog is used. This presents a dialog box with three main regions: +at the top left, a palette of 48 commonly-used colours is shown. Under this, there is a palette of 16 'custom colours' +which can be set by the application if desired. Additionally, the user may open up the dialog box to show a right-hand +panel containing controls to select a precise colour, and add it to the custom colour palette. + + +The Generic Colour Selector +^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Under non-MS Windows platforms, the colour selector is a simulation of most of the features of the MS Windows selector. +Two palettes of 48 standard and 16 custom colours are presented, with the right-hand area containing three sliders for +the user to select a colour from red, green and blue components. This colour may be added to the custom colour palette, +and will replace either the currently selected custom colour, or the first one in the palette if none is selected. +The RGB colour sliders are not optional in the generic colour selector. The generic colour selector is also available +under MS Windows; use the name `GenericColourDialog`. + + +Example +^^^^^^^ + +Here is an example of using :ref:`ColourDialog`, which sets various parameters of a :ref:`ColourData` object, including +a grey scale for the custom colours. If the user did not cancel the dialog, the application retrieves the selected colour +and uses it to set the background of a window:: + + data = wx.ColourData() + data.SetChooseFull(True) + + for i in xrange(16): + colour = wx.Colour(i*16, i*16, i*16) + data.SetCustomColour(i, colour) + + + dialog = wx.ColourDialog(self, data) + + if dialog.ShowModal() == wx.ID_OK: + + retData = dialog.GetColourData() + col = retData.GetColour() + brush = wx.Brush(col, wx.SOLID) + myWindow.SetBackground(brush) + myWindow.Clear() + myWindow.Refresh() + + + + +.. _fontdialog overview: + +FontDialog Overview +------------------- + + +The :ref:`FontDialog` presents a font selector to the user, and returns with font and colour information. + + +The MS Windows Font Selector +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Under Windows, the native font selector common dialog is used. This presents a dialog box with controls for font name, +point size, style, weight, underlining, strikeout and text foreground colour. A sample of the font is shown on a white +area of the dialog box. Note that in the translation from full MS Windows fonts to wxPython font conventions, strikeout +is ignored and a font family (such as Swiss or Modern) is deduced from the actual font name (such as Arial or Courier). + + +The Generic Font Selector +^^^^^^^^^^^^^^^^^^^^^^^^^ + +Under non-MS Windows platforms, the font selector is simpler. Controls for font family, point size, style, weight, +underlining and text foreground colour are provided, and a sample is shown upon a white background. The generic font +selector is also available under MS Windows; use the name `GenericFontDialog`. + + +Example +^^^^^^^ + +Here is an example of using :ref:`FontDialog`. The application uses the returned font and colour for drawing text on a canvas:: + + data = wx.FontData() + data.SetInitialFont(canvasFont) + data.SetColour(canvasTextColour) + + dialog = wx.FontDialog(self, data) + + if dialog.ShowModal() == wx.ID_OK: + + retData = dialog.GetFontData() + canvasFont = retData.GetChosenFont() + canvasTextColour = retData.GetColour() + myWindow.Refresh() + + + + +.. _printdialog overview: + +PrintDialog Overview +-------------------- + + +This class represents the print and print setup common dialogs. You may obtain a :ref:`PrinterDC` device context from a +successfully dismissed print dialog. + +.. seealso:: :ref:`Printing Framework Overview ` for an example. + + + +.. _filedialog overview: + +FileDialog Overview +------------------- + + +Pops up a file selector box. On Windows and GTK 2.4+, this is the common file selector dialog. In X, this is a file +selector box with somewhat less functionality. The path and filename are distinct elements of a full file pathname. + +If path is "", the current directory will be used. If filename is "", no default filename will be supplied. +The wildcard determines what files are displayed in the file selector, and file extension supplies a type extension +for the required filename. Flags may be a combination of ``FD_OPEN``, ``FD_SAVE``, ``FD_OVERWRITE_PROMPT``, +``FD_HIDE_READONLY``, ``FD_FILE_MUST_EXIST``, ``FD_MULTIPLE``, ``FD_CHANGE_DIR`` or 0. + +Both the X and Windows versions implement a wildcard filter. Typing a filename containing wildcards ``(*, ?)`` in the +filename text item, and clicking on Ok, will result in only those files matching the pattern being displayed. In the +X version, supplying no default name will result in the wildcard filter being inserted in the filename text item; +the filter is ignored if a default name is supplied. + +The wildcard may be a specification for multiple types of file with a description for each, such as:: + + wildcard = "BMP files (*.bmp)|*.bmp|GIF files (*.gif)|*.gif" + + + +.. _dirdialog overview: + +DirDialog Overview +------------------- + + +This dialog shows a directory selector dialog, allowing the user to select a single directory. + + + +.. _textentrydialog overview: + +TextEntryDialog Overview +------------------------ + + +This is a dialog with a text entry field. The value that the user entered is obtained using :meth:`TextEntryDialog.GetValue` (). + + + +.. _passwordentrydialog overview: + +PasswordEntryDialog Overview +---------------------------- + + +This is a dialog with a password entry field. The value that the user entered is obtained using :meth:`TextEntryDialog.GetValue` (). + + + +.. _messagedialog overview: + +MessageDialog Overview +---------------------- + + +This dialog shows a message, plus buttons that can be chosen from ``OK``, ``Cancel``, ``Yes``, and ``No``. Under Windows, an +optional icon can be shown, such as an exclamation mark or question mark. + +The return value of :meth:`MessageDialog.ShowModal` () indicates which button the user pressed. + + + +.. _singlechoicedialog overview: + +SingleChoiceDialog Overview +--------------------------- + + +This dialog shows a list of choices, plus ``OK`` and (optionally) ``Cancel``. The user can select one of them. The selection +can be obtained from the dialog as an index, a string or client data. + + + +.. _multichoicedialog overview: + +MultiChoiceDialog Overview +--------------------------- + + +This dialog shows a list of choices, plus ``OK`` and (optionally) ``Cancel``. The user can select one or more of them. + diff --git a/docs/sphinx/rest_substitutions/overviews/config_overview.rst b/docs/sphinx/rest_substitutions/overviews/config_overview.rst new file mode 100644 index 00000000..8eaf07a9 --- /dev/null +++ b/docs/sphinx/rest_substitutions/overviews/config_overview.rst @@ -0,0 +1,44 @@ +.. include:: headings.inc + + +.. _config overview: + +================================================= +|phoenix_title| **Config Overview** +================================================= + + +This overview briefly describes what the config classes are and what they are for. All the details about +how to use them may be found in the description of the :ref:`ConfigBase` class and the documentation of +the file, registry and INI file based implementations mentions all the features/limitations specific to +each one of these versions. + +The config classes provide a way to store some application configuration information. They were especially +designed for this usage and, although may probably be used for many other things as well, should be limited +to it. It means that this information should be: + +- Typed, i.e. strings or numbers for the moment. You cannot store binary data, for example. +- Small. For instance, it is not recommended to use the Windows registry for amounts of data more than a couple of kilobytes. +- Not performance critical, neither from speed nor from a memory consumption point of view. + + +On the other hand, the features provided make them very useful for storing all kinds of small to medium volumes +of hierarchically-organized, heterogeneous data. In short, this is a place where you can conveniently stuff +all your data (numbers and strings) organizing it in a tree where you use the filesystem-like paths to +specify the location of a piece of data. In particular, these classes were designed to be as easy to use as possible. + +From another point of view, they provide an interface which hides the differences between the Windows registry +and the standard Unix text format configuration files. Other (future) implementations of :ref:`ConfigBase` might +also understand GTK resource files or their analogues on the KDE side. + +In any case, each implementation of :ref:`ConfigBase` does its best to make the data look the same way everywhere. +Due to limitations of the underlying physical storage, it may not implement 100% of the base class functionality. + +There are groups of entries and the entries themselves. Each entry contains either a string or a number (or a +boolean value; support for other types of data such as dates or timestamps is planned) and is identified by +the full path to it: something like ``/MyApp/UserPreferences/Colors/Foreground``. + +The previous elements in the path are the group names, and each name may contain an arbitrary number of entries and subgroups. + +The path components are always separated with a slash, even though some implementations use the backslash internally. +Further details (including how to read/write these entries) may be found in the documentation for :ref:`ConfigBase`. diff --git a/docs/sphinx/rest_substitutions/overviews/dc_overview.rst b/docs/sphinx/rest_substitutions/overviews/dc_overview.rst new file mode 100644 index 00000000..5f45f494 --- /dev/null +++ b/docs/sphinx/rest_substitutions/overviews/dc_overview.rst @@ -0,0 +1,38 @@ +.. include:: headings.inc + + +.. _device contexts: + +=============================================== +|phoenix_title| **Device Contexts** +=============================================== + + +A :ref:`DC` is a device context onto which graphics and text can be drawn. The device context is intended to represent +a number of output devices in a generic way, with the same API being used throughout. + +Some device contexts are created temporarily in order to draw on a window. This is true of :ref:`ScreenDC`, :ref:`ClientDC`, +:ref:`PaintDC`, and :ref:`WindowDC`. The following describes the differences between these device contexts and when you should use them. + +- :ref:`ScreenDC`. Use this to paint on the screen, as opposed to an individual window. +- :ref:`ClientDC`. Use this to paint on the client area of window (the part without borders and other decorations), but do not use + it from within an :ref:`PaintEvent`. +- :ref:`PaintDC`. Use this to paint on the client area of a window, but only from within a :ref:`PaintEvent`. +- :ref:`WindowDC`. Use this to paint on the whole area of a window, including decorations. This may not be available on non-Windows platforms. + + +To use a client, paint or window device context, create an object on the stack with the window as argument, for example:: + + def OnMyCmd(self, event): + + dc = wx.ClientDC(window) + DrawMyPicture(dc) + + + +Try to write code so it is parameterised by :ref:`DC` - if you do this, the same piece of code may write to a number of different devices, +by passing a different device context. This doesn't work for everything (for example not all device contexts support bitmap drawing) +but will work most of the time. + + + diff --git a/docs/sphinx/rest_substitutions/overviews/dialog_overview.rst b/docs/sphinx/rest_substitutions/overviews/dialog_overview.rst new file mode 100644 index 00000000..0af1caa9 --- /dev/null +++ b/docs/sphinx/rest_substitutions/overviews/dialog_overview.rst @@ -0,0 +1,101 @@ +.. include:: headings.inc + + +.. _dialog overview: + +==================================== +|phoenix_title| **Dialog Overview** +==================================== + + +A dialog box is similar to a panel, in that it is a window which can be used for placing controls, with the following exceptions: + +- A surrounding frame is implicitly created. +- Extra functionality is automatically given to the dialog box, such as tabbing between items (currently Windows only). +- If the dialog box is `modal`, the calling program is blocked until the dialog box is dismissed. + + +.. seealso:: :ref:`TopLevelWindow` and :ref:`Window` for inherited member functions. Validation of data in controls is covered in + :ref:`Validator Overview `. + + +.. _automatic scrolling dialogs: + +Automatic scrolling dialogs +--------------------------- + +As an ever greater variety of mobile hardware comes to market, it becomes more imperative for wxPython applications to adapt to +these platforms without putting too much burden on the programmer. One area where wxPython can help is in adapting dialogs for +the lower resolution screens that inevitably accompany a smaller form factor. :ref:`Dialog` therefore supplies a global +:ref:`DialogLayoutAdapter` class that implements automatic scrolling adaptation for most sizer-based custom dialogs. + +Many applications should therefore be able to adapt to small displays with little or no work, as far as dialogs are concerned. +By default this adaptation is off. To switch scrolling adaptation on globally in your application, call the static function +:meth:`Dialog.EnableLayoutAdaptation` passing ``True``. You can also adjust adaptation on a per-dialog basis by calling +:meth:`Dialog.SetLayoutAdaptationMode` with one of ``DIALOG_ADAPTATION_MODE_DEFAULT`` (use the global setting), ``DIALOG_ADAPTATION_MODE_ENABLED`` +or ``DIALOG_ADAPTATION_MODE_DISABLED``. + +The last two modes override the global adaptation setting. With adaptation enabled, if the display size is too small for the dialog, +wxPython (or rather the standard adapter class :ref:`StandardDialogLayoutAdapter`) will make part of the dialog scrolling, leaving +standard buttons in a non-scrolling part at the bottom of the dialog. This is done as follows, in :meth:`DialogLayoutAdapter.DoLayoutAdaptation` +called from within :meth:`Dialog.Show` or :meth:`Dialog.ShowModal`: + +- If :meth:`Dialog.GetContentWindow` returns a window derived from :ref:`BookCtrlBase`, the pages are made scrollable and no other adaptation is done. +- wxPython looks for a :ref:`StdDialogButtonSizer` and uses it for the non-scrolling part. +- If that search failed, wxPython looks for a horizontal :ref:`BoxSizer` with one or more standard buttons, with identifiers such as ``ID_OK`` and ``ID_CANCEL``. +- If that search failed too, wxPython finds 'loose' standard buttons (in any kind of sizer) and adds them to a :ref:`StdDialogButtonSizer`. + If no standard buttons were found, the whole dialog content will scroll. +- All the children apart from standard buttons are reparented onto a new :ref:`ScrolledWindow` object, using the old top-level sizer + for the scrolled window and creating a new top-level sizer to lay out the scrolled window and standard button sizer. + + +.. _layout adaptation code: + +Customising scrolling adaptation +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +In addition to switching adaptation on and off globally and per dialog, you can choose how aggressively wxPython will search +for standard buttons by setting :meth:`Dialog.SetLayoutAdaptationLevel`. By default, all the steps described above will be +performed but by setting the level to 1, for example, you can choose to only look for :ref:`StdDialogButtonSizer`. + +You can use :meth:`Dialog.AddMainButtonId` to add identifiers for buttons that should also be treated as standard buttons for the non-scrolling area. + +You can derive your own class from :ref:`DialogLayoutAdapter` or :ref:`StandardDialogLayoutAdapter` and call :meth:`Dialog.SetLayoutAdapter`, +deleting the old object that this function returns. Override the functions `CanDoLayoutAdaptation` and `DoLayoutAdaptation` to test +for adaptation applicability and perform the adaptation. + +You can also override :meth:`Dialog.CanDoLayoutAdaptation` and :meth:`Dialog.DoLayoutAdaptation` in a class derived from :ref:`Dialog`. + + +Situations where automatic scrolling adaptation may fail +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Because adaptation rearranges your sizer and window hierarchy, it is not fool-proof, and may fail in the following situations: + +- The dialog doesn't use sizers. +- The dialog implementation makes assumptions about the window hierarchy, for example getting the parent of a control and casting to the dialog class. +- The dialog does custom painting and/or event handling not handled by the scrolled window. If this problem can be solved globally, + you can derive a new adapter class from :ref:`StandardDialogLayoutAdapter` and override its `CreateScrolledWindow` function + to return an instance of your own class. +- The dialog has unusual layout, for example a vertical sizer containing a mixture of standard buttons and other controls. +- The dialog makes assumptions about the sizer hierarchy, for example to show or hide children of the top-level sizer. However, + the original sizer hierarchy will still hold until `Show` or `ShowModal` is called. + + +You can help make sure that your dialogs will continue to function after adaptation by: + +- Avoiding the above situations and assumptions; +- Using :ref:`StdDialogButtonSizer`; +- Only making assumptions about hierarchy immediately after the dialog is created; +- Using an intermediate sizer under the main sizer, a false top-level sizer that can be relied on to exist for the purposes of manipulating child sizers and windows; +- Overriding :meth:`Dialog.GetContentWindow` to return a book control if your dialog implements pages: wxPython will then only make the pages scrollable. + + +PropertySheetDialog and Wizard +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Adaptation for :ref:`PropertySheetDialog` is always done by simply making the pages scrollable, since :meth:`Dialog.GetContentWindow` returns the dialog's +book control and this is handled by the standard layout adapter. + +:ref:`Wizard` uses its own `CanDoLayoutAdaptation` and `DoLayoutAdaptation` functions rather than the global adapter: again, only the wizard pages are made scrollable. + diff --git a/docs/sphinx/rest_substitutions/overviews/dnd_overview.rst b/docs/sphinx/rest_substitutions/overviews/dnd_overview.rst new file mode 100644 index 00000000..c144b1a1 --- /dev/null +++ b/docs/sphinx/rest_substitutions/overviews/dnd_overview.rst @@ -0,0 +1,70 @@ +.. include:: headings.inc + + +.. _drag and drop overview: + +================================================= +|phoenix_title| **Drag and Drop Overview** +================================================= + + +It may be noted that data transfer to and from the clipboard is quite similar to data transfer +with drag and drop and the code to implement these two types is almost the same. In particular, +both data transfer mechanisms store data in some kind of :ref:`DataObject` and identify its format(s) using +the :ref:`DataFormat` class. + +To be a `drag` source, i.e. to provide the data which may be dragged by the user elsewhere, you +should implement the following steps: + +- **Preparation**: First of all, a data object must be created and initialized with the data you wish to drag. For example:: + + my_data = wx.TextDataObject("This text will be dragged.") + + + +- **Drag start**: To start the dragging process (typically in response to a mouse click) you must call + :meth:`DropSource.DoDragDrop` like this:: + + dragSource = wx.DropSource(self) + dragSource.SetData(my_data) + result = dragSource.DoDragDrop(True) + + + +- **Dragging**: The call to `DoDragDrop()` blocks the program until the user releases the mouse button (unless + you override the :meth:`DropSource.GiveFeedback` function to do something special). When the mouse moves in + a window of a program which understands the same drag-and-drop protocol (any program under Windows or any + program supporting the XDnD protocol under X Windows), the corresponding :ref:`DropTarget` methods are called - see below. + +- **Processing the result**: `DoDragDrop()` returns an effect code which is one of the values of :ref:`DragResult`:: + + if result == wx.DragCopy: + # Copy the data + CopyMyData() + + elif result == wx.DragMove: + # Move the data + MoveMyData() + + else: + # Default, do nothing + pass + + +To be a `drop` target, i.e. to receive the data dropped by the user you should follow the instructions below: + +- **Initialization**: For a window to be a drop target, it needs to have an associated :ref:`DropTarget` object. Normally, + you will call :meth:`Window.SetDropTarget` during window creation associating your drop target with it. You must + derive a class from :ref:`DropTarget` and override its pure virtual methods. Alternatively, you may derive + from :ref:`TextDropTarget` or :ref:`FileDropTarget` and override their `OnDropText()` or `OnDropFiles()` method. + +- **Drop**: When the user releases the mouse over a window, wxPython asks the associated :ref:`DropTarget` object if + it accepts the data. For this, a :ref:`DataObject` must be associated with the drop target and this data object + will be responsible for the format negotiation between the drag source and the drop target. If all goes well, + then :meth:`DropTarget.OnData` will get called and the :ref:`DataObject` belonging to the drop target can get filled with data. + +- **The end**: After processing the data, `DoDragDrop()` returns either ``DragCopy`` or ``DragMove`` depending on the + state of the keys ``Ctrl``, ``Shift`` and ``Alt`` at the moment of the drop. There is currently no way for + the drop target to change this return code. + + diff --git a/docs/sphinx/rest_substitutions/overviews/events_overview.rst b/docs/sphinx/rest_substitutions/overviews/events_overview.rst new file mode 100644 index 00000000..ae180d95 --- /dev/null +++ b/docs/sphinx/rest_substitutions/overviews/events_overview.rst @@ -0,0 +1,311 @@ +.. include:: headings.inc + + +.. _events and event handling: + +============================================== +|phoenix_title| **Events and Event Handling** +============================================== + + +Like with all the other GUI frameworks, the control of flow in wxPython applications is event-based: the program +normally performs most of its actions in response to the events generated by the user. These events can be +triggered by using the input devices (such as keyboard, mouse, joystick) directly or, more commonly, by a standard +control which synthesizes such input events into higher level events: for example, a :ref:`Button` can generate +a click event when the user presses the left mouse button on it and then releases it without pressing ``Esc`` in +the meanwhile. There are also events which don't directly correspond to the user actions, such as :ref:`TimerEvent`. + +But in all cases wxPython represents these events in a uniform way and allows you to handle them in the same way +wherever they originate from. And while the events are normally generated by wxPython itself, you can also do this, +which is especially useful when using custom events (see :ref:`Custom Event Summary `). + +To be more precise, each event is described by: + +- `Event type`: this is simply a value of type `EventType` which uniquely identifies the type of the event. + For example, clicking on a button, selecting an item from a list box and pressing a key on the keyboard all + generate events with different event types. +- `Event class` carried by the event: each event has some information associated with it and this data is represented + by an object of a class derived from :ref:`Event`. Events of different types can use the same event class, for + example both button click and listbox selection events use :ref:`CommandEvent` class (as do all the other simple + control events), but the key press event uses :ref:`KeyEvent` as the information associated with it is different. +- `Event source`: :ref:`Event` stores the object which generated the event and, for windows, its identifier (see + :ref:`Window Identifiers `). As it is common to have more than one object generating events of + the same type (e.g. a typical window contains several buttons, all generating the same button click event), checking + the event source object or its id allows to distinguish between them. + + + +.. _event handling: + +Event Handling +-------------- + +There is one principal way to handle events in wxPython, which uses :meth:`EvtHandler.Bind` () call and can be used +to bind and unbind the handlers dynamically, i.e. during run-time depending on some conditions. It also allows the direct +binding of events to: + +- A handler method in another object. +- An ordinary function like a static method or a global function. +- An arbitrary function. + + + +.. _dynamic event handling: + +Dynamic Event Handling +---------------------- + +Let us start by looking at the syntax: in any place in your code, but usually in the code of the class defining the handler +itself, call its `Bind()` method like this:: + + class MyFrame(wx.Frame): + + def __init__(self, parent): + + wx.Frame.__init__(self, parent) + + # Other initialization code... + + self.Bind(wx.EVT_MENU, self.OnExit, id=wx.ID_EXIT) + + + +Event handlers can be bound at any moment. For example, it's possible to do some initialization first and only bind the +handlers if and when it succeeds. This can avoid the need to test that the object was properly initialized in the event +handlers themselves. With `Bind()` they simply won't be called if it wasn't correctly initialized. + +As a slight extension of the above, the handlers can also be unbound at any time with `Unbind()` (and maybe rebound later). + +Almost last but very, very far from least is the flexibility which allows to bind an event to: + +- A method in another object. +- An ordinary function like a static method or a global function. +- An arbitrary function. + + +Let us now look at more examples of how to use different event handlers using the two overloads of `Bind()` function: +first one for the object methods and the other one for arbitrary functors (callable objects, including simple functions). + +In addition to using a method of the object generating the event itself, you can use a method from a completely different +object as an event handler:: + + def OnFrameExit(event) + + # Do something useful. + + + class MyFrame(wx.Frame): + + def __init__(self, parent): + + wx.Frame.__init__(self, parent) + + # Other initialization code... + + self.Bind(wx.EVT_MENU, OnFrameExit, id=wx.ID_EXIT) + + + +Note that `MyFrameHandler` doesn't need to derive from :ref:`EvtHandler`. + + + +.. _how events are processed: + +How Events are Processed +------------------------ + +The previous sections explain how to define event handlers but don't address the question of how exactly +wxPython finds the handler to call for the given event. This section describes the algorithm used in detail. + +When an event is received from the windowing system, wxPython calls :meth:`EvtHandler.ProcessEvent` () on +the first event handler object belonging to the window generating the event. The normal order of event table +searching by `ProcessEvent()` is as follows, with the event processing stopping as soon as a handler is found +(unless the handler calls :meth:`Event.Skip` () in which case it doesn't count as having handled the event +and the search continues): + +1. Before anything else happens, :meth:`AppConsole.FilterEvent` () is called. If it returns anything but -1 (default), + the event handling stops immediately. +2. If this event handler is disabled via a call to :meth:`EvtHandler.SetEvtHandlerEnabled` () the next three + steps are skipped and the event handler resumes at step (5). +3. If the object is a :ref:`Window` and has an associated validator, :ref:`Validator` gets a chance to process the event. +4. The list of dynamically bound event handlers, i.e., those for which `Bind()` was called, is consulted. +5. The event table containing all the handlers defined using the event table macros in this class and its base classes + is examined. Notice that this means that any event handler defined in a base class will be executed at this step. +6. The event is passed to the next event handler, if any, in the event handler chain, i.e., the steps (1) to (4) are done + for it. Usually there is no next event handler so the control passes to the next step but see :ref:`Event Handlers Chain ` + for how the next handler may be defined. +7. If the object is a :ref:`Window` and the event is set to propagate (by default only :ref:`CommandEvent` -derived events are set to propagate), + then the processing restarts from the step (1) (and excluding the step (7)) for the parent window. If this object is not a window + but the next handler exists, the event is passed to its parent if it is a window. This ensures that in a common case of + (possibly several) non-window event handlers pushed on top of a window, the event eventually reaches the window parent. +8. Finally, i.e., if the event is still not processed, the :ref:`App` object itself (which derives from :ref:`EvtHandler`) + gets a last chance to process it. + + +**Please pay close attention to step 6!** People often overlook or get confused by this powerful feature of the wxPython +event processing system. The details of event propagation up the window hierarchy are described in the next section. + + + +.. _how events propagate upwards: + +How Events Propagate Upwards +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +As mentioned above, the events of the classes deriving from :ref:`CommandEvent` are propagated by default to the parent +window if they are not processed in this window itself. But although by default only the command events are propagated +like this, other events can be propagated as well because the event handling code uses :meth:`Event.ShouldPropagate` () +to check whether an event should be propagated. It is also possible to propagate the event only a limited number of times +and not until it is processed (or a top level parent window is reached). + +Finally, there is another additional complication (which, in fact, simplifies life of wxPython programmers significantly): +when propagating the command events up to the parent window, the event propagation stops when it reaches the parent dialog, +if any. This means that you don't risk getting unexpected events from the dialog controls (which might be left unprocessed +by the dialog itself because it doesn't care about them) when a modal dialog is popped up. The events do propagate beyond +the frames, however. The rationale for this choice is that there are only a few frames in a typical application and their +parent-child relation are well understood by the programmer while it may be difficult, if not impossible, to track down all +the dialogs that may be popped up in a complex program (remember that some are created automatically by wxPython). +If you need to specify a different behaviour for some reason, you can use :meth:`Window.SetExtraStyle` (``WS_EX_BLOCK_EVENTS``) +explicitly to prevent the events from being propagated beyond the given window or unset this flag for the dialogs that +have it on by default. + +Typically events that deal with a window as a window (size, motion, paint, mouse, keyboard, etc.) are sent only to the window. +Events that have a higher level of meaning or are generated by the window itself (button click, menu select, tree expand, etc.) +are command events and are sent up to the parent to see if it is interested in the event. More precisely, as said above, all +event classes not deriving from :ref:`CommandEvent` (see the :ref:`Event` inheritance diagram) do not propagate upward. + +In some cases, it might be desired by the programmer to get a certain number of system events in a parent window, for +example all key events sent to, but not used by, the native controls in a dialog. In this case, a special event handler +will have to be written that will override `ProcessEvent()` in order to pass all events (or any selection of them) to the +parent window. + + +.. _event handlers chain: + +Event Handlers Chain +^^^^^^^^^^^^^^^^^^^^ + +The step 4 of the event propagation algorithm checks for the next handler in the event handler chain. This chain can be formed +using :meth:`EvtHandler.SetNextHandler` (): + +.. figure:: _static/images/overviews/overview_events_chain.png + :align: center + +| + +(referring to the image, if `A.ProcessEvent` is called and it doesn't handle the event, `B.ProcessEvent` will be called and so on...). + +Additionally, in the case of :ref:`Window` you can build a stack (implemented using :ref:`EvtHandler` double-linked list) using +:meth:`Window.PushEventHandler` (): + +.. figure:: _static/images/overviews/overview_events_winstack.png + :align: center + +| + + + +(referring to the image, if `W.ProcessEvent` is called, it immediately calls `A.ProcessEvent`; if nor A nor B handle the event, +then the :ref:`Window` itself is used -- i.e. the dynamically bind event handlers and static event table entries of :ref:`Window` +are looked as the last possibility, after all pushed event handlers were tested). + +By default the chain is empty, i.e. there is no next handler. + + +.. _custom event summary: + +Custom Event Summary +-------------------- + +General approach +^^^^^^^^^^^^^^^^ + +Custom event classes allow you to create more polished-seeming controls by allowing the control's user to process updates +without needing to sub-class the control. However, to effectively use events, you normally need to create custom event classes. + +This recipe gives you some boilerplate code for creating your own custom event classes:: + + import wx + import wx.lib.newevent + + SomeNewEvent, EVT_SOME_NEW_EVENT = wx.lib.newevent.NewEvent() + SomeNewCommandEvent, EVT_SOME_NEW_COMMAND_EVENT = wx.lib.newevent.NewCommandEvent() + + +You can bind the events normally via either binding syntax:: + + self.Bind(EVT_SOME_NEW_EVENT, self.handler) + EVT_SOME_NEW_EVENT(self, self.handler) + + +You can also attach arbitrary data to the event during its creation, then post it to whatever window you choose:: + + # Create the event + evt = SomeNewEvent(attr1="hello", attr2=654) + # Post the event + wx.PostEvent(target, evt) + + +When handling events with such arbitrary data, you can fetch the data via attributes, named the same as the names +passed in during the event instance creation. That is, given the two keyword arguments passed to SomeNewEvent above:: + + + def handler(self, evt): + # Given the above constructed event, the following is true + evt.attr1 == "hello" + evt.attr2 == 654 + + + + +Miscellaneous Notes +------------------- + + +.. _user generated events vs programmatically generated events: + +User Generated Events vs Programmatically Generated Events +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +While generically a :ref:`Event` can be generated both by user actions (e.g., resize of a :ref:`Window`) and by calls to functions +(e.g., :meth:`Window.SetSize`), wxPython controls normally send :ref:`CommandEvent` -derived events only for the user-generated +events. The only exceptions to this rule are: + +- :meth:`BookCtrlBase.AddPage` No event-free alternatives +- :meth:`BookCtrlBase.AdvanceSelection` No event-free alternatives +- :meth:`BookCtrlBase.DeletePage` No event-free alternatives +- :meth:`Notebook.SetSelection`: Use :meth:`Notebook.ChangeSelection` instead, as :meth:`Notebook.SetSelection` is deprecated +- :meth:`TreeCtrl.Delete`: No event-free alternatives +- :meth:`TreeCtrl.DeleteAllItems`: No event-free alternatives +- :meth:`TreeCtrl.EditLabel`: No event-free alternatives +- All :ref:`TextCtrl` methods + + +:meth:`TextEntry.ChangeValue` can be used instead of :meth:`TextEntry.SetValue` but the other functions, such as :meth:`TextEntry.Replace` +or meth:`TextCtrl.WriteText` don't have event-free equivalents. + + + +.. _window identifiers: + +Window Identifiers +^^^^^^^^^^^^^^^^^^ + +Window identifiers are integers, and are used to uniquely determine window identity in the event system (though you can use it +for other purposes). In fact, identifiers do not need to be unique across your entire application as long they are unique within +the particular context you're interested in, such as a frame and its children. You may use the ``ID_OK`` identifier, for example, +on any number of dialogs as long as you don't have several within the same dialog. + +If you pass ``ID_ANY`` or -1 to a window constructor, an identifier will be generated for you automatically by wxPython. This is useful +when you don't care about the exact identifier either because you're not going to process the events from the control being created +or because you process the events from all controls in one place (in which case you should specify ``ID_ANY`` in the :meth:`EvtHandler.Bind` +call as well). The automatically generated identifiers are always negative and so will never conflict with the user-specified +identifiers which must be always positive. + +.. seealso:: See :ref:`Standard event identifiers ` for the list of standard identifiers available. + + +You can use ``ID_HIGHEST`` to determine the number above which it is safe to define your own identifiers. Or, you can use identifiers below ``ID_LOWEST``. +Finally, you can allocate identifiers dynamically using :func:`NewId` () function too. If you use :func:`NewId` () consistently in your +application, you can be sure that your identifiers don't conflict accidentally. diff --git a/docs/sphinx/rest_substitutions/overviews/font_encodings.rst b/docs/sphinx/rest_substitutions/overviews/font_encodings.rst new file mode 100644 index 00000000..41030391 --- /dev/null +++ b/docs/sphinx/rest_substitutions/overviews/font_encodings.rst @@ -0,0 +1,57 @@ +.. include:: headings.inc + + +.. _font encodings: + +================================================= +|phoenix_title| **Font Encodings** +================================================= + + +wxPython has support for multiple font encodings. + +By encoding we mean here the mapping between the character codes and the letters. Probably the most well-known encoding is +(7 bit) ASCII one which is used almost universally now to represent the letters of the English alphabet and some other +common characters. However, it is not enough to represent the letters of foreign alphabets and here other encodings +come into play. Please note that we will only discuss 8-bit fonts here and not Unicode. + +Font encoding support is ensured by several classes: :ref:`Font` itself, but also :ref:`FontEnumerator` and :ref:`FontMapper`. +:ref:`Font` encoding support is reflected by a (new) constructor parameter encoding which takes one of the following +values (elements of enumeration type :ref:`FontEncoding`): + +======================================== ========================================================= +``FONTENCODING_SYSTEM`` The default encoding of the underlying operating system (notice that this might be a "foreign" encoding for foreign versions of Windows 9x/NT). +``FONTENCODING_DEFAULT`` The applications default encoding as returned by :meth:`Font.GetDefaultEncoding`. On program startup, the applications default encoding is the same as ``FONTENCODING_SYSTEM``, but may be changed to make all the fonts created later to use it (by default). +``FONTENCODING_ISO8859_1..15`` ISO8859 family encodings which are usually used by all non-Microsoft operating systems. +``FONTENCODING_KOI8`` Standard Cyrillic encoding for the Internet (but see also ``FONTENCODING_ISO8859_5`` and ``FONTENCODING_CP1251``). +``FONTENCODING_CP1250`` Microsoft analogue of ISO8859-2 +``FONTENCODING_CP1251`` Microsoft analogue of ISO8859-5 +``FONTENCODING_CP1252`` Microsoft analogue of ISO8859-1 +======================================== ========================================================= + + +As you may see, Microsoft's encoding partly mirror the standard ISO8859 ones, but there are (minor) differences even between +ISO8859-1 (Latin1, ISO encoding for Western Europe) and CP1251 (WinLatin1, standard code page for English versions of Windows) +and there are more of them for other encodings. + +The situation is particularly complicated with Cyrillic encodings for which (more than) three incompatible encodings exist: +KOI8 (the old standard, widely used on the Internet), ISO8859-5 (ISO standard for Cyrillic) and CP1251 (WinCyrillic). + +This abundance of (incompatible) encodings should make it clear that using encodings is less easy than it might seem. +The problems arise both from the fact that the standard encodings for the given language (say Russian, which is written +in Cyrillic) are different on different platforms and because the fonts in the given encoding might just not be installed +(this is especially a problem with Unix, or, in general, non-Win32 systems). + +To clarify, the :ref:`FontEnumerator` class may be used to enumerate both all available encodings and to find the facename(s) +in which the given encoding exists. If you can find the font in the correct encoding with :ref:`FontEnumerator` then your +troubles are over, but, unfortunately, sometimes this is not enough. For example, there is no standard way (that I know of, +please tell me if you do!) to find a font on a Windows system for KOI8 encoding (only for WinCyrillic one which is quite different), +so :ref:`FontEnumerator` will never return one, even if the user has installed a KOI8 font on his system. + +To solve this problem, a :ref:`FontMapper` class is provided. + +This class stores the mapping between the encodings and the font face names which support them in :ref:`ConfigBase` object. +Of course, it would be fairly useless if it tried to determine these mappings by itself, so, instead, it (optionally) asks +the user and remembers his answers so that the next time the program will automatically choose the correct font. + + diff --git a/docs/sphinx/rest_substitutions/overviews/font_overview.rst b/docs/sphinx/rest_substitutions/overviews/font_overview.rst new file mode 100644 index 00000000..11e48b6c --- /dev/null +++ b/docs/sphinx/rest_substitutions/overviews/font_overview.rst @@ -0,0 +1,55 @@ +.. include:: headings.inc + + +.. _font overview: + +================================================= +|phoenix_title| **Font Overview** +================================================= + + +Introduction +------------ + +A font is an object which determines the appearance of text, primarily when drawing text to a window +or device context. A font is determined by the following parameters (not all of them have to be specified, of course): + +======================== ========================================== +**Point size** This is the standard way of referring to text size. +**Family** Supported families are: ``DEFAULT``, ``DECORATIVE``, ``ROMAN``, ``SCRIPT``, ``SWISS``, ``MODERN``. ``MODERN`` is a fixed pitch font; the others are either fixed or variable pitch. +**Style** The value can be ``NORMAL``, ``SLANT`` or ``ITALIC``. +**Weight** The value can be ``NORMAL``, ``LIGHT`` or ``BOLD``. +**Underlining** The value can be ``True`` or ``False``. +**Face name** An optional string specifying the actual typeface to be used. If ``None``, a default typeface will chosen based on the family. +**Encoding** The font encoding (see ``FONTENCODING_XXX`` constants and the :ref:`Font Encodings ` for more details) +======================== ========================================== + +Specifying a family, rather than a specific typeface name, ensures a degree of portability across platforms because a +suitable font will be chosen for the given font family, however it doesn't allow to choose a font precisely as the parameters +above don't suffice, in general, to identify all the available fonts and this is where using the native font descriptions +may be helpful - see below. + +Under Windows, the face name can be one of the installed fonts on the user's system. Since the choice of fonts differs +from system to system, either choose standard Windows fonts, or if allowing the user to specify a face name, store the +family name with any file that might be transported to a different Windows machine or other platform. + +.. note:: There is currently a difference between the appearance of fonts on the two platforms, if the mapping mode is anything + other than ``MM_TEXT``. Under X, font size is always specified in points. Under MS Windows, the unit for text is points but + the text is scaled according to the current mapping mode. However, user scaling on a device context will also scale fonts under both environments. + + +Native font information +----------------------- + +An alternative way of choosing fonts is to use the native font description. This is the only acceptable solution if the user +is allowed to choose the font using the :ref:`FontDialog` because the selected font cannot be described using only the family +name and so, if only family name is stored permanently, the user would almost surely see a different font in the program later. + +Instead, you should store the value returned by :meth:`Font.GetNativeFontInfoDesc` and pass it to :meth:`Font.SetNativeFontInfo` +later to recreate exactly the same font. + +.. note:: Note that the contents of this string depends on the platform and shouldn't be used for any other purpose (in particular, it is not + meant to be shown to the user). Also please note that although the native font information is currently implemented for Windows and + Unix (GTK+ and Motif) ports only, all the methods are available for all the ports and should be used to make your program work correctly + when they are implemented later. + diff --git a/docs/sphinx/rest_substitutions/overviews/index.rst b/docs/sphinx/rest_substitutions/overviews/index.rst new file mode 100644 index 00000000..ca412d72 --- /dev/null +++ b/docs/sphinx/rest_substitutions/overviews/index.rst @@ -0,0 +1,146 @@ +.. wxPython (Phoenix) documentation master file, created by + sphinx-quickstart on Fri Dec 09 11:27:02 2011. + You can adapt this file completely to your liking, but it should at least + contain the root `toctree` directive. + +============================================== +Welcome to wxPython (Phoenix)'s documentation! +============================================== + + +wxPython +======== + +wxPython is a **GUI toolkit** for the `Python `_ programming language. It allows Python programmers to +create programs with a robust, highly functional graphical user interface, simply and easily. + +.. figure:: _static/images/sphinxdocs/central_bar.png + :align: center + + +| + +What is wxPython +---------------- + +wxPython is a **GUI toolkit** for the `Python `_ programming language. It allows Python programmers to +create programs with a robust, highly functional graphical user interface, simply and easily. +It is implemented as a Python extension module (native code) that wraps the popular `wxWidgets `_ cross +platform GUI library, which is written in C++. + +Like Python and wxWidgets, wxPython is *Open Source* which means that it is free for anyone to use and +the source code is available for anyone to look at and modify. Or anyone can contribute fixes or +enhancements to the project. + +wxPython is a *cross-platform* toolkit. This means that the same program will run on multiple platforms +without modification. Currently supported platforms are 32-bit Microsoft Windows, most Unix or unix-like +systems, and Macintosh OS X+, in most cases the native widgets are used on each platform. + +Since the language is Python, wxPython programs are **simple, easy** to write and easy to understand. + +As an example, this is a simple "Hello World" program with wxPython:: + + import wx + + app = wx.App() + + frame = wx.Frame(None, -1, "Hello World") + frame.Show() + + app.MainLoop() + + +The GUI layouts you can build with wxPython are almost infinite: it has an extremely rich set of widgets (derived from `wxWidgets`) and +greatly extended by a huge set of pure-Python controls written over the years. + + +Prerequisites +------------- + +Like any other complex piece of software, wxPython requires other software in order to function properly. +Obviously you'll need `Python `_ itself, but if you're reading this you've probably already got +Python and are just here looking for the `best GUI toolkit `_ available for Python. +Check out the details for your platform of choice here: + +Win32 +^^^^^ + +* If you have a modern up to date version of Windows and use the binary installer for wxPython found below, you probably + don't need anything else. + +* If your tree controls have strange background colors, try loading this `MS Common Controls Update `_ + as wxWidgets does something that causes a bug in one of the older versions to manifest itself. Another way to get this update + is to install Internet Explorer or MS Office apps, so if the system has those already then you probably don't need to worry about this. + +* wxPython's `wx.glcanvas.GLCanvas` class only provides the GL Context and a wx.Window to put it in, so if you want to use + the wxGLCanvas you will also need the `PyOpenGL `_ Python extension modules as well. + + +Linux/Unix/Etc. +^^^^^^^^^^^^^^^ + +* The first thing you'll need are the `glib and gtk+ `_ libraries. Before you run off and download the sources + check your system, you probably already have it. Most distributions of Linux come with it and you'll start seeing it on many + other systems too now that Sun and others have chosen GNOME as the desktop of choice. If you don't have glib and gtk+ already, + you can get the sources `here `_. Build and install them following the directions included. + +* In order to use the wxGLCanvas you'll need to have either OpenGL or the `Mesa3D `_ library on your system. + wxPython's `wx.glcanvas.GLCanvas` only provides the GL Context and a :class:`Window` to put it in, so you will also need the PyOpenGL + Python extension modules as well, if you want to use OpenGL. + + If you are building wxPython yourself and don't care to use OpenGL/Mesa then you can easily skip building it and can ignore + this step. See the `build instructions `_ for details. + + +Mac OS X +^^^^^^^^ + +The wxPython binaries for OSX are mountable disk images. Simply double click to mount the image and then run the installer application +in the image. Download the image that matches the version of Python that you want to use it with, and unless you know for sure that you +need the ansi build please get the Unicode build. + +These binaries should work on all versions of OSX from 10.3.9 onwards on either PPC or i386 architectures. Since they use the Carbon API + they are limited to running in 32-bit mode. + + +OK, I'm interested. What do I do next? +-------------------------------------- + +You can download the `Prebuild binary of wxPython +`_ which includes +the source code for wxPython. + +Prebuilt binaries are available for Microsoft Windows, Linux and Mac OS X. + +Don't forget to download the wxPython demo and the documentation! + + +Bleeding-edge source +-------------------- + +If you are a very keen developer, you can access the SVN repository directly for this +project in the `wxWidgets SVN `_. + + + +wxPython Documentation +---------------------- + +The new wxPython API documentation is available `in this page `_. + + +.. toctree:: + :maxdepth: 2 + :hidden: + :glob: + + * + + +Indices and tables +================== + +* `genindex` +* `modindex` +* `search` + diff --git a/docs/sphinx/rest_substitutions/overviews/log_classes_overview.rst b/docs/sphinx/rest_substitutions/overviews/log_classes_overview.rst new file mode 100644 index 00000000..219dc56e --- /dev/null +++ b/docs/sphinx/rest_substitutions/overviews/log_classes_overview.rst @@ -0,0 +1,229 @@ +.. include:: headings.inc + + +.. _log classes overview: + +=============================================== +|phoenix_title| **Log Classes Overview** +=============================================== + + +Introduction +------------ + +This is a general overview of logging classes provided by wxPython. The word logging here has a broad sense, including all +of the program output, not only non-interactive messages. The logging facilities included in wxPython provide the base :ref:`Log` +class which defines the standard interface for a log target as well as several standard implementations of it and a family of +functions to use with them. + +First of all, no knowledge of :ref:`Log` classes is needed to use them. For this, you should only know about :func:`LogDebug`, +:func:`LogError`, :func:`LogMessage` and similar functions. All of them have the same syntax as the Python +`logging `_ module. + +Here are all of them: + +- :func:`LogFatalError` which is like :func:`LogError`, but also terminates the program with the exit code 3 (using `abort()` + standard function). Unlike for all the other logging functions, this function can't be overridden by a log target. +- :func:`LogError` is the function to use for error messages, i.e. the messages that must be shown to the user. + The default processing is to pop up a message box to inform the user about it. +- :func:`LogWarning` for warnings. They are also normally shown to the user, but don't interrupt the program work. +- :func:`LogMessage` is for all normal, informational messages. They also appear in a message box by default (but it can be changed, see below). +- :func:`LogVerbose` is for verbose output. Normally, it is suppressed, but might be activated if the user wishes to know + more details about the program progress (another, but possibly confusing name for the same function is :func:`LogInfo`). +- :func:`LogStatus` is for status messages. They will go into the status bar of the active or specified (as the first argument) + :ref:`Frame` if it has one. +- :func:`LogSysError` is mostly used by wxPython itself, but might be handy for logging errors after system call (API function) + failure. It logs the specified message text as well as the last system error code (`errno` or Windows' `GetLastError()` depending + on the platform) and the corresponding error message. The second form of this function takes the error code explicitly as the first argument. +- :func:`LogDebug` is the right function for debug output. It only does anything at all in the debug mode (when the preprocessor + symbol ``__WXDEBUG__`` is defined) and expands to nothing in release mode (otherwise). Note that under Windows, you must either run + the program under debugger or use a 3rd party program such as **DebugView** (http://www.microsoft.com/technet/sysinternals/Miscellaneous/DebugView.mspx) + to actually see the debug output. +- :func:`LogTrace` as :func:`LogDebug` only does something in debug build. The reason for making it a separate function from it is + that usually there are a lot of trace messages, so it might make sense to separate them from other debug messages which would be + flooded in them. Moreover, the second version of this function takes a trace mask as the first argument which allows to further + restrict the amount of messages generated. + + +The usage of these functions should be fairly straightforward, however it may be asked why not use the other logging facilities, +such as the Python `logging `_ module. The short answer is that they're all very +good generic mechanisms, but are not really adapted for wxPython, while the log classes are. + +Some of advantages in using wxPython log functions are: + +- Portability +- Flexibility: The output of :ref:`Log` functions can be redirected or suppressed entirely based on their importance, which is + either impossible or difficult to do with traditional methods. For example, only error messages, or only error messages and + warnings might be logged, filtering out all informational messages. +- Completeness: Usually, an error message should be presented to the user when some operation fails. Let's take a quite simple but + common case of a file error: suppose that you're writing your data file on disk and there is not enough space. The actual error + might have been detected inside wxPython code, so the calling function doesn't really know the exact reason of the failure, + it only knows that the data file couldn't be written to the disk. However, as wxPython uses :func:`LogError` in this situation, + the exact error code (and the corresponding error message) will be given to the user together with "high level" message about + data file writing error. + + + +.. _log messages selection: + +Log Messages Selection +---------------------- + +By default, most log messages are enabled. In particular, this means that errors logged by wxPython code itself (e.g. when it fails +to perform some operation) will be processed and shown to the user. To disable the logging entirely you can use :meth:`Log.EnableLogging` +method or, more usually, :ref:`LogNull` class which temporarily disables logging and restores it back to the original setting when it is destroyed. + +To limit logging to important messages only, you may use :meth:`Log.SetLogLevel` with e.g. ``LOG_Warning`` value -- this will completely +disable all logging messages with the severity less than warnings, so :func:`LogMessage` output won't be shown to the user any more. + +Moreover, the log level can be set separately for different log components. Before showing how this can be useful, let us explain what +log components are: they are simply arbitrary strings identifying the component, or module, which generated the message. They are hierarchical +in the sense that "foo/bar/baz" component is supposed to be a child of "foo". And all components are children of the unnamed root component. + +By default, all messages logged by wxPython originate from "wx" component or one of its subcomponents such as "wx/net/ftp", while the +messages logged by your own code are assigned empty log component. To change this, you need to define ``LOG_COMPONENT`` to a string uniquely +identifying each component, e.g. you could give it the value "MyProgram" by default and re-define it as "MyProgram/DB" in the module +working with the database and "MyProgram/DB/Trans" in its part managing the transactions. Then you could use :meth:`Log.SetComponentLevel` +in the following ways:: + + # Disable all database error messages, everybody knows databases never + # fail anyhow + wx.Log.SetComponentLevel("MyProgram/DB", wx.LOG_FatalError) + + # but enable tracing for the transactions as somehow our changes don't + # get committed sometimes + wx.Log.SetComponentLevel("MyProgram/DB/Trans", wx.LOG_Trace) + + # also enable tracing messages from wxPython dynamic module loading + # mechanism + wx.Log.SetComponentLevel("wx/base/module", wx.LOG_Trace) + + + +Notice that the log level set explicitly for the transactions code overrides the log level of the parent component but that all other database +code subcomponents inherit its setting by default and so won't generate any log messages at all. + + + +.. _log targets: + +Log Targets +----------- + +After having enumerated all the functions which are normally used to log the messages, and why would you want to use them, we now +describe how all this works. + +wxPython has the notion of a `log target`: it is just a class deriving from :ref:`Log`. As such, it implements the virtual functions +of the base class which are called when a message is logged. Only one log target is active at any moment, this is the one used by +`LogXXX` functions. The normal usage of a log object (i.e. object of a class derived from :ref:`Log`) is to install it as the active +target with a call to `SetActiveTarget()` and it will be used automatically by all subsequent calls to `LogXXX` functions. + +To create a new log target class you only need to derive it from :ref:`Log` and override one or several of :meth:`Log.DoLogRecord`, +:meth:`Log.DoLogTextAtLevel` and :meth:`Log.DoLogText` in it. The first one is the most flexible and allows you to change the formatting +of the messages, dynamically filter and redirect them and so on -- all log messages, except for those generated by :func:`LogFatalError`, +pass by this function. :meth:`Log.DoLogTextAtLevel` should be overridden if you simply want to redirect the log messages somewhere else, +without changing their formatting. Finally, it is enough to override :meth:`Log.DoLogText` if you only want to redirect the log +messages and the destination doesn't depend on the message log level. + +There are some predefined classes deriving from :ref:`Log` and which might be helpful to see how you can create a new log target +class and, of course, may also be used without any change. There are: + +- :ref:`LogStderr`: This class logs messages to a ``FILE *``, using stderr by default as its name suggests. +- `LogStream`: This class has the same functionality as :ref:`LogStderr`, but uses stdout. +- :ref:`LogGui`: This is the standard log target for wxPython applications (it is used by default if you don't do anything) and provides + the most reasonable handling of all types of messages for given platform. +- :ref:`LogWindow`: This log target provides a "log console" which collects all messages generated by the application and also passes + them to the previous active log target. The log window frame has a menu allowing user to clear the log, close it completely or save all messages to file. +- :ref:`LogBuffer`: This target collects all the logged messages in an internal buffer allowing to show them later to the user all at once. +- :ref:`LogNull`: The last log class is quite particular: it doesn't do anything. The objects of this class may be instantiated to (temporarily) + suppress output of `LogXXX` functions. + + +The log targets can also be combined: for example you may wish to redirect the messages somewhere else (for example, to a log file) +but also process them as normally. For this the :ref:`LogChain`, :ref:`LogInterposer`, and :ref:`LogInterposerTemp` can be used. + + + +.. _logging in multi-threaded applications: + +Logging in Multi-Threaded Applications +-------------------------------------- + +Starting with wxPython 2.9.1, logging functions can be safely called from any thread. Messages logged from threads other than the main +one will be buffered until :meth:`Log.Flush` is called in the main thread (which usually happens during idle time, i.e. after processing +all pending events) and will be really output only then. Notice that the default GUI logger already only output the messages when it is +flushed, so by default messages from the other threads will be shown more or less at the same moment as usual. However if you define a +custom log target, messages may be logged out of order, e.g. messages from the main thread with later timestamp may appear before messages +with earlier timestamp logged from other threads. :ref:`Log` does however guarantee that messages logged by each thread will appear in +order in which they were logged. + +Also notice that :meth:`Log.EnableLogging` and :ref:`LogNull` class which uses it only affect the current thread, i.e. logging messages +may still be generated by the other threads after a call to `EnableLogging(False)`. + + + +.. _logging customization: + +Logging Customization +--------------------- + +To completely change the logging behaviour you may define a custom log target. For example, you could define a class inheriting from +:ref:`Log` which shows all the log messages in some part of your main application window reserved for the message output without +interrupting the user work flow with modal message boxes. + +To use your custom log target you may either call :meth:`Log.SetActiveTarget` with your custom log object or create a :ref:`AppTraits` -derived +class and override :meth:`AppTraits.CreateLogTarget` virtual method in it and also override :meth:`App.CreateTraits` to return an instance +of your custom traits object. Notice that in the latter case you should be prepared for logging messages early during the program startup +and also during program shutdown so you shouldn't rely on existence of the main application window, for example. You can however safely +assume that GUI is (already/still) available when your log target as used as wxPython automatically switches to using :ref:`LogStderr` +if it isn't. + +There are several methods which may be overridden in the derived class to customize log messages handling: :meth:`Log.DoLogRecord`, +:meth:`Log.DoLogTextAtLevel` and :meth:`Log.DoLogText`. + +The last method is the simplest one: you should override it if you simply want to redirect the log output elsewhere, without taking +into account the level of the message. If you do want to handle messages of different levels differently, then you should override +:meth:`Log.DoLogTextAtLevel`. + +Additionally, you can customize the way full log messages are constructed from the components (such as time stamp, source file information, +logging thread ID and so on). This task is performed by :ref:`LogFormatter` class so you need to derive a custom class from it and override +its `Format()` method to build the log messages in desired way. Notice that if you just need to modify (or suppress) the time stamp display, +overriding `FormatTime()` is enough. + +Finally, if even more control over the output format is needed, then `LogRecord()` can be overridden as it allows to construct custom +messages depending on the log level or even do completely different things depending on the message severity (for example, throw away all +messages except warnings and errors, show warnings on the screen and forward the error messages to the user's (or programmer's) cell +phone -- maybe depending on whether the timestamp tells us if it is day or night in the current time zone). + + + +.. _using trace masks: + +Using trace masks +----------------- + +Notice that the use of log trace masks is hardly necessary any longer in current wxPython version as the same effect can be achieved by +using different log components for different log statements of any level. Please see :ref:`Log Messages Selection ` +for more information about the log components. + +The functions below allow some limited customization of :ref:`Log` behaviour without writing a new log target class (which, aside from +being a matter of several minutes, allows you to do anything you want). The verbose messages are the trace messages which are not disabled +in the release mode and are generated by :func:`LogVerbose`. They are not normally shown to the user because they present little interest, +but may be activated, for example, in order to help the user find some program problem. + +As for the (real) trace messages, their handling depends on the currently enabled trace masks: if :meth:`Log.AddTraceMask` was called for +the mask of the given message, it will be logged, otherwise nothing happens. + + +For example:: + + wx.LogTrace(wx.TRACE_OleCalls, "Foo.Bar() called") + + +will log the message if it was preceded by:: + + wx.Log.AddTraceMask(wx.TRACE_OleCalls) + + +The standard trace masks are given in the :func:`LogTrace` documentation. + diff --git a/docs/sphinx/rest_substitutions/overviews/printing_framework_overview.rst b/docs/sphinx/rest_substitutions/overviews/printing_framework_overview.rst new file mode 100644 index 00000000..096e6231 --- /dev/null +++ b/docs/sphinx/rest_substitutions/overviews/printing_framework_overview.rst @@ -0,0 +1,155 @@ +.. include:: headings.inc + + +.. _printing framework overview: + +================================================= +|phoenix_title| **Printing Framework Overview** +================================================= + + +The printing framework relies on the application to provide classes whose member functions can respond +to particular requests, such as 'print this page' or 'does this page exist in the document?'. This method +allows wxPython to take over the housekeeping duties of turning preview pages, calling the print dialog box, +creating the printer device context, and so on: the application can concentrate on the rendering of the +information onto a device context. + +In most cases, the only class you will need to derive from is :ref:`Printout`; all others will be used as-is. + +A brief description of each class's role and how they work together follows. + + +Printout +-------- + +A document's printing ability is represented in an application by a derived :ref:`Printout` class. This class +prints a page on request, and can be passed to the Print function of a :ref:`Printer` object to actually print +the document, or can be passed to a :ref:`PrintPreview` object to initiate previewing. The following code +shows how easy it is to initiate printing, previewing and the print setup dialog, once the :ref:`Printout` +functionality has been defined. Notice the use of `MyPrintout` for both printing and previewing. All the preview +user interface functionality is taken care of by wxPython:: + + if printing: + printer = wx.Printer() + printout = MyPrintout("My printout") + printer.Print(self, printout, True) + + elif preview: + # Pass two printout objects: for preview, and possible printing. + preview = wx.PrintPreview(MyPrintout(), MyPrintout()) + frame = wx.PreviewFrame(preview, self, "Demo Print Preview", wx.Point(100, 100), wx.Size(600, 650)) + frame.Centre(wx.BOTH) + frame.Initialize() + frame.Show(True) + + + +:ref:`Printout` assembles the printed page and (using your subclass's overrides) writes requested pages to a :ref:`DC` +that is passed to it. This :ref:`DC` could be a :ref:`MemoryDC` (for displaying the preview image on-screen), +a :ref:`PrinterDC` (for printing under MSW and Mac), or a :ref:`PostScriptDC` (for printing under GTK or generating PostScript output). + +If your window classes have a `Draw(dc)` routine to do screen rendering, your :ref:`Printout` subclass will typically +call those routines to create portions of the image on your printout. Your :ref:`Printout` subclass can also make its +own calls to its :ref:`DC` to draw headers, footers, page numbers, etc. + +The scaling of the drawn image typically differs from the screen to the preview and printed images. This class provides +a set of routines named `FitThisSizeToXXX()`, `MapScreenSizeToXXX()`, and `GetLogicalXXXRect`, which can be used to set +the user scale and origin of the Printout's DC so that your class can easily map your image to the printout withouth +getting into the details of screen and printer PPI and scaling. + + +Printer +------- + +Class :ref:`Printer` encapsulates the platform-dependent print function with a common interface. In most cases, you will +not need to derive a class from :ref:`Printer`; simply create a :ref:`Printer` object in your `Print` function as in the example above. + + +PrintPreview +------------ + +Class :ref:`PrintPreview` manages the print preview process. Among other things, it constructs the DCs that get passed to your +:ref:`Printout` subclass for printing and manages the display of multiple pages, a zoomable preview image, and so forth. +In most cases you will use this class as-is, but you can create your own subclass, for example, to change the layout or +contents of the preview window. + + +PrinterDC +--------- + +Class :ref:`PrinterDC` is the :ref:`DC` that represents the actual printed page under MSW and Mac. During printing, an object +of this class will be passed to your derived :ref:`Printout` object to draw upon. The size of the :ref:`PrinterDC` will depend +on the paper orientation and the resolution of the printer. + +There are two important rectangles in printing: the page rectangle defines the printable area seen by the application, and under +MSW and Mac, it is the printable area specified by the printer. (For PostScript printing, the page rectangle is the entire page.) +The inherited function :meth:`DC.GetSize` returns the page size in device pixels. The point (0,0) on the :ref:`PrinterDC` +represents the top left corner of the page rectangle; that is, the page rect is given by `Rect(0, 0, w, h)`, where (w,h) are the values +returned by `GetSize`. + +The paper rectangle, on the other hand, represents the entire paper area including the non-printable border. Thus, the coordinates +of the top left corner of the paper rectangle will have small negative values, while the width and height will be somewhat larger +than that of the page rectangle. The :ref:`PrinterDC` -specific function :meth:`PrinterDC.GetPaperRect` returns the paper +rectangle of the given :ref:`PrinterDC`. + + +PostScriptDC +------------ + +Class :ref:`PostScriptDC` is the :ref:`DC` that represents the actual printed page under GTK and other PostScript printing. +During printing, an object of this class will be passed to your derived :ref:`Printout` object to draw upon. The size of +the :ref:`PostScriptDC` will depend upon the :ref:`PrintData` used to construct it. + +Unlike a :ref:`PrinterDC`, there is no distinction between the page rectangle and the paper rectangle in a :ref:`PostScriptDC`; +both rectangles are taken to represent the entire sheet of paper. + + +PrintDialog +----------- + +Class :ref:`PrintDialog` puts up the standard print dialog, which allows you to select the page range for printing (as well +as many other print settings, which may vary from platform to platform). You provide an object of type :ref:`PrintDialogData` to +the :ref:`PrintDialog` at construction, which is used to populate the dialog. + + +PrintData +--------- + +Class :ref:`PrintData` is a subset of :ref:`PrintDialogData` that is used (internally) to initialize a :ref:`PrinterDC` or +:ref:`PostScriptDC`. (In fact, a :ref:`PrintData` is a data member of a :ref:`PrintDialogData` and a :ref:`PageSetupDialogData`). +Essentially, :ref:`PrintData` contains those bits of information from the two dialogs necessary to configure the :ref:`PrinterDC` or +:ref:`PostScriptDC` (e.g., size, orientation, etc.). You might wish to create a global instance of this object to provide +call-to-call persistence to your application's print settings. + + +PrintDialogData +--------------- + +Class :ref:`PrintDialogData` contains the settings entered by the user in the print dialog. It contains such things as page range, +number of copies, and so forth. In most cases, you won't need to access this information; the framework takes care of asking your +:ref:`Printout` derived object for the pages requested by the user. + + +PageSetupDialog +--------------- + +Class :ref:`PageSetupDialog` puts up the standard page setup dialog, which allows you to specify the orientation, paper size, +and related settings. You provide it with a :ref:`PageSetupDialogData` object at intialization, which is used to populate the dialog; +when the dialog is dismissed, this object contains the settings chosen by the user, including orientation and/or page margins. + + +.. note:: Note that on Macintosh, the native page setup dialog does not contain entries that allow you to change the page margins. + + + +PageSetupDialogData +------------------- + +Class :ref:`PageSetupDialogData` contains settings affecting the page size (paper size), orientation, margins, and so forth. Note +that not all platforms populate all fields; for example, the MSW page setup dialog lets you set the page margins while the Mac setup dialog does not. + +You will typically create a global instance of each of a :ref:`PrintData` and :ref:`PageSetupDialogData` at program initiation, +which will contain the default settings provided by the system. Each time the user calls up either the :ref:`PrintDialog` or the +:ref:`PageSetupDialog`, you pass these data structures to initialize the dialog values and to be updated by the dialog. +The framework then queries these data structures to get information like the printed page range (from the :ref:`PrintDialogData`) or +the paper size and/or page orientation (from the :ref:`PageSetupDialogData`). diff --git a/docs/sphinx/rest_substitutions/overviews/refcount_overview.rst b/docs/sphinx/rest_substitutions/overviews/refcount_overview.rst new file mode 100644 index 00000000..5b937dda --- /dev/null +++ b/docs/sphinx/rest_substitutions/overviews/refcount_overview.rst @@ -0,0 +1,72 @@ +.. include:: headings.inc + + +.. _reference counting: + +================================================= +|phoenix_title| **Reference Counting Overview** +================================================= + + +Why You Shouldn't Care About It +------------------------------- + +Many wxPython objects use a technique known as `reference counting`, also known as `copy on write` (COW). This means that when an +object is assigned to another, no copying really takes place. Only the reference count on the shared object data is incremented +and both objects share the same data (a very fast operation). + +But as soon as one of the two (or more) objects is modified, the data has to be copied because the changes to one of the objects +shouldn't be seen in the others. As data copying only happens when the object is written to, this is known as COW. + +What is important to understand is that all this happens absolutely transparently to the class users and that whether an object +is shared or not is not seen from the outside of the class - in any case, the result of any operation on it is the same. + + +Object Comparison +----------------- + +The ``==`` and ``!=`` operators of the reference counted classes always do a `deep comparison`. This means that the equality operator +will return true if two objects are identical and not only if they share the same data. + + +Note that wxPython follows the STL philosophy: when a comparison operator cannot be implemented efficiently (like for e.g. +:ref:`Image` 's ``==`` operator which would need to compare the entire image's data, pixel-by-pixel), it's not implemented at all. +That's why not all reference counted classes provide comparison operators. + + +Also note that if you only need to do a shallow comparison between two :ref:`Object` derived classes, you should not use the ``==`` +and ``!=`` operators but rather the :meth:`Object.IsSameAs` () function. + + +Object Destruction +------------------ + +When a COW object destructor is called, it may not delete the data: if it's shared, the destructor will just decrement the shared +data's reference count without destroying it. Only when the destructor of the last object owning the data is called, the data is +really destroyed. Just like all other COW-things, this happens transparently to the class users so that you shouldn't care about it. + + +List of Reference Counted Classes +--------------------------------- + +The following classes in wxPython have efficient (i.e. fast) assignment operators and copy constructors since they are reference-counted: + +- :ref:`AcceleratorTable` +- :ref:`animate.Animation` +- :ref:`Bitmap` +- :ref:`Brush` +- :ref:`Cursor` +- :ref:`Font` +- :ref:`GraphicsBrush` +- :ref:`GraphicsContext` +- :ref:`GraphicsFont` +- :ref:`GraphicsMatrix` +- :ref:`GraphicsPath` +- :ref:`GraphicsPen` +- :ref:`Icon` +- :ref:`Image` +- :ref:`Metafile` +- :ref:`Palette` + + +Note that the list above reports the objects which are reference counted in all ports of wxPython; some ports may use this technique also for other classes. diff --git a/docs/sphinx/rest_substitutions/overviews/scrolling_overview.rst b/docs/sphinx/rest_substitutions/overviews/scrolling_overview.rst new file mode 100644 index 00000000..76fb329f --- /dev/null +++ b/docs/sphinx/rest_substitutions/overviews/scrolling_overview.rst @@ -0,0 +1,68 @@ +.. include:: headings.inc + + +.. _scrolled windows: + +================================================= +|phoenix_title| **Scrolled Windows Overview** +================================================= + + +Scrollbars come in various guises in wxWidgets. All windows have the potential to show a vertical scrollbar and/or a horizontal +scrollbar: it is a basic capability of a window. However, in practice, not all windows do make use of scrollbars, such as a +single-line :ref:`TextCtrl`. + +Because any class derived from :ref:`Window` may have scrollbars, there are functions to manipulate the scrollbars and event +handlers to intercept scroll events. But just because a window generates a scroll event, doesn't mean that the window necessarily +handles it and physically scrolls the window. The base class :ref:`Window` in fact doesn't have any default functionality to +handle scroll events. If you created a :ref:`Window` object with scrollbars, and then clicked on the scrollbars, nothing at +all would happen. This is deliberate, because the interpretation of scroll events varies from one window class to another. + +:ref:`ScrolledWindow` is an example of a window that adds functionality to make scrolling really work. It assumes that scrolling +happens in consistent units, not different-sized jumps, and that page size is represented by the visible portion of the window. +It is suited to drawing applications, but perhaps not so suitable for a sophisticated editor in which the amount scrolled may +vary according to the size of text on a given line. For this, you would derive from :ref:`Window` and implement scrolling yourself. +:ref:`grid.Grid` is an example of a class that implements its own scrolling, largely because columns and rows can vary in size. + + +The Scrollbar Model +------------------- + +The function :meth:`Window.SetScrollbar` gives a clue about the way a scrollbar is modeled. This function takes the following arguments: + +=================== =================================== +`orientation` Which scrollbar: ``VERTICAL`` or ``HORIZONTAL``. +`position` The position of the scrollbar in scroll units. +`visible` The size of the visible portion of the scrollbar, in scroll units. +`range` The maximum position of the scrollbar. +`refresh` Whether the scrollbar should be repainted. +=================== =================================== + +`orientation` determines whether we're talking about the built-in horizontal or vertical scrollbar. + +`position` is simply the position of the 'thumb' (the bit you drag to scroll around). It is given in scroll units, and so is +relative to the total range of the scrollbar. + +`visible` gives the number of scroll units that represents the portion of the window currently visible. Normally, a scrollbar is +capable of indicating this visually by showing a different length of thumb. + +`range` is the maximum value of the scrollbar, where zero is the start position. You choose the units that suit you, so if you wanted to display text that has 100 lines, you would set this to 100. Note that this doesn't have to correspond to the number of pixels scrolled - it is up to you how you actually show the contents of the window. + +`refresh` just indicates whether the scrollbar should be repainted immediately or not. + + +An Example +---------- + +Let's say you wish to display 50 lines of text, using the same font. The window is sized so that you can only see 16 lines at a time. You would use:: + + SetScrollbar(wx.VERTICAL, 0, 16, 50) + + +.. note:: Note that with the window at this size, the thumb position can never go above 50 minus 16, or 34. You can determine how many lines + are currently visible by dividing the current view size by the character height in pixels. + +When defining your own scrollbar behaviour, you will always need to recalculate the scrollbar settings when the window size changes. You +could therefore put your scrollbar calculations and `SetScrollbar` call into a function named `AdjustScrollbars`, which can be called +initially and also from your :ref:`SizeEvent` handler function. + diff --git a/docs/sphinx/rest_substitutions/overviews/sizers_overview.rst b/docs/sphinx/rest_substitutions/overviews/sizers_overview.rst new file mode 100644 index 00000000..bd04081f --- /dev/null +++ b/docs/sphinx/rest_substitutions/overviews/sizers_overview.rst @@ -0,0 +1,331 @@ +.. include:: headings.inc + + +.. _sizers overview: + +============================================= +|phoenix_title| **Sizers Overview** +============================================= + + +Sizers, as represented by the :ref:`Sizer` class and its descendants in the wxPython class hierarchy, have become the method of +choice to define the layout of controls in dialogs in wxPython because of their ability to create visually appealing dialogs +independent of the platform, taking into account the differences in size and style of the individual controls. +Editors such as wxDesigner, DialogBlocks, XRCed and wxWorkshop create dialogs based exclusively on sizers, practically forcing +the user to create platform independent layouts without compromises. + +The next section describes and shows what can be done with sizers. The following sections briefly describe how to program with +individual sizer classes. + + +The Idea Behind Sizers +---------------------- + +The layout algorithm used by sizers in wxPython is closely related to layout systems in other GUI toolkits, such as Java's AWT, +the GTK toolkit or the Qt toolkit. It is based upon the idea of individual subwindows reporting their minimal required size and +their ability to get stretched if the size of the parent window has changed. This will most often mean that the programmer does +not set the start-up size of a dialog, the dialog will rather be assigned a sizer and this sizer will be queried about the +recommended size. This sizer in turn will query its children (which can be normal windows, empty space or other sizers) so +that a hierarchy of sizers can be constructed. Note that :ref:`Sizer` does not derive from :ref:`Window` and thus does not +interfere with tab ordering and requires very few resources compared to a real window on screen. + +What makes sizers so well fitted for use in wxPython is the fact that every control reports its own minimal size and the algorithm +can handle differences in font sizes or different window (dialog item) sizes on different platforms without problems. For example, +if the standard font as well as the overall design of Linux/GTK widgets requires more space than on Windows, the initial dialog +size will automatically be bigger on Linux/GTK than on Windows. + +There are currently five different kinds of sizers available in wxPython. Each represents either a certain way to lay out dialog +items in a dialog or it fulfills a special task such as wrapping a static box around a dialog item (or another sizer). These sizers +will be discussed one by one in the text below. For more detailed information on how to use sizers programmatically, please refer +to the section :ref:`Programming with BoxSizer `. + + +Common Features +--------------- + +All sizers are containers, that is, they are used to lay out one dialog item (or several dialog items), which they contain. Such +items are sometimes referred to as the children of the sizer. Independent of how the individual sizers lay out their children, +all children have certain features in common: + +**A minimal size**: This minimal size is usually identical to the initial size of the controls and may either be set explicitly in +the :ref:`Size` field of the control constructor or may be calculated by wxPython, typically by setting the height and/or the width +of the item to -1. Note that only some controls can calculate their size (such as a checkbox) whereas others (such as a listbox) +don't have any natural width or height and thus require an explicit size. Some controls can calculate their height, but not their +width (e.g. a single line text control): + + +.. figure:: _static/images/overviews/overview_sizer_04.png + :align: center + + +| + + +**A border**: The border is just empty space and is used to separate dialog items in a dialog. This border can either be all around, +or at any combination of sides such as only above and below the control. The thickness of this border must be set explicitly, typically +5 points. The following samples show dialogs with only one dialog item (a button) and a border of 0, 5, and 10 pixels around the button: + + +.. figure:: _static/images/overviews/overview_sizer_02.png + :align: center + + +| + + +**An alignment**: Often, a dialog item is given more space than its minimal size plus its border. Depending on what flags are used +for the respective dialog item, the dialog item can be made to fill out the available space entirely, i.e. it will grow to a size +larger than the minimal size, or it will be moved to either the centre of the available space or to either side of the space. The +following sample shows a listbox and three buttons in a horizontal box sizer; one button is centred, one is aligned at the top, one is +aligned at the bottom: + + +.. figure:: _static/images/overviews/overview_sizer_06.png + :align: center + + +| + + +**A stretch factor**: If a sizer contains more than one child and it is offered more space than its children and their borders need, the +question arises how to distribute the surplus space among the children. For this purpose, a stretch factor may be assigned to each child, +where the default value of 0 indicates that the child will not get more space than its requested minimum size. A value of more than zero +is interpreted in relation to the sum of all stretch factors in the children of the respective sizer, i.e. if two children get a stretch +factor of 1, they will get half the extra space each independent of whether one control has a minimal sizer inferior to the other or not. +The following sample shows a dialog with three buttons, the first one has a stretch factor of 1 and thus gets stretched, whereas the other +two buttons have a stretch factor of zero and keep their initial width: + + +.. figure:: _static/images/overviews/overview_sizer_07.png + :align: center + + +| + + +Within wxDesigner, this stretch factor gets set from the `Option` menu. + + +Hiding Controls Using Sizers +---------------------------- + +You can hide controls contained in sizers the same way you would hide any control, using the :meth:`Window.Show` method. However, :ref:`Sizer` +also offers a separate method which can tell the sizer not to consider that control in its size calculations. To hide a window using the +sizer, call :meth:`Sizer.Show`. You must then call `Layout` on the sizer to force an update. + +This is useful when hiding parts of the interface, since you can avoid removing the controls from the sizer and having to add them back later. + +.. note:: This is supported only by :ref:`BoxSizer` and :ref:`FlexGridSizer`. + + + +BoxSizer +^^^^^^^^ + +:ref:`BoxSizer` can lay out its children either vertically or horizontally, depending on what flag is being used in its constructor. +When using a vertical sizer, each child can be centered, aligned to the right or aligned to the left. Correspondingly, when using a +horizontal sizer, each child can be centered, aligned at the bottom or aligned at the top. The stretch factor described in the last +paragraph is used for the main orientation, i.e. when using a horizontal box sizer, the stretch factor determines how much the child can +be stretched horizontally. The following sample shows the same dialog as in the last sample, only the box sizer is a vertical box sizer now: + +.. figure:: _static/images/overviews/overview_sizer_08.png + :align: center + + + +StaticBoxSizer +^^^^^^^^^^^^^^ + +:ref:`StaticBoxSixer` is the same as a :ref:`BoxSizer`, but surrounded by a static box. Here is a sample: + + +.. figure:: _static/images/overviews/overview_sizer_09.png + :align: center + + + +GridSizer +^^^^^^^^^ + +:ref:`GridSizer` is a two-dimensional sizer. All children are given the same size, which is the minimal size required by the biggest +child, in this case the text control in the left bottom border. Either the number of columns or the number or rows is fixed and the grid +sizer will grow in the respectively other orientation if new children are added: + + +.. figure:: _static/images/overviews/overview_sizer_10.png + :align: center + + +For programming information, see :ref:`GridSizer`. + + +FlexGridSizer +^^^^^^^^^^^^^ + +Another two-dimensional sizer derived from :ref:`GridSizer`. The width of each column and the height of each row are calculated individually +according to the minimal requirements from the respectively biggest child. Additionally, columns and rows can be declared to be stretchable +if the sizer is assigned a size different from the one it requested. The following sample shows the same dialog as the one above, but using +a flex grid sizer: + + +.. figure:: _static/images/overviews/overview_sizer_11.png + :align: center + + + +.. _programming with boxsizer: + +Programming with BoxSizer +--------------------------- + +The basic idea behind a :ref:`BoxSizer` is that windows will most often be laid out in rather simple basic geometry, typically in a row or a +column or several hierarchies of either. + +As an example, we will construct a dialog that will contain a text field at the top and two buttons at the bottom. This can be seen as a +top-hierarchy column with the text at the top and buttons at the bottom and a low-hierarchy row with an ``OK`` button to the left and a ``Cancel`` +button to the right. In many cases (particularly dialogs under Unix and normal frames) the main window will be resizable by the user and this +change of size will have to get propagated to its children. In our case, we want the text area to grow with the dialog, whereas the button +shall have a fixed size. In addition, there will be a thin border around all controls to make the dialog look nice and - to make matter worse - the +buttons shall be centred as the width of the dialog changes. + +It is the unique feature of a box sizer, that it can grow in both directions (height and width) but can distribute its growth in the +main direction (horizontal for a row) `unevenly` among its children. In our example case, the vertical sizer is supposed to propagate all its +height changes to only the text area, not to the button area. This is determined by the `proportion` parameter when adding a window (or +another sizer) to a sizer. It is interpreted as a weight factor, i.e. it can be zero, indicating that the window may not be resized at all, +or above zero. If several windows have a value above zero, the value is interpreted relative to the sum of all weight factors of the sizer, +so when adding two windows with a value of 1, they will both get resized equally much and each half as much as the sizer owning them. +Then what do we do when a column sizer changes its width? This behaviour is controlled by `flags` (the second parameter of the `Add()` function): +Zero or no flag indicates that the window will preserve it is original size, ``GROW`` flag (same as ``EXPAND``) forces the window to grow with +the sizer, and ``SHAPED`` flag tells the window to change it is size proportionally, preserving original aspect ratio. When ``GROW`` flag is +not used, the item can be aligned within available space. ``ALIGN_LEFT``, ``ALIGN_TOP``, ``ALIGN_RIGHT``, ``ALIGN_BOTTOM``, ``ALIGN_CENTER_HORIZONTAL`` +and ``ALIGN_CENTER_VERTICAL`` do what they say. ``ALIGN_CENTRE`` (same as ``ALIGN_CENTER``) is defined as +(``ALIGN_CENTER_HORIZONTAL`` | ``ALIGN_CENTER_VERTICAL``). Default alignment is ``ALIGN_LEFT`` | ``ALIGN_TOP``. + +As mentioned above, any window belonging to a sizer may have a border, and it can be specified which of the four sides may have this border, +using the ``TOP``, ``LEFT``, ``RIGHT`` and ``BOTTOM`` constants or ``ALL`` for all directions (and you may also use ``NORTH``, ``WEST`` etc instead). +These flags can be used in combination with the alignment flags above as the second parameter of the `Add()` method using the binary or operator ``|``. +The sizer of the border also must be made known, and it is the third parameter in the `Add()` method. This means, that the entire behaviour of a +sizer and its children can be controlled by the three parameters of the `Add()` method. + +Example:: + + # We want to get a dialog that is stretchable because it + # has a text ctrl at the top and two buttons at the bottom. + + class MyDialog(wx.Dialog): + + def __init__(self, parent, id, title): + + wx.Dialog(parent, id, title, wx.DefaultPosition, wx.DefaultSize, + wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER) + + topsizer = wx.BoxSizer(wx.VERTICAL) + + # create text ctrl with minimal size 100x60 + topsizer.Add( + wx.TextCtrl(self, -1, "My text.", wx.DefaultPosition, wx.Size(100,60), wx.TE_MULTILINE), + 1, # make vertically stretchable + wx.EXPAND | # make horizontally stretchable + wx.ALL, # and make border all around + 10) # set border width to 10 + + button_sizer = wx.BoxSizer(wx.HORIZONTAL) + button_sizer.Add( + wx.Button(self, wx.ID_OK, "OK"), + 0, # make horizontally unstretchable + wx.ALL, # make border all around (implicit top alignment) + 10) # set border width to 10 + button_sizer.Add( + wx.Button(self, wx.ID_CANCEL, "Cancel"), + 0, # make horizontally unstretchable + wx.ALL, # make border all around (implicit top alignment) + 10) # set border width to 10 + + topsizer.Add( + button_sizer, + 0, # make vertically unstretchable + wx.ALIGN_CENTER) # no border and centre horizontally + + self.SetSizerAndFit(topsizer) # use the sizer for layout and size window + # accordingly and prevent it from being resized + # to smaller size + + + +Note that the new way of specifying flags to :ref:`Sizer` is via :ref:`SizerFlags`. This class greatly eases the burden of passing flags to a :ref:`Sizer`. + +Here's how you'd do the previous example with :ref:`SizerFlags`:: + + + # We want to get a dialog that is stretchable because it + # has a text ctrl at the top and two buttons at the bottom. + + class MyDialog(wx.Dialog): + + def __init__(self, parent, id, title): + + wx.Dialog(parent, id, title, wx.DefaultPosition, wx.DefaultSize, + wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER) + + topsizer = wx.BoxSizer(wx.VERTICAL) + + # create text ctrl with minimal size 100x60 + topsizer.Add( + wx.TextCtrl(self, -1, "My text.", wx.DefaultPosition, wx.Size(100,60), wx.TE_MULTILINE), + wx.SizerFlags(1).Align().Expand().Border(wx.ALL, 10)) + + button_sizer = wx.BoxSizer(wx.HORIZONTAL) + button_sizer.Add( + wx.Button(self, wx.ID_OK, "OK"), + wx.SizerFlags(0).Align().Border(wx.ALL, 10)) + + button_sizer.Add( + wx.Button(self, wx.ID_CANCEL, "Cancel"), + wx.SizerFlags(0).Align().Border(wx.ALL, 10)) + + topsizer.Add( + button_sizer, + wx.SizerFlags(0).Center()) + + self.SetSizerAndFit(topsizer) # use the sizer for layout and set size and hints + + + +Other Types of Sizers +--------------------- + +:ref:`GridSizer` is a sizer which lays out its children in a two-dimensional table with all table fields having the same size, i.e. +the width of each field is the width of the widest child, the height of each field is the height of the tallest child. + +:ref:`FlexGridSizer` is a sizer which lays out its children in a two-dimensional table with all table fields in one row having the +same height and all fields in one column having the same width, but all rows or all columns are not necessarily the same height or +width as in the :ref:`GridSizer`. + +:ref:`StaticBoxSizer` is a sizer derived from :ref:`BoxSizer` but adds a static box around the sizer. Note that this static box +has to be created separately. + +:ref:`GridBagSizer` is a rather special kind of sizer which, unlike the other classes, allows to directly put the elements at the +given position in the sizer. Please see its documentation for more details. + + +CreateButtonSizer +----------------- + +As a convenience, :meth:`Dialog.CreateButtonSizer` (flags) can be used to create a standard button sizer in which standard buttons +are displayed. The following flags can be passed to this method:: + + wx.YES_NO # Add Yes/No subpanel + wx.YES # return wx.ID_YES + wx.NO # return wx.ID_NO + wx.NO_DEFAULT # make the wx.NO button the default, + # otherwise wx.YES or wx.OK button will be default + + wx.OK # return wx.ID_OK + wx.CANCEL # return wx.ID_CANCEL + wx.HELP # return wx.ID_HELP + + wx.FORWARD # return wx.ID_FORWARD + wx.BACKWARD # return wx.ID_BACKWARD + wx.SETUP # return wx.ID_SETUP + wx.MORE # return wx.ID_MORE + diff --git a/docs/sphinx/rest_substitutions/overviews/splitterwindow_overview.rst b/docs/sphinx/rest_substitutions/overviews/splitterwindow_overview.rst new file mode 100644 index 00000000..e7e1ff2e --- /dev/null +++ b/docs/sphinx/rest_substitutions/overviews/splitterwindow_overview.rst @@ -0,0 +1,69 @@ +.. include:: headings.inc + + +.. _splitterwindow overview: + +================================================= +|phoenix_title| **Splitter Windows Overview** +================================================= + + +The following screenshot shows the appearance of a splitter window with a horizontal split. + +The style ``SP_3D`` has been used to show a 3D border and 3D sash. + +.. figure:: _static/images/overviews/overview_splitter_3d.png + :align: center + + + +Example +------- + +The following fragment shows how to create a splitter window, creating two subwindows and hiding one of them:: + + splitter = wx.SplitterWindow(self, -1, wx.Point(0, 0), + wx.Size(400, 400), wx.SP_3D) + + leftWindow = MyWindow(splitter) + leftWindow.SetScrollbars(20, 20, 50, 50) + + rightWindow = MyWindow(splitter) + rightWindow.SetScrollbars(20, 20, 50, 50) + rightWindow.Show(False) + + splitter.Initialize(leftWindow) + + # Set this to prevent unsplitting + # splitter.SetMinimumPaneSize(20) + + +The next fragment shows how the splitter window can be manipulated after creation:: + + def OnSplitVertical(self, event): + + if splitter.IsSplit(): + splitter.Unsplit() + + leftWindow.Show(True) + rightWindow.Show(True) + splitter.SplitVertically(leftWindow, rightWindow) + + + def OnSplitHorizontal(self, event): + + if splitter.IsSplit(): + splitter.Unsplit() + + leftWindow.Show(True) + rightWindow.Show(True) + splitter.SplitHorizontally(leftWindow, rightWindow) + + + def OnUnsplit(self, event): + + if splitter.IsSplit(): + splitter.Unsplit() + + + diff --git a/docs/sphinx/rest_substitutions/overviews/standard_event_identifiers.rst b/docs/sphinx/rest_substitutions/overviews/standard_event_identifiers.rst new file mode 100644 index 00000000..3b90402d --- /dev/null +++ b/docs/sphinx/rest_substitutions/overviews/standard_event_identifiers.rst @@ -0,0 +1,24 @@ +.. include:: headings.inc + + +.. _standard event identifiers: + +=============================================== +|phoenix_title| **Standard event identifiers** +=============================================== + +wxPython defines a special identifier value ``ID_ANY`` (-1) which is used in the following two situations: + +- When creating a new window you may specify ``ID_ANY`` to let wxPython assign an unused identifier to it automatically +- When installing an event handler using :meth:`EvtHandler.Bind`, you may use it to indicate that you want to handle + the events coming from any control, regardless of its identifier + + +Another standard special identifier value is ``ID_NONE``: this is a value which is not matched by any other id. + +wxPython also defines a few standard command identifiers which may be used by the user code and also are sometimes +used by wxPython itself. These reserved identifiers are all in the range between ``ID_LOWEST`` and ``ID_HIGHEST`` and, +accordingly, the user code should avoid defining its own constants in this range (e.g. by using :func:`NewId` ()). + +Refer to :ref:`the list of stock items ` for the subset of standard IDs which are stock IDs as well. + diff --git a/docs/sphinx/rest_substitutions/overviews/stock_items.rst b/docs/sphinx/rest_substitutions/overviews/stock_items.rst new file mode 100644 index 00000000..ec2f5ab3 --- /dev/null +++ b/docs/sphinx/rest_substitutions/overviews/stock_items.rst @@ -0,0 +1,240 @@ +.. include:: headings.inc + + +.. _stock items: + +=============================================== +|phoenix_title| **Stock items** +=============================================== + +The following is the list of the window IDs for which stock buttons and menu items are created. + +See the :ref:`Button` constructor and the :ref:`MenuItem` constructor for classes which automatically +add stock bitmaps when using stock IDs. Also note that you can retrieve stock bitmaps using :ref:`ArtProvider`. + + ++--------------------------------------+----------------------------------------------------------------------+--------------------------+ +| Stock ID | GTK Icon | Stock label | ++======================================+======================================================================+==========================+ +| ``ID_ABOUT`` | .. figure:: _static/images/stock/gtk-about.png | &About... | +| | :align: left | | ++--------------------------------------+----------------------------------------------------------------------+--------------------------+ +| ``ID_ADD`` | .. figure:: _static/images/stock/gtk-add.png | Add | +| | :align: left | | ++--------------------------------------+----------------------------------------------------------------------+--------------------------+ +| ``ID_APPLY`` | .. figure:: _static/images/stock/gtk-apply.png | &Apply | +| | :align: left | | ++--------------------------------------+----------------------------------------------------------------------+--------------------------+ +| ``ID_BACKWARD`` | .. figure:: _static/images/stock/gtk-go-back-ltr.png | &Back | +| | :align: left | | ++--------------------------------------+----------------------------------------------------------------------+--------------------------+ +| ``ID_BOLD`` | .. figure:: _static/images/stock/gtk-bold.png | &Bold | +| | :align: left | | ++--------------------------------------+----------------------------------------------------------------------+--------------------------+ +| ``ID_BOTTOM`` | .. figure:: _static/images/stock/gtk-goto-bottom.png | &Bottom | +| | :align: left | | ++--------------------------------------+----------------------------------------------------------------------+--------------------------+ +| ``ID_CANCEL`` | .. figure:: _static/images/stock/gtk-cancel.png | &Cancel | +| | :align: left | | ++--------------------------------------+----------------------------------------------------------------------+--------------------------+ +| ``ID_CDROM`` | .. figure:: _static/images/stock/gtk-cdrom.png | &CD-Rom | +| | :align: left | | ++--------------------------------------+----------------------------------------------------------------------+--------------------------+ +| ``ID_CLEAR`` | .. figure:: _static/images/stock/gtk-clear.png | &Clear | +| | :align: left | | ++--------------------------------------+----------------------------------------------------------------------+--------------------------+ +| ``ID_CLOSE`` | .. figure:: _static/images/stock/gtk-close.png | &Close | +| | :align: left | | ++--------------------------------------+----------------------------------------------------------------------+--------------------------+ +| ``ID_CONVERT`` | .. figure:: _static/images/stock/gtk-convert.png | &Convert | +| | :align: left | | ++--------------------------------------+----------------------------------------------------------------------+--------------------------+ +| ``ID_COPY`` | .. figure:: _static/images/stock/gtk-copy.png | &Copy | +| | :align: left | | ++--------------------------------------+----------------------------------------------------------------------+--------------------------+ +| ``ID_CUT`` | .. figure:: _static/images/stock/gtk-cut.png | Cu&t | +| | :align: left | | ++--------------------------------------+----------------------------------------------------------------------+--------------------------+ +| ``ID_DELETE`` | .. figure:: _static/images/stock/gtk-delete.png | &Delete | +| | :align: left | | ++--------------------------------------+----------------------------------------------------------------------+--------------------------+ +| ``ID_DOWN`` | .. figure:: _static/images/stock/gtk-go-down.png | &Down | +| | :align: left | | ++--------------------------------------+----------------------------------------------------------------------+--------------------------+ +| ``ID_EDIT`` | .. figure:: _static/images/stock/gtk-edit.png | &Edit | +| | :align: left | | ++--------------------------------------+----------------------------------------------------------------------+--------------------------+ +| ``ID_EXECUTE`` | .. figure:: _static/images/stock/gtk-execute.png | &Execute | +| | :align: left | | ++--------------------------------------+----------------------------------------------------------------------+--------------------------+ +| ``ID_EXIT`` | .. figure:: _static/images/stock/gtk-quit.png | &Quit | +| | :align: left | | ++--------------------------------------+----------------------------------------------------------------------+--------------------------+ +| ``ID_FILE`` | .. figure:: _static/images/stock/gtk-file.png | &File | +| | :align: left | | ++--------------------------------------+----------------------------------------------------------------------+--------------------------+ +| ``ID_FIND`` | .. figure:: _static/images/stock/gtk-find.png | &Find | +| | :align: left | | ++--------------------------------------+----------------------------------------------------------------------+--------------------------+ +| ``ID_FIRST`` | .. figure:: _static/images/stock/gtk-goto-first-ltr.png | &First | +| | :align: left | | ++--------------------------------------+----------------------------------------------------------------------+--------------------------+ +| ``ID_FLOPPY`` | .. figure:: _static/images/stock/gtk-floppy.png | &Floppy | +| | :align: left | | ++--------------------------------------+----------------------------------------------------------------------+--------------------------+ +| ``ID_FORWARD`` | .. figure:: _static/images/stock/gtk-go-forward-ltr.png | &Forward | +| | :align: left | | ++--------------------------------------+----------------------------------------------------------------------+--------------------------+ +| ``ID_HARDDISK`` | .. figure:: _static/images/stock/gtk-harddisk.png | &Harddisk | +| | :align: left | | ++--------------------------------------+----------------------------------------------------------------------+--------------------------+ +| ``ID_HELP`` | .. figure:: _static/images/stock/gtk-help.png | &Help | +| | :align: left | | ++--------------------------------------+----------------------------------------------------------------------+--------------------------+ +| ``ID_HOME`` | .. figure:: _static/images/stock/gtk-home.png | &Home | +| | :align: left | | ++--------------------------------------+----------------------------------------------------------------------+--------------------------+ +| ``ID_INDENT`` | .. figure:: _static/images/stock/gtk-indent-ltr.png | Indent | +| | :align: left | | ++--------------------------------------+----------------------------------------------------------------------+--------------------------+ +| ``ID_INDEX`` | .. figure:: _static/images/stock/gtk-index.png | &Index | +| | :align: left | | ++--------------------------------------+----------------------------------------------------------------------+--------------------------+ +| ``ID_INFO`` | .. figure:: _static/images/stock/gtk-info.png | &Info | +| | :align: left | | ++--------------------------------------+----------------------------------------------------------------------+--------------------------+ +| ``ID_ITALIC`` | .. figure:: _static/images/stock/gtk-italic.png | &Italic | +| | :align: left | | ++--------------------------------------+----------------------------------------------------------------------+--------------------------+ +| ``ID_JUMP_TO`` | .. figure:: _static/images/stock/gtk-jump-to-ltr.png | &Jump to | +| | :align: left | | ++--------------------------------------+----------------------------------------------------------------------+--------------------------+ +| ``ID_JUSTIFY_CENTER`` | .. figure:: _static/images/stock/gtk-justify-center.png | Centered | +| | :align: left | | ++--------------------------------------+----------------------------------------------------------------------+--------------------------+ +| ``ID_JUSTIFY_FILL`` | .. figure:: _static/images/stock/gtk-justify-fill.png | Justified | +| | :align: left | | ++--------------------------------------+----------------------------------------------------------------------+--------------------------+ +| ``ID_JUSTIFY_LEFT`` | .. figure:: _static/images/stock/gtk-justify-left.png | Align Left | +| | :align: left | | ++--------------------------------------+----------------------------------------------------------------------+--------------------------+ +| ``ID_JUSTIFY_RIGHT`` | .. figure:: _static/images/stock/gtk-justify-right.png | Align Right | +| | :align: left | | ++--------------------------------------+----------------------------------------------------------------------+--------------------------+ +| ``ID_LAST`` | .. figure:: _static/images/stock/gtk-goto-last-ltr.png | &Last | +| | :align: left | | ++--------------------------------------+----------------------------------------------------------------------+--------------------------+ +| ``ID_NETWORK`` | .. figure:: _static/images/stock/gtk-network.png | &Network | +| | :align: left | | ++--------------------------------------+----------------------------------------------------------------------+--------------------------+ +| ``ID_NEW`` | .. figure:: _static/images/stock/gtk-new.png | &New | +| | :align: left | | ++--------------------------------------+----------------------------------------------------------------------+--------------------------+ +| ``ID_NO`` | .. figure:: _static/images/stock/gtk-no.png | &No | +| | :align: left | | ++--------------------------------------+----------------------------------------------------------------------+--------------------------+ +| ``ID_OK`` | .. figure:: _static/images/stock/gtk-ok.png | &OK | +| | :align: left | | ++--------------------------------------+----------------------------------------------------------------------+--------------------------+ +| ``ID_OPEN`` | .. figure:: _static/images/stock/gtk-open.png | &Open... | +| | :align: left | | ++--------------------------------------+----------------------------------------------------------------------+--------------------------+ +| ``ID_PASTE`` | .. figure:: _static/images/stock/gtk-paste.png | &Paste | +| | :align: left | | ++--------------------------------------+----------------------------------------------------------------------+--------------------------+ +| ``ID_PREFERENCES`` | .. figure:: _static/images/stock/gtk-preferences.png | &Preferences | +| | :align: left | | ++--------------------------------------+----------------------------------------------------------------------+--------------------------+ +| ``ID_PREVIEW`` | .. figure:: _static/images/stock/gtk-print-preview.png | Print previe&w | +| | :align: left | | ++--------------------------------------+----------------------------------------------------------------------+--------------------------+ +| ``ID_PRINT`` | .. figure:: _static/images/stock/gtk-print.png | &Print... | +| | :align: left | | ++--------------------------------------+----------------------------------------------------------------------+--------------------------+ +| ``ID_PROPERTIES`` | .. figure:: _static/images/stock/gtk-properties.png | &Properties | +| | :align: left | | ++--------------------------------------+----------------------------------------------------------------------+--------------------------+ +| ``ID_REDO`` | .. figure:: _static/images/stock/gtk-redo-ltr.png | &Redo | +| | :align: left | | ++--------------------------------------+----------------------------------------------------------------------+--------------------------+ +| ``ID_REFRESH`` | .. figure:: _static/images/stock/gtk-refresh.png | Refresh | +| | :align: left | | ++--------------------------------------+----------------------------------------------------------------------+--------------------------+ +| ``ID_REMOVE`` | .. figure:: _static/images/stock/gtk-remove.png | Remove | +| | :align: left | | ++--------------------------------------+----------------------------------------------------------------------+--------------------------+ +| ``ID_REPLACE`` | .. figure:: _static/images/stock/gtk-find-and-replace.png | Rep&lace | +| | :align: left | | ++--------------------------------------+----------------------------------------------------------------------+--------------------------+ +| ``ID_REVERT_TO_SAVED`` | .. figure:: _static/images/stock/gtk-revert-to-saved-ltr.png | Revert to Saved | +| | :align: left | | ++--------------------------------------+----------------------------------------------------------------------+--------------------------+ +| ``ID_SAVE`` | .. figure:: _static/images/stock/gtk-save.png | &Save | +| | :align: left | | ++--------------------------------------+----------------------------------------------------------------------+--------------------------+ +| ``ID_SAVEAS`` | .. figure:: _static/images/stock/gtk-save-as.png | Save &As... | +| | :align: left | | ++--------------------------------------+----------------------------------------------------------------------+--------------------------+ +| ``ID_SELECTALL`` | .. figure:: _static/images/stock/gtk-select-all.png | Select &All | +| | :align: left | | ++--------------------------------------+----------------------------------------------------------------------+--------------------------+ +| ``ID_SELECT_COLOR`` | .. figure:: _static/images/stock/gtk-select-color.png | &Color | +| | :align: left | | ++--------------------------------------+----------------------------------------------------------------------+--------------------------+ +| ``ID_SELECT_FONT`` | .. figure:: _static/images/stock/gtk-select-font.png | &Font | +| | :align: left | | ++--------------------------------------+----------------------------------------------------------------------+--------------------------+ +| ``ID_SORT_ASCENDING`` | .. figure:: _static/images/stock/gtk-sort-ascending.png | &Ascending | +| | :align: left | | ++--------------------------------------+----------------------------------------------------------------------+--------------------------+ +| ``ID_SORT_DESCENDING`` | .. figure:: _static/images/stock/gtk-sort-descending.png | &Descending | +| | :align: left | | ++--------------------------------------+----------------------------------------------------------------------+--------------------------+ +| ``ID_SPELL_CHECK`` | .. figure:: _static/images/stock/gtk-spell-check.png | &Spell Check | +| | :align: left | | ++--------------------------------------+----------------------------------------------------------------------+--------------------------+ +| ``ID_STOP`` | .. figure:: _static/images/stock/gtk-stop.png | &Stop | +| | :align: left | | ++--------------------------------------+----------------------------------------------------------------------+--------------------------+ +| ``ID_STRIKETHROUGH`` | .. figure:: _static/images/stock/gtk-strikethrough.png | &Strikethrough | +| | :align: left | | ++--------------------------------------+----------------------------------------------------------------------+--------------------------+ +| ``ID_TOP`` | .. figure:: _static/images/stock/gtk-goto-top.png | &Top | +| | :align: left | | ++--------------------------------------+----------------------------------------------------------------------+--------------------------+ +| ``ID_UNDELETE`` | .. figure:: _static/images/stock/gtk-undelete-ltr.png | Undelete | +| | :align: left | | ++--------------------------------------+----------------------------------------------------------------------+--------------------------+ +| ``ID_UNDERLINE`` | .. figure:: _static/images/stock/gtk-underline.png | &Underline | +| | :align: left | | ++--------------------------------------+----------------------------------------------------------------------+--------------------------+ +| ``ID_UNDO`` | .. figure:: _static/images/stock/gtk-undo-ltr.png | &Undo | +| | :align: left | | ++--------------------------------------+----------------------------------------------------------------------+--------------------------+ +| ``ID_UNINDENT`` | .. figure:: _static/images/stock/gtk-unindent-ltr.png | &Unindent | +| | :align: left | | ++--------------------------------------+----------------------------------------------------------------------+--------------------------+ +| ``ID_UP`` | .. figure:: _static/images/stock/gtk-go-up.png | &Up | +| | :align: left | | ++--------------------------------------+----------------------------------------------------------------------+--------------------------+ +| ``ID_YES`` | .. figure:: _static/images/stock/gtk-yes.png | &Yes | +| | :align: left | | ++--------------------------------------+----------------------------------------------------------------------+--------------------------+ +| ``ID_ZOOM_100`` | .. figure:: _static/images/stock/gtk-zoom-100.png | &Actual Size | +| | :align: left | | ++--------------------------------------+----------------------------------------------------------------------+--------------------------+ +| ``ID_ZOOM_FIT`` | .. figure:: _static/images/stock/gtk-zoom-fit.png | Zoom to &Fit | +| | :align: left | | ++--------------------------------------+----------------------------------------------------------------------+--------------------------+ +| ``ID_ZOOM_IN`` | .. figure:: _static/images/stock/gtk-zoom-in.png | Zoom &In | +| | :align: left | | ++--------------------------------------+----------------------------------------------------------------------+--------------------------+ +| ``ID_ZOOM_OUT`` | .. figure:: _static/images/stock/gtk-zoom-out.png | Zoom &Out | +| | :align: left | | ++--------------------------------------+----------------------------------------------------------------------+--------------------------+ + + +| + +.. note:: Note that some of the IDs listed above also have a stock accelerator and an associated help string. + diff --git a/docs/sphinx/rest_substitutions/overviews/validator_overview.rst b/docs/sphinx/rest_substitutions/overviews/validator_overview.rst new file mode 100644 index 00000000..cc024508 --- /dev/null +++ b/docs/sphinx/rest_substitutions/overviews/validator_overview.rst @@ -0,0 +1,108 @@ +.. include:: headings.inc + + +.. _validator overview: + +======================================= +|phoenix_title| **Validator Overview** +======================================= + + +.. _validator basic concepts: + +Validator basic concepts +------------------------ + +The aim of the validator concept is to make dialogs very much easier to write. A validator is an object that can be +plugged into a control (such as a :ref:`TextCtrl`), and mediates between Python data and the control, transferring +the data in either direction and validating it. It also is able to intercept events generated by the control, providing +filtering behaviour without the need to derive a new control class. + +:ref:`Validator` can also be used to intercept keystrokes and other events within an input field. To use a validator, +you have to create your own sub-class of :ref:`Validator` (neither `TextValidator` nor `GenericValidator` are implemented +in wxPython). This sub-class is then associated with your input field by calling:: + + myInputField.SetValidator(myValidator) + + +.. note:: Your :ref:`Validator` sub-class must implement the :meth:`Validator.Clone` method. + + +.. note:: + + Note that any :ref:`Window` may have a validator; using the ``WS_EX_VALIDATE_RECURSIVELY`` style (see + :ref:`Window extended styles `) you can also implement recursive validation. + + + +.. _anatomy of a validator: + +Anatomy of a Validator +---------------------- + +A programmer creating a new validator class should provide the following functionality. + +A validator constructor is responsible for allowing the programmer to specify the kind of validation required, and perhaps +a pointer to a Python variable that is used for storing the data for the control. If such a variable address is not supplied +by the user, then the validator should store the data internally. + +The :meth:`Validator.Validate` method should return true if the data in the control (not the Python variable) is valid. +It should also show an appropriate message if data was not valid. + +The :meth:`Validator.TransferToWindow` member function should transfer the data from the validator or associated Python +variable to the control. + +The :meth:`Validator.TransferFromWindow` member function should transfer the data from the control to the validator or +associated Python variable. + +There should be a copy constructor, and a :meth:`Validator.Clone` function which returns a copy of the validator object. +This is important because validators are passed by reference to window constructors, and must therefore be cloned internally. + +You can optionally define event handlers for the validator, to implement filtering. These handlers will capture events before +the control itself does (see :ref:`How Events are Processed `). + + + +.. _how validators interact with dialogs: + +How Validators Interact with Dialogs +------------------------------------ + + +For validators to work correctly, validator functions must be called at the right times during dialog initialisation and dismissal. + +When a :meth:`Dialog.Show` is called (for a modeless dialog) or :meth:`Dialog.ShowModal` is called (for a modal dialog), +the function :meth:`Window.InitDialog` is automatically called. This in turn sends an initialisation event to the dialog. The +default handler for the ``wxEVT_INIT_DIALOG`` event is defined in the :ref:`Window` class to simply call the function +:meth:`Window.TransferDataToWindow`. This function finds all the validators in the window's children and calls the +:meth:`Validator.TransferToWindow` function for each. Thus, data is transferred from Python variables to the dialog just as the +dialog is being shown. + +.. note:: If you are using a window or panel instead of a dialog, you will need to call :meth:`Window.InitDialog` explicitly before + showing the window. + + +When the user clicks on a button, for example the ``OK`` button, the application should first call :meth:`Window.Validate`, which +returns ``False`` if any of the child window validators failed to validate the window data. The button handler should return +immediately if validation failed. Secondly, the application should call :meth:`Window.TransferDataFromWindow` and return if this failed. +It is then safe to end the dialog by calling :meth:`Dialog.EndModal` (if modal) or :meth:`Dialog.Show` (if modeless). + +In fact, :ref:`Dialog` contains a default command event handler for the ``ID_OK`` button. It goes like this:: + + def OnOK(self, event): + + if self.Validate() and self.TransferDataFromWindow(): + + if self.IsModal(): + self.EndModal(wx.ID_OK) + else: + self.SetReturnCode(wx.ID_OK) + self.Show(False) + + + +So if using validators and a normal ``OK`` button, you may not even need to write any code for handling dialog dismissal. + +If you load your dialog from a resource file, you will need to iterate through the controls setting validators, since validators +can't be specified in a dialog resource. + diff --git a/docs/sphinx/rest_substitutions/overviews/window_deletion_overview.rst b/docs/sphinx/rest_substitutions/overviews/window_deletion_overview.rst new file mode 100644 index 00000000..b0c2cbf8 --- /dev/null +++ b/docs/sphinx/rest_substitutions/overviews/window_deletion_overview.rst @@ -0,0 +1,95 @@ +.. include:: headings.inc + + +.. _window deletion: + +============================================= +|phoenix_title| **Window Deletion Overview** +============================================= + + +Window deletion can be a confusing subject, so this overview is provided to help make it clear when and +how you delete windows, or respond to user requests to close windows. + + + +Sequence of Events During Window Deletion +----------------------------------------- + +When the user clicks on the system close button or system close command, in a frame or a dialog, wxPython calls :meth:`Window.Close`. +This in turn generates an ``EVT_CLOSE`` event: see :ref:`CloseEvent`. + +It is the duty of the application to define a suitable event handler, and decide whether or not to destroy the window. If the +application is for some reason forcing the application to close (:meth:`CloseEvent.CanVeto` returns ``False``), the window should +always be destroyed, otherwise there is the option to ignore the request, or maybe wait until the user has answered a question +before deciding whether it is safe to close. The handler for ``EVT_CLOSE`` should signal to the calling code if it does not destroy +the window, by calling :meth:`CloseEvent.Veto`. Calling this provides useful information to the calling code. + +The :ref:`CloseEvent` handler should only call :meth:`Window.Destroy` to delete the window, and not use the `del` operator. This +is because for some window classes, wxPython delays actual deletion of the window until all events have been processed, since otherwise +there is the danger that events will be sent to a non-existent window. + +As reinforced in the next section, calling `Close` does not guarantee that the window will be destroyed. Call :meth:`Window.Destroy` +if you want to be certain that the window is destroyed. + + + +Closing Windows +--------------- + +Your application can either use :meth:`Window.Close` event just as the framework does, or it can call :meth:`Window.Destroy` directly. +If using `Close()`, you can pass a ``True`` argument to this function to tell the event handler that we definitely want to delete +the frame and it cannot be vetoed. + +The advantage of using `Close` instead of `Destroy` is that it will call any clean-up code defined by the ``EVT_CLOSE`` handler; for +example it may close a document contained in a window after first asking the user whether the work should be saved. `Close` can be +vetoed by this process (return ``False``), whereas `Destroy` definitely destroys the window. + + + +Default Window Close Behaviour +------------------------------ + +The default close event handler for :ref:`Dialog` simulates a ``Cancel`` command, generating a ``ID_CANCEL`` event. Since the handler +for this cancel event might itself call `Close`, there is a check for infinite looping. The default handler for ``ID_CANCEL`` hides +the dialog (if modeless) or calls `EndModal(ID_CANCEL)` (if modal). In other words, by default, the dialog is not destroyed. + +The default close event handler for :ref:`Frame` destroys the frame using `Destroy()`. + + + +User Calls to Exit From a Menu +------------------------------ + +What should I do when the user calls up `Exit` from a menu? You can simply call :meth:`Window.Close` on the frame. This will invoke +your own close event handler which may destroy the frame. + +You can do checking to see if your application can be safely exited at this point, either from within your close event handler, or +from within your exit menu command handler. For example, you may wish to check that all files have been saved. Give the user a chance +to save and quit, to not save but quit anyway, or to cancel the exit command altogether. + + + +Exiting the Application Gracefully +---------------------------------- + +A wxPython application automatically exits when the last top level window (:ref:`Frame` or :ref:`Dialog`), is destroyed. Put any +application-wide cleanup code in :meth:`AppConsole.OnExit` (this is a method, not an event handler). + + + +Automatic Deletion of Child Windows +----------------------------------- + +Child windows are deleted from within the parent destructor. This includes any children that are themselves frames or dialogs, so you +may wish to close these child frame or dialog windows explicitly from within the parent close handler. + + + +Other Kinds of Windows +---------------------- + +So far we've been talking about 'managed' windows, i.e. frames and dialogs. Windows with parents, such as controls, don't have delayed +destruction and don't usually have close event handlers, though you can implement them if you wish. For consistency, continue to use +the :meth:`Window.Destroy` method instead of the `del` operator when deleting these kinds of windows explicitly. + diff --git a/docs/sphinx/rest_substitutions/overviews/window_ids_overview.rst b/docs/sphinx/rest_substitutions/overviews/window_ids_overview.rst new file mode 100644 index 00000000..22cfc636 --- /dev/null +++ b/docs/sphinx/rest_substitutions/overviews/window_ids_overview.rst @@ -0,0 +1,30 @@ +.. include:: headings.inc + + +.. _window ids: + +================================================= +|phoenix_title| **Window IDs Overview** +================================================= + + +Various controls and other parts of wxPython need an ID. Sometimes the ID may be directly provided by the user or +have a predefined value, such as ``ID_OPEN``. Often, however, the value of the ID is unimportant and is created +automatically by calling :meth:`Window.NewControlId` or by passing ``ID_ANY`` as the ID of an object. + +There are two ways to generate an ID. One way is to start at a negative number, and for each new ID, return the +next smallest number. This is fine for systems that can use the full range of negative numbers for IDs, as +this provides more than enough IDs and it would take a very very long time to run out and wrap around. +However, some systems cannot use the full range of the ID value. Windows, for example, can only use 16 bit +IDs, and only has about 32000 possible automatic IDs that can be generated by :meth:`Window.NewControlId`. +If the program runs long enough, depending on the program itself, using this first method would cause the IDs +to wrap around into the positive ID range and cause possible clashes with any directly specified ID values. + +The other way is to keep track of the IDs returned by :meth:`Window.NewControlId` and don't return them again +until the ID is completely free and not being used by any other objects. This will make sure that the ID values +do not clash with one another. This is accomplished by keeping a reference count for each of the IDs that can +possibly be returned by :meth:`Window.NewControlId`. Other IDs are not reference counted. + + +.. seealso:: :ref:`IdManager`, :meth:`Window.NewControlId`, :meth:`Window.UnreserveControlId` + diff --git a/docs/sphinx/rest_substitutions/overviews/window_sizing_overview.rst b/docs/sphinx/rest_substitutions/overviews/window_sizing_overview.rst new file mode 100644 index 00000000..c5a6129c --- /dev/null +++ b/docs/sphinx/rest_substitutions/overviews/window_sizing_overview.rst @@ -0,0 +1,70 @@ +.. include:: headings.inc + + +.. _window sizing overview: + +=========================================== +|phoenix_title| **Window Sizing Overview** +=========================================== + + +It can sometimes be confusing to keep track of the various size-related attributes of a :ref:`Window`, how they +relate to each other, and how they interact with sizers. + +This document will attempt to clear the fog a little, and give some simple explanations of things. + +Glossary +-------- + +- **"Best Size"**: the best size of a widget depends on what kind of widget it is, and usually also on the contents of + the widget. For example a :ref:`ListBox` 's best size will be calculated based on how many items it has, up to a + certain limit, or a :ref:`Button` 's best size will be calculated based on its label size, but normally won't be smaller + than the platform default button size (unless a style flag overrides that). There is a special method in the wxPython + window classes called :meth:`Window.DoGetBestSize` that a class needs to override if it wants to calculate its own best + size based on its content. +- **"Minimal Size"**: the minimal size of a widget is a size that is normally explicitly set by the programmer either + with the :meth:`Window.SetMinSize` method or with the :meth:`Window.SetSizeHints` method. Most controls will also set + the minimal size to the size given in the control's constructor if a non-default value is passed. Top-level windows + such as :ref:`Frame` will not allow the user to resize the frame below the minimal size. +- **"Maximum Size"**: just like for the minimal size, the maximum size is normally explicitly set by the programmer with + the :meth:`Window.SetMaxSize` method or with :meth:`Window.SetSizeHints`. Top-level windows such as :ref:`Frame` will + not allow the user to resize the frame above the maximum size. +- **"Size"**: the size of a widget can be explicitly set or fetched with the :meth:`Window.SetSize` or :meth:`Window.GetSize` + methods. This size value is the size that the widget is currently using on screen and is the way to change the size of + something that is not being managed by a sizer. +- **"Client Size"**: the client size represents the widget's area inside of any borders belonging to the widget and is the + area that can be drawn upon in a ``EVT_PAINT`` event. If a widget doesn't have a border then its client size is the + same as its size. +- **"Initial Size"**: the initial size of a widget is the size given to the constructor of the widget, if any. As mentioned + above most controls will also set this size value as the control's minimal size. If the size passed to the constructor is + the default ``DefaultSize``, or if the size is not fully specified (such as `wx.Size(150, -1)`) then most controls will + fill in the missing size components using the best size and will set the initial size of the control to the resulting size. +- **"Virtual Size"**: the virtual size is the size of the potentially viewable area of the widget. The virtual size of a + widget may be larger than its actual size and in this case scrollbars will appear to the let the user 'explore' the full + contents of the widget. See :ref:`Scrolled` for more info. + + + +Functions related to sizing +--------------------------- + +- :meth:`Window.GetEffectiveMinSize`: returns a blending of the widget's minimal size and best size, giving precedence to + the minimal size. For example, if a widget's min size is set to (150, -1) and the best size is (80, 22) then the best + fitting size is (150, 22). If the min size is (50, 20) then the best fitting size is (50, 20). This method is what is + called by the sizers when determining what the requirements of each item in the sizer is, and is used for calculating + the overall minimum needs of the sizer. +- :meth:`Window.SetInitialSize`: this is a little different than the typical size setters. Rather than just setting an + "initial size" attribute it actually sets the minimal size to the value passed in, blends that value with the best size, + and then sets the size of the widget to be the result. So you can consider this method to be a "Smart SetSize". This + method is what is called by the constructor of most controls to set the minimal size and the initial size of the control. +- :meth:`Window.Fit`: this method sets the size of a window to fit around its children. If it has no children then nothing + is done, if it does have children then the size of the window is set to the window's best size. +- :meth:`Sizer.Fit`: this sets the size of the window to be large enough to accommodate the minimum size needed by the sizer, + (along with a few other constraints...). If the sizer is the one that is assigned to the window then this should be + equivalent to :meth:`Window.Fit`. +- :meth:`Sizer.Layout`: recalculates the minimum space needed by each item in the sizer, and then lays out the items + within the space currently allotted to the sizer. +- :meth:`Window.Layout`: if the window has a sizer then it sets the space given to the sizer to the current size of the window, + which results in a call to :meth:`Sizer.Layout`. If the window has layout constraints instead of a sizer then the constraints + algorithm is run. The `Layout()` method is what is called by the default ``EVT_SIZE`` handler for container windows. + diff --git a/docs/sphinx/rest_substitutions/overviews/window_styles_overview.rst b/docs/sphinx/rest_substitutions/overviews/window_styles_overview.rst new file mode 100644 index 00000000..e3ed8b7d --- /dev/null +++ b/docs/sphinx/rest_substitutions/overviews/window_styles_overview.rst @@ -0,0 +1,22 @@ +.. include:: headings.inc + + +.. _window styles: + +================================================= +|phoenix_title| **Window Styles Overview** +================================================= + + +Window styles are used to specify alternative behaviour and appearances for windows, when they are created. + +The symbols are defined in such a way that they can be combined in a 'bit-list' using the Python `bitwise-or` operator (``|``). + +For example:: + + style = wx.CAPTION | wx.MINIMIZE_BOX | wx.MAXIMIZE_BOX | wx.RESIZE_BORDER + + +For the window styles specific to each window class, please see the documentation for the window. + +Most windows can use the generic styles listed for :ref:`Window` in addition to their own styles. diff --git a/docs/sphinx/rest_substitutions/snippets/python/converted/AcceleratorTable.1.py b/docs/sphinx/rest_substitutions/snippets/python/converted/AcceleratorTable.1.py new file mode 100644 index 00000000..6d3cd003 --- /dev/null +++ b/docs/sphinx/rest_substitutions/snippets/python/converted/AcceleratorTable.1.py @@ -0,0 +1,10 @@ + + entries = [wx.AcceleratorEntry() for i in xrange(4)] + + entries[0].Set(wx.ACCEL_CTRL, 'N', ID_NEW_WINDOW) + entries[1].Set(wx.ACCEL_CTRL, 'X', wx.ID_EXIT) + entries[2].Set(wx.ACCEL_SHIFT, 'A', ID_ABOUT) + entries[3].Set(wx.ACCEL_NORMAL, wx.WXK_DELETE, wx.ID_CUT) + + accel = wx.AcceleratorTable(entries) + frame.SetAcceleratorTable(accel) \ No newline at end of file diff --git a/docs/sphinx/rest_substitutions/snippets/python/converted/App.SetTopWindow.1.py b/docs/sphinx/rest_substitutions/snippets/python/converted/App.SetTopWindow.1.py new file mode 100644 index 00000000..5dd00c7e --- /dev/null +++ b/docs/sphinx/rest_substitutions/snippets/python/converted/App.SetTopWindow.1.py @@ -0,0 +1,2 @@ + + wx.App.SetTopWindow(None) diff --git a/docs/sphinx/rest_substitutions/snippets/python/converted/Bitmap.__init__.1.py b/docs/sphinx/rest_substitutions/snippets/python/converted/Bitmap.__init__.1.py new file mode 100644 index 00000000..f39f3787 --- /dev/null +++ b/docs/sphinx/rest_substitutions/snippets/python/converted/Bitmap.__init__.1.py @@ -0,0 +1,3 @@ + + newBitmap = oldBitmap.GetSubBitmap( + wx.Rect(0, 0, oldBitmap.GetWidth(), oldBitmap.GetHeight())) diff --git a/docs/sphinx/rest_substitutions/snippets/python/converted/BoxSizer.AddSpacer.1.py b/docs/sphinx/rest_substitutions/snippets/python/converted/BoxSizer.AddSpacer.1.py new file mode 100644 index 00000000..f4e9389a --- /dev/null +++ b/docs/sphinx/rest_substitutions/snippets/python/converted/BoxSizer.AddSpacer.1.py @@ -0,0 +1,9 @@ + + if boxSizer.IsVertical(): + + boxSizer.Add(0, size, 0) + + else: + + boxSizer.Add(size, 0, 0) + diff --git a/docs/sphinx/rest_substitutions/snippets/python/converted/BusyCursor.1.py b/docs/sphinx/rest_substitutions/snippets/python/converted/BusyCursor.1.py new file mode 100644 index 00000000..52ef7fef --- /dev/null +++ b/docs/sphinx/rest_substitutions/snippets/python/converted/BusyCursor.1.py @@ -0,0 +1,7 @@ + + wait = wx.BusyCursor() + + for i in xrange(10000): + DoACalculation() + + del wait diff --git a/docs/sphinx/rest_substitutions/snippets/python/converted/CloseEvent.1.py b/docs/sphinx/rest_substitutions/snippets/python/converted/CloseEvent.1.py new file mode 100644 index 00000000..3b65b602 --- /dev/null +++ b/docs/sphinx/rest_substitutions/snippets/python/converted/CloseEvent.1.py @@ -0,0 +1,15 @@ + + def OnClose(self, event): + + if event.CanVeto() and self.fileNotSaved: + + if wx.MessageBox("The file has not been saved... continue closing?", + "Please confirm", + wx.ICON_QUESTION | wx.YES_NO) != wx.YES: + + event.Veto() + return + + self.Destroy() # you may also do: event.Skip() + # since the default event handler does call Destroy(), too + diff --git a/docs/sphinx/rest_substitutions/snippets/python/converted/CollapsiblePane.1.py b/docs/sphinx/rest_substitutions/snippets/python/converted/CollapsiblePane.1.py new file mode 100644 index 00000000..578ba92a --- /dev/null +++ b/docs/sphinx/rest_substitutions/snippets/python/converted/CollapsiblePane.1.py @@ -0,0 +1,12 @@ + + collpane = wx.CollapsiblePane(self, wx.ID_ANY, "Details:") + + # add the pane with a zero proportion value to the 'sz' sizer which contains it + sz.Add(collpane, 0, wx.GROW|wx.ALL, 5) + + # now add a test label in the collapsible pane using a sizer to layout it: + win = collpane.GetPane() + paneSz = wx.BoxSizer(wx.VERTICAL) + paneSz.Add(wx.StaticText(win, wx.ID_ANY, "test!"), 1, wx.GROW|wx.ALL, 2) + win.SetSizer(paneSz) + paneSz.SetSizeHints(win) diff --git a/docs/sphinx/rest_substitutions/snippets/python/converted/ConfigBase.1.py b/docs/sphinx/rest_substitutions/snippets/python/converted/ConfigBase.1.py new file mode 100644 index 00000000..764211e7 --- /dev/null +++ b/docs/sphinx/rest_substitutions/snippets/python/converted/ConfigBase.1.py @@ -0,0 +1,14 @@ + + # using wx.Config instead of writing wx.FileConfig or wx.RegConfig enhances + # portability of the code + config = wx.Config("MyAppName") + strs = config.Read("LastPrompt") + + # another example: using default values and the full path instead of just + # key name: if the key is not found , the value 17 is returned + value = config.ReadInt("/LastRun/CalculatedValues/MaxValue", 17) + + # at the end of the program we would save everything back + config.Write("LastPrompt", strs) + config.Write("/LastRun/CalculatedValues/MaxValue", value) + \ No newline at end of file diff --git a/docs/sphinx/rest_substitutions/snippets/python/converted/ConfigBase.2.py b/docs/sphinx/rest_substitutions/snippets/python/converted/ConfigBase.2.py new file mode 100644 index 00000000..c1818b0c --- /dev/null +++ b/docs/sphinx/rest_substitutions/snippets/python/converted/ConfigBase.2.py @@ -0,0 +1,23 @@ + + config = wx.Config("FooBarApp") + + # right now the current path is '/' + conf.Write("RootEntry", 1) + + # go to some other place: if the group(s) don't exist, they will be created + conf.SetPath("/Group/Subgroup") + + # create an entry in subgroup + conf.Write("SubgroupEntry", 3) + + # '..' is understood + conf.Write("../GroupEntry", 2) + conf.SetPath("..") + + if conf.ReadInt("Subgroup/SubgroupEntry", 0) != 3: + raise Exception('Invalid SubgroupEntry') + + # use absolute path: it is allowed, too + if conf.ReadInt("/RootEntry", 0) != 1: + raise Exception('Invalid RootEntry') + diff --git a/docs/sphinx/rest_substitutions/snippets/python/converted/ConfigBase.3.py b/docs/sphinx/rest_substitutions/snippets/python/converted/ConfigBase.3.py new file mode 100644 index 00000000..ed3d7f85 --- /dev/null +++ b/docs/sphinx/rest_substitutions/snippets/python/converted/ConfigBase.3.py @@ -0,0 +1,10 @@ + + def foo(config): + + oldPath = config.GetPath() + + config.SetPath("/Foo/Data") + # ... + + config.SetPath(oldPath) + diff --git a/docs/sphinx/rest_substitutions/snippets/python/converted/ConfigBase.4.py b/docs/sphinx/rest_substitutions/snippets/python/converted/ConfigBase.4.py new file mode 100644 index 00000000..76dadbea --- /dev/null +++ b/docs/sphinx/rest_substitutions/snippets/python/converted/ConfigBase.4.py @@ -0,0 +1,11 @@ + + def bar(config): + + config.Write("Test", 17) + + foo(config) + + # we're reading "/Foo/Data/Test" here! -1 will probably be returned... + if config.ReadInt("Test", -1) != 17: + raise Exception('Invalid Test') + diff --git a/docs/sphinx/rest_substitutions/snippets/python/converted/ConfigBase.5.py b/docs/sphinx/rest_substitutions/snippets/python/converted/ConfigBase.5.py new file mode 100644 index 00000000..3808ea40 --- /dev/null +++ b/docs/sphinx/rest_substitutions/snippets/python/converted/ConfigBase.5.py @@ -0,0 +1,21 @@ + + config = wx.Config("MyAppName") + names = [] + + # first enum all entries + more, value, index = config.GetFirstEntry() + + while more: + names.append(value) + more, value, index = config.GetNextEntry(index) + + # ... we have all entry names in names... + + # now all groups... + more, value, index = config.GetFirstGroup() + + while more: + names.append(value) + more, value, index = config.GetNextGroup(index) + + # ... we have all group (and entry) names in names... diff --git a/docs/sphinx/rest_substitutions/snippets/python/converted/ConfigPathChanger.1.py b/docs/sphinx/rest_substitutions/snippets/python/converted/ConfigPathChanger.1.py new file mode 100644 index 00000000..188d190f --- /dev/null +++ b/docs/sphinx/rest_substitutions/snippets/python/converted/ConfigPathChanger.1.py @@ -0,0 +1,21 @@ + + # this function loads somes settings from the given wx.Config object + # the path selected inside it is left unchanged + def LoadMySettings(config): + + changer = wx.ConfigPathChanger(config, "/Foo/Data/SomeString") + + strs = config.Read("SomeString") + + if not strs: + wx.LogError("Couldn't read SomeString!") + return False + + # NOTE: without wx.ConfigPathChanger it would be easy to forget to + # set the old path back into the wx.Config object before this return! + + + # do something useful with SomeString... + + return True # again: wx.ConfigPathChanger dtor will restore the original wx.Config path + diff --git a/docs/sphinx/rest_substitutions/snippets/python/converted/ConfigPathChanger.__init__.1.py b/docs/sphinx/rest_substitutions/snippets/python/converted/ConfigPathChanger.__init__.1.py new file mode 100644 index 00000000..aef65fb8 --- /dev/null +++ b/docs/sphinx/rest_substitutions/snippets/python/converted/ConfigPathChanger.__init__.1.py @@ -0,0 +1,2 @@ + + wx.ConfigPathChanger(wx.ConfigBase.Get(), "/MyProgram/SomeKeyName") diff --git a/docs/sphinx/rest_substitutions/snippets/python/converted/ConfigPathChanger.__init__.2.py b/docs/sphinx/rest_substitutions/snippets/python/converted/ConfigPathChanger.__init__.2.py new file mode 100644 index 00000000..826fcabe --- /dev/null +++ b/docs/sphinx/rest_substitutions/snippets/python/converted/ConfigPathChanger.__init__.2.py @@ -0,0 +1,2 @@ + + wx.ConfigPathChanger(wx.ConfigBase.Get(), "/MyProgram/") diff --git a/docs/sphinx/rest_substitutions/snippets/python/converted/Control.SetLabelMarkup.1.py b/docs/sphinx/rest_substitutions/snippets/python/converted/Control.SetLabelMarkup.1.py new file mode 100644 index 00000000..39c80505 --- /dev/null +++ b/docs/sphinx/rest_substitutions/snippets/python/converted/Control.SetLabelMarkup.1.py @@ -0,0 +1,7 @@ + + text = wx.StaticText(self, -1, 'Hello world!') + + # Some more code... + text.SetLabelMarkup("&Bed &mp " + "breakfast " + "available HERE") diff --git a/docs/sphinx/rest_substitutions/snippets/python/converted/Cursor.1.py b/docs/sphinx/rest_substitutions/snippets/python/converted/Cursor.1.py new file mode 100644 index 00000000..89980a16 --- /dev/null +++ b/docs/sphinx/rest_substitutions/snippets/python/converted/Cursor.1.py @@ -0,0 +1,40 @@ + + down_bits = [255, 255, 255, 255, 31, + 255, 255, 255, 31, 255, 255, 255, 31, 255, 255, 255, + 31, 255, 255, 255, 31, 255, 255, 255, 31, 255, 255, + 255, 31, 255, 255, 255, 31, 255, 255, 255, 25, 243, + 255, 255, 19, 249, 255, 255, 7, 252, 255, 255, 15, 254, + 255, 255, 31, 255, 255, 255, 191, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255] + + down_mask = [240, 1, 0, 0, 240, 1, + 0, 0, 240, 1, 0, 0, 240, 1, 0, 0, 240, 1, 0, 0, 240, 1, + 0, 0, 240, 1, 0, 0, 240, 1, 0, 0, 255, 31, 0, 0, 255, + 31, 0, 0, 254, 15, 0, 0, 252, 7, 0, 0, 248, 3, 0, 0, + 240, 1, 0, 0, 224, 0, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0] + + if wx.Platform == '__WXMSW__': + + down_bitmap = wx.BitmapFromBits(down_bits, 32, 32) + down_mask_bitmap = wx.BitmapFromBits(down_mask, 32, 32) + + down_bitmap.SetMask(wx.Mask(down_mask_bitmap)) + down_image = down_bitmap.ConvertToImage() + down_image.SetOption(wx.IMAGE_OPTION_CUR_HOTSPOT_X, 6) + down_image.SetOption(wx.IMAGE_OPTION_CUR_HOTSPOT_Y, 14) + down_cursor = wx.Cursor(down_image) + + elif wx.Platform == '__WXGTK__': + + down_cursor = wx.Cursor(down_bits, 32, 32, 6, 14, + down_mask, wx.WHITE, wx.BLACK) diff --git a/docs/sphinx/rest_substitutions/snippets/python/converted/DCClipper.1.py b/docs/sphinx/rest_substitutions/snippets/python/converted/DCClipper.1.py new file mode 100644 index 00000000..37242287 --- /dev/null +++ b/docs/sphinx/rest_substitutions/snippets/python/converted/DCClipper.1.py @@ -0,0 +1,13 @@ + + def MyFunction(dc): + + clip = wx.DCClipper(dc, rect) + # ... drawing functions here are affected by clipping rect ... + + + def OtherFunction(): + + dc = wx.DC() + MyFunction(dc) + # ... drawing functions here are not affected by clipping rect ... + diff --git a/docs/sphinx/rest_substitutions/snippets/python/converted/Dialog.1.py b/docs/sphinx/rest_substitutions/snippets/python/converted/Dialog.1.py new file mode 100644 index 00000000..acffa5bb --- /dev/null +++ b/docs/sphinx/rest_substitutions/snippets/python/converted/Dialog.1.py @@ -0,0 +1,13 @@ + + def AskUser(self): + + dlg = MyAskDialog(self) + + if dlg.ShowModal() == wx.ID_OK: + # do something here + print 'Hello' + + # else: dialog was cancelled or some another button pressed + + dlg.Destroy() + diff --git a/docs/sphinx/rest_substitutions/snippets/python/converted/Dialog.2.py b/docs/sphinx/rest_substitutions/snippets/python/converted/Dialog.2.py new file mode 100644 index 00000000..0d64b1e9 --- /dev/null +++ b/docs/sphinx/rest_substitutions/snippets/python/converted/Dialog.2.py @@ -0,0 +1,11 @@ + + def AskUser(self): + + dlg = MyAskDialog(self) + + if dlg.ShowModal() == wx.ID_OK: + # do something here + print 'Hello' + + # no need to call Destroy() here + diff --git a/docs/sphinx/rest_substitutions/snippets/python/converted/DirDialog.1.py b/docs/sphinx/rest_substitutions/snippets/python/converted/DirDialog.1.py new file mode 100644 index 00000000..7b68c565 --- /dev/null +++ b/docs/sphinx/rest_substitutions/snippets/python/converted/DirDialog.1.py @@ -0,0 +1,4 @@ + + dlg = wx.DirDialog (None, "Choose input directory", "", + wx.DD_DEFAULT_STYLE | wx.DD_DIR_MUST_EXIST) + diff --git a/docs/sphinx/rest_substitutions/snippets/python/converted/Event.Clone.1.py b/docs/sphinx/rest_substitutions/snippets/python/converted/Event.Clone.1.py new file mode 100644 index 00000000..1fc0e19e --- /dev/null +++ b/docs/sphinx/rest_substitutions/snippets/python/converted/Event.Clone.1.py @@ -0,0 +1,4 @@ + + def Clone(self): + + return MyEvent() diff --git a/docs/sphinx/rest_substitutions/snippets/python/converted/EventBlocker.1.py b/docs/sphinx/rest_substitutions/snippets/python/converted/EventBlocker.1.py new file mode 100644 index 00000000..418883a0 --- /dev/null +++ b/docs/sphinx/rest_substitutions/snippets/python/converted/EventBlocker.1.py @@ -0,0 +1,14 @@ + + def DoSomething(self): + # block all events directed to this window while + # we do the 1000 FunctionWhichSendsEvents() calls + blocker = wx.EventBlocker(self) + + for i in xrange(1000): + FunctionWhichSendsEvents(i) + + # wx.EventBlocker destructor called, old event handler is restored + + # the event generated by this call will be processed: + FunctionWhichSendsEvents(0) + diff --git a/docs/sphinx/rest_substitutions/snippets/python/converted/EventFilter.1.py b/docs/sphinx/rest_substitutions/snippets/python/converted/EventFilter.1.py new file mode 100644 index 00000000..a2e6568f --- /dev/null +++ b/docs/sphinx/rest_substitutions/snippets/python/converted/EventFilter.1.py @@ -0,0 +1,43 @@ + + # This class allows to determine the last time the user has worked with + # this application: + class LastActivityTimeDetector(wx.EventFilter): + + def __init__(self): + + wx.EventFilter.__init__(self) + + wx.EvtHandler.AddFilter(self) + + self.last = wx.DateTime.Now() + + + def __del__(self): + + wx.EvtHandler.RemoveFilter(self) + + + def FilterEvent(self, event): + + # Update the last user activity + t = event.GetEventType() + + if t == wx.EVT_KEY_DOWN or t == wx.EVT_MOTION or \ + t == wx.EVT_LEFT_DOWN or t == wx.EVT_RIGHT_DOWN or \ + t == wx.EVT_MIDDLE_DOWN: + + self.last = wx.DateTime.Now() + + + # Continue processing the event normally as well. + event.Skip() + + + # This function could be called periodically from some timer to + # do something (e.g. hide sensitive data or log out from remote + # server) if the user has been inactive for some time period. + def IsInactiveFor(self, diff): + + return wx.DateTime.Now() - diff > self.last + + \ No newline at end of file diff --git a/docs/sphinx/rest_substitutions/snippets/python/converted/EventLoopActivator.1.py b/docs/sphinx/rest_substitutions/snippets/python/converted/EventLoopActivator.1.py new file mode 100644 index 00000000..33fee4e0 --- /dev/null +++ b/docs/sphinx/rest_substitutions/snippets/python/converted/EventLoopActivator.1.py @@ -0,0 +1,11 @@ + + class MyEventLoop(wx.EventLoopBase): + + def RunMyLoop(self): + + loop = MyEventLoop() + activate = wx.EventLoopActivator(loop) + + # other code... + + # the previously active event loop restored here diff --git a/docs/sphinx/rest_substitutions/snippets/python/converted/EventLoopBase.Dispatch.1.py b/docs/sphinx/rest_substitutions/snippets/python/converted/EventLoopBase.Dispatch.1.py new file mode 100644 index 00000000..1ecec182 --- /dev/null +++ b/docs/sphinx/rest_substitutions/snippets/python/converted/EventLoopBase.Dispatch.1.py @@ -0,0 +1,3 @@ + + while evtloop.Pending(): + evtloop.Dispatch() diff --git a/docs/sphinx/rest_substitutions/snippets/python/converted/EvtHandler.QueueEvent.1.py b/docs/sphinx/rest_substitutions/snippets/python/converted/EvtHandler.QueueEvent.1.py new file mode 100644 index 00000000..5cdc5713 --- /dev/null +++ b/docs/sphinx/rest_substitutions/snippets/python/converted/EvtHandler.QueueEvent.1.py @@ -0,0 +1,10 @@ + + def FunctionInAWorkerThread(strs): + + evt = wx.CommandEvent() + + # NOT evt.SetString(strs) as this would be a shallow copy + evt.SetString(strs[:]) # make a deep copy + + wx.TheApp.QueueEvent(evt) + diff --git a/docs/sphinx/rest_substitutions/snippets/python/converted/EvtHandler.QueueEvent.2.py b/docs/sphinx/rest_substitutions/snippets/python/converted/EvtHandler.QueueEvent.2.py new file mode 100644 index 00000000..e0ec1693 --- /dev/null +++ b/docs/sphinx/rest_substitutions/snippets/python/converted/EvtHandler.QueueEvent.2.py @@ -0,0 +1,10 @@ + + def FunctionInAWorkerThread(strs): + + evt = wx.ThreadEvent() + evt.SetString(strs) + + # wx.ThreadEvent.Clone() makes sure that the internal wx.String + # member is not shared by other string instances: + wx.TheApp.QueueEvent(evt.Clone()) + diff --git a/docs/sphinx/rest_substitutions/snippets/python/converted/EvtHandler.SetNextHandler.1.py b/docs/sphinx/rest_substitutions/snippets/python/converted/EvtHandler.SetNextHandler.1.py new file mode 100644 index 00000000..7d64e380 --- /dev/null +++ b/docs/sphinx/rest_substitutions/snippets/python/converted/EvtHandler.SetNextHandler.1.py @@ -0,0 +1,3 @@ + + handlerA.SetNextHandler(handlerB) + handlerB.SetPreviousHandler(handlerA) diff --git a/docs/sphinx/rest_substitutions/snippets/python/converted/FileDialog.1.py b/docs/sphinx/rest_substitutions/snippets/python/converted/FileDialog.1.py new file mode 100644 index 00000000..43fc2035 --- /dev/null +++ b/docs/sphinx/rest_substitutions/snippets/python/converted/FileDialog.1.py @@ -0,0 +1,27 @@ + + def OnOpen(self, event): + + if self.contentNotSaved: + + if wx.MessageBox("Current content has not been saved! Proceed?", "Please confirm", + wx.ICON_QUESTION | wx.YES_NO, self) == wx.NO: + return + + # else: proceed asking to the user the new file to open + + openFileDialog = wx.FileDialog(self, "Open XYZ file", "", "", + "XYZ files (*.xyz)|*.xyz", wx.FD_OPEN|wx.FD_FILE_MUST_EXIST) + + if openFileDialog.ShowModal() == wx.ID_CANCEL: + return # the user changed idea... + + # proceed loading the file chosen by the user + # this can be done with e.g. wxPython input streams: + input_stream = wx.FileInputStream(openFileDialog.GetPath()) + + if not input_stream.IsOk(): + + wx.LogError("Cannot open file '%s'."%openFileDialog.GetPath()) + return + + \ No newline at end of file diff --git a/docs/sphinx/rest_substitutions/snippets/python/converted/FileDialog.2.py b/docs/sphinx/rest_substitutions/snippets/python/converted/FileDialog.2.py new file mode 100644 index 00000000..cf8afced --- /dev/null +++ b/docs/sphinx/rest_substitutions/snippets/python/converted/FileDialog.2.py @@ -0,0 +1,17 @@ + + def OnSaveAs(self, event): + + saveFileDialog = wx.FileDialog(self, "Save XYZ file", "", "", + "XYZ files (*.xyz)|*.xyz", wx.FD_SAVE|wx.FD_OVERWRITE_PROMPT) + + if saveFileDialog.ShowModal() == wx.ID_CANCEL: + return # the user changed idea... + + # save the current contents in the file + # this can be done with e.g. wxPython output streams: + output_stream = wx.FileOutputStream(saveFileDialog.GetPath()) + + if not output_stream.IsOk(): + wx.LogError("Cannot save current contents in file '%s'."%saveFileDialog.GetPath()) + return + diff --git a/docs/sphinx/rest_substitutions/snippets/python/converted/FileDialog.3.py b/docs/sphinx/rest_substitutions/snippets/python/converted/FileDialog.3.py new file mode 100644 index 00000000..cd5f72e3 --- /dev/null +++ b/docs/sphinx/rest_substitutions/snippets/python/converted/FileDialog.3.py @@ -0,0 +1,2 @@ + + wildcard = "BMP and GIF files (*.bmp*.gif)|*.bmp*.gif|PNG files (*.png)|*.png" diff --git a/docs/sphinx/rest_substitutions/snippets/python/converted/Frame.1.py b/docs/sphinx/rest_substitutions/snippets/python/converted/Frame.1.py new file mode 100644 index 00000000..fa5258dd --- /dev/null +++ b/docs/sphinx/rest_substitutions/snippets/python/converted/Frame.1.py @@ -0,0 +1,2 @@ + + style = wx.DEFAULT_FRAME_STYLE & ~(wx.RESIZE_BORDER | wx.MAXIMIZE_BOX) diff --git a/docs/sphinx/rest_substitutions/snippets/python/converted/GraphicsContext.1.py b/docs/sphinx/rest_substitutions/snippets/python/converted/GraphicsContext.1.py new file mode 100644 index 00000000..1c9cdc21 --- /dev/null +++ b/docs/sphinx/rest_substitutions/snippets/python/converted/GraphicsContext.1.py @@ -0,0 +1,25 @@ + + def OnPaint(self, event): + + # Create paint DC + dc = wx.PaintDC(self) + + # Create graphics context from it + gc = wx.GraphicsContext.Create(dc) + + if gc: + + # make a path that contains a circle and some lines + gc.SetPen(wx.RED_PEN) + path = gc.CreatePath() + path.AddCircle(50.0, 50.0, 50.0) + path.MoveToPoint(0.0, 50.0) + path.AddLineToPoint(100.0, 50.0) + path.MoveToPoint(50.0, 0.0) + path.AddLineToPoint(50.0, 100.0) + path.CloseSubpath() + path.AddRectangle(25.0, 25.0, 50.0, 50.0) + + gc.StrokePath(path) + + diff --git a/docs/sphinx/rest_substitutions/snippets/python/converted/GraphicsRenderer.1.py b/docs/sphinx/rest_substitutions/snippets/python/converted/GraphicsRenderer.1.py new file mode 100644 index 00000000..62df5608 --- /dev/null +++ b/docs/sphinx/rest_substitutions/snippets/python/converted/GraphicsRenderer.1.py @@ -0,0 +1,3 @@ + + path = wx.GraphicsPath() # from somewhere + brush = path.GetRenderer().CreateBrush(wx.BLACK_BRUSH) diff --git a/docs/sphinx/rest_substitutions/snippets/python/converted/HeaderColumnSimple.1.py b/docs/sphinx/rest_substitutions/snippets/python/converted/HeaderColumnSimple.1.py new file mode 100644 index 00000000..7c017ddc --- /dev/null +++ b/docs/sphinx/rest_substitutions/snippets/python/converted/HeaderColumnSimple.1.py @@ -0,0 +1,6 @@ + + header = wx.HeaderCtrlSimple() # Fill in the constructor + col = wx.HeaderColumnSimple("Title") + col.SetWidth(100) + col.SetSortable(100) + header.AppendColumn(col) diff --git a/docs/sphinx/rest_substitutions/snippets/python/converted/IconBundle.GetIcon.1.py b/docs/sphinx/rest_substitutions/snippets/python/converted/IconBundle.GetIcon.1.py new file mode 100644 index 00000000..6653b217 --- /dev/null +++ b/docs/sphinx/rest_substitutions/snippets/python/converted/IconBundle.GetIcon.1.py @@ -0,0 +1,2 @@ + + GetIcon(wx.Size(size, size)) diff --git a/docs/sphinx/rest_substitutions/snippets/python/converted/Image.ComputeHistogram.1.py b/docs/sphinx/rest_substitutions/snippets/python/converted/Image.ComputeHistogram.1.py new file mode 100644 index 00000000..ec020eea --- /dev/null +++ b/docs/sphinx/rest_substitutions/snippets/python/converted/Image.ComputeHistogram.1.py @@ -0,0 +1,10 @@ + + # This is a raw translation of the ImageHistogramEntry + # code in C++, not a real Python class + class ImageHistogramEntry(object): + + def __init__(self): + + self.index = 0 + self.value = 0 + diff --git a/docs/sphinx/rest_substitutions/snippets/python/converted/Image.GetImageExtWildcard.1.py b/docs/sphinx/rest_substitutions/snippets/python/converted/Image.GetImageExtWildcard.1.py new file mode 100644 index 00000000..7c169699 --- /dev/null +++ b/docs/sphinx/rest_substitutions/snippets/python/converted/Image.GetImageExtWildcard.1.py @@ -0,0 +1,4 @@ + + FileDlg = wx.FileDialog(self, "Choose Image", os.getcwd(), "", + "Image Files " + wx.Image.GetImageExtWildcard(), + wx.FD_OPEN) diff --git a/docs/sphinx/rest_substitutions/snippets/python/converted/Image.LoadFile.1.py b/docs/sphinx/rest_substitutions/snippets/python/converted/Image.LoadFile.1.py new file mode 100644 index 00000000..4b1a53f5 --- /dev/null +++ b/docs/sphinx/rest_substitutions/snippets/python/converted/Image.LoadFile.1.py @@ -0,0 +1,3 @@ + + hotspot_x = image.GetOptionInt(wx.IMAGE_OPTION_CUR_HOTSPOT_X) + hotspot_y = image.GetOptionInt(wx.IMAGE_OPTION_CUR_HOTSPOT_Y) diff --git a/docs/sphinx/rest_substitutions/snippets/python/converted/Image.LoadFile.2.py b/docs/sphinx/rest_substitutions/snippets/python/converted/Image.LoadFile.2.py new file mode 100644 index 00000000..4b1a53f5 --- /dev/null +++ b/docs/sphinx/rest_substitutions/snippets/python/converted/Image.LoadFile.2.py @@ -0,0 +1,3 @@ + + hotspot_x = image.GetOptionInt(wx.IMAGE_OPTION_CUR_HOTSPOT_X) + hotspot_y = image.GetOptionInt(wx.IMAGE_OPTION_CUR_HOTSPOT_Y) diff --git a/docs/sphinx/rest_substitutions/snippets/python/converted/Image.SaveFile.1.py b/docs/sphinx/rest_substitutions/snippets/python/converted/Image.SaveFile.1.py new file mode 100644 index 00000000..6800fb0c --- /dev/null +++ b/docs/sphinx/rest_substitutions/snippets/python/converted/Image.SaveFile.1.py @@ -0,0 +1,3 @@ + + image.SetOption(wx.IMAGE_OPTION_CUR_HOTSPOT_X, hotspotX) + image.SetOption(wx.IMAGE_OPTION_CUR_HOTSPOT_Y, hotspotY) diff --git a/docs/sphinx/rest_substitutions/snippets/python/converted/Image.SaveFile.2.py b/docs/sphinx/rest_substitutions/snippets/python/converted/Image.SaveFile.2.py new file mode 100644 index 00000000..6800fb0c --- /dev/null +++ b/docs/sphinx/rest_substitutions/snippets/python/converted/Image.SaveFile.2.py @@ -0,0 +1,3 @@ + + image.SetOption(wx.IMAGE_OPTION_CUR_HOTSPOT_X, hotspotX) + image.SetOption(wx.IMAGE_OPTION_CUR_HOTSPOT_Y, hotspotY) diff --git a/docs/sphinx/rest_substitutions/snippets/python/converted/Image.Scale.1.py b/docs/sphinx/rest_substitutions/snippets/python/converted/Image.Scale.1.py new file mode 100644 index 00000000..50facf29 --- /dev/null +++ b/docs/sphinx/rest_substitutions/snippets/python/converted/Image.Scale.1.py @@ -0,0 +1,14 @@ + + # get the bitmap from somewhere + bmp = wx.Bitmap('my_png.png', wx.BITMAP_TYPE_PNG) + + # rescale it to have size of 32*32 + if bmp.GetWidth() != 32 or bmp.GetHeight() != 32: + + image = bmp.ConvertToImage() + bmp = wx.BitmapFromImage(image.Scale(32, 32)) + + # another possibility: + image.Rescale(32, 32) + bmp = wx.BitmapFromImage(image) + diff --git a/docs/sphinx/rest_substitutions/snippets/python/converted/Image.__init__.1.py b/docs/sphinx/rest_substitutions/snippets/python/converted/Image.__init__.1.py new file mode 100644 index 00000000..4b1a53f5 --- /dev/null +++ b/docs/sphinx/rest_substitutions/snippets/python/converted/Image.__init__.1.py @@ -0,0 +1,3 @@ + + hotspot_x = image.GetOptionInt(wx.IMAGE_OPTION_CUR_HOTSPOT_X) + hotspot_y = image.GetOptionInt(wx.IMAGE_OPTION_CUR_HOTSPOT_Y) diff --git a/docs/sphinx/rest_substitutions/snippets/python/converted/KeyEvent.GetKeyCode.1.py b/docs/sphinx/rest_substitutions/snippets/python/converted/KeyEvent.GetKeyCode.1.py new file mode 100644 index 00000000..66b42cd2 --- /dev/null +++ b/docs/sphinx/rest_substitutions/snippets/python/converted/KeyEvent.GetKeyCode.1.py @@ -0,0 +1,24 @@ + + def OnChar(self, event): + + keycode = event.GetUnicodeKey() + + if keycode != wx.WXK_NONE: + + # It's a printable character + wx.LogMessage("You pressed '%c'"%keycode) + + else: + + # It's a special key, deal with all the known ones: + if keycode in [wx.WXK_LEFT, wx.WXK_RIGHT]: + # move cursor ... + MoveCursor() + + elif keycode == wx.WXK_F1: + # give help ... + GiveHelp() + + + + diff --git a/docs/sphinx/rest_substitutions/snippets/python/converted/KeyboardState.GetModifiers.1.py b/docs/sphinx/rest_substitutions/snippets/python/converted/KeyboardState.GetModifiers.1.py new file mode 100644 index 00000000..1dc7b175 --- /dev/null +++ b/docs/sphinx/rest_substitutions/snippets/python/converted/KeyboardState.GetModifiers.1.py @@ -0,0 +1,5 @@ + + if ControlDown() and not AltDown() and not ShiftDown() and not MetaDown(): + # handle Ctrl-XXX ... + HandleControl() + diff --git a/docs/sphinx/rest_substitutions/snippets/python/converted/KeyboardState.GetModifiers.2.py b/docs/sphinx/rest_substitutions/snippets/python/converted/KeyboardState.GetModifiers.2.py new file mode 100644 index 00000000..0dbccdb9 --- /dev/null +++ b/docs/sphinx/rest_substitutions/snippets/python/converted/KeyboardState.GetModifiers.2.py @@ -0,0 +1,4 @@ + + if GetModifiers() == wx.MOD_CONTROL: + # handle Ctrl-XXX ... + HandleControl() diff --git a/docs/sphinx/rest_substitutions/snippets/python/converted/Log.LogRecord.1.py b/docs/sphinx/rest_substitutions/snippets/python/converted/Log.LogRecord.1.py new file mode 100644 index 00000000..499df34b --- /dev/null +++ b/docs/sphinx/rest_substitutions/snippets/python/converted/Log.LogRecord.1.py @@ -0,0 +1,11 @@ + + def DoLogRecord(self, level, msg, info): + + # let the previous logger show it + if self.logOld and IsPassingMessages(): + self.logOld.LogRecord(level, msg, info) + + # and also send it to the one + if self.logNew and self.logNew != self: + self.logNew.LogRecord(level, msg, info) + diff --git a/docs/sphinx/rest_substitutions/snippets/python/converted/Log.SetComponentLevel.1.py b/docs/sphinx/rest_substitutions/snippets/python/converted/Log.SetComponentLevel.1.py new file mode 100644 index 00000000..24fa6b4b --- /dev/null +++ b/docs/sphinx/rest_substitutions/snippets/python/converted/Log.SetComponentLevel.1.py @@ -0,0 +1,2 @@ + + wx.Log.SetComponentLevel("wx./net", wx.LOG_Error) diff --git a/docs/sphinx/rest_substitutions/snippets/python/converted/LogChain.1.py b/docs/sphinx/rest_substitutions/snippets/python/converted/LogChain.1.py new file mode 100644 index 00000000..54f40b3b --- /dev/null +++ b/docs/sphinx/rest_substitutions/snippets/python/converted/LogChain.1.py @@ -0,0 +1,7 @@ + + logChain = wx.LogChain(wx.LogStderr) + + # all the log messages are sent to stderr and also processed as usually + + # don't delete logChain directly as self would leave a dangling + # pointer as active log target, use SetActiveTarget() instead diff --git a/docs/sphinx/rest_substitutions/snippets/python/converted/MemoryDC.1.py b/docs/sphinx/rest_substitutions/snippets/python/converted/MemoryDC.1.py new file mode 100644 index 00000000..cad5cfc5 --- /dev/null +++ b/docs/sphinx/rest_substitutions/snippets/python/converted/MemoryDC.1.py @@ -0,0 +1,8 @@ + + # Create a memory DC + temp_dc = wx.MemoryDC() + temp_dc.SelectObject(test_bitmap) + + # We can now draw into the memory DC... + # Copy from self DC to another DC. + old_dc.Blit(250, 50, BITMAP_WIDTH, BITMAP_HEIGHT, temp_dc, 0, 0) diff --git a/docs/sphinx/rest_substitutions/snippets/python/converted/MemoryDC.2.py b/docs/sphinx/rest_substitutions/snippets/python/converted/MemoryDC.2.py new file mode 100644 index 00000000..62a581c4 --- /dev/null +++ b/docs/sphinx/rest_substitutions/snippets/python/converted/MemoryDC.2.py @@ -0,0 +1,2 @@ + + temp_dc.SelectObject(wx.NullBitmap) diff --git a/docs/sphinx/rest_substitutions/snippets/python/converted/Menu.Append.1.py b/docs/sphinx/rest_substitutions/snippets/python/converted/Menu.Append.1.py new file mode 100644 index 00000000..00e23389 --- /dev/null +++ b/docs/sphinx/rest_substitutions/snippets/python/converted/Menu.Append.1.py @@ -0,0 +1,2 @@ + + self.fileMenu.Append(ID_NEW_FILE, "&New file\tCTRL+N", "Creates a XYZ document") diff --git a/docs/sphinx/rest_substitutions/snippets/python/converted/Menu.Append.2.py b/docs/sphinx/rest_substitutions/snippets/python/converted/Menu.Append.2.py new file mode 100644 index 00000000..2e815841 --- /dev/null +++ b/docs/sphinx/rest_substitutions/snippets/python/converted/Menu.Append.2.py @@ -0,0 +1,2 @@ + + self.fileMenu.Append(wx.ID_NEW, "", "Creates a XYZ document") diff --git a/docs/sphinx/rest_substitutions/snippets/python/converted/Menu.Append.3.py b/docs/sphinx/rest_substitutions/snippets/python/converted/Menu.Append.3.py new file mode 100644 index 00000000..00e23389 --- /dev/null +++ b/docs/sphinx/rest_substitutions/snippets/python/converted/Menu.Append.3.py @@ -0,0 +1,2 @@ + + self.fileMenu.Append(ID_NEW_FILE, "&New file\tCTRL+N", "Creates a XYZ document") diff --git a/docs/sphinx/rest_substitutions/snippets/python/converted/Menu.Append.4.py b/docs/sphinx/rest_substitutions/snippets/python/converted/Menu.Append.4.py new file mode 100644 index 00000000..2e815841 --- /dev/null +++ b/docs/sphinx/rest_substitutions/snippets/python/converted/Menu.Append.4.py @@ -0,0 +1,2 @@ + + self.fileMenu.Append(wx.ID_NEW, "", "Creates a XYZ document") diff --git a/docs/sphinx/rest_substitutions/snippets/python/converted/MenuItem.GetLabelText.1.py b/docs/sphinx/rest_substitutions/snippets/python/converted/MenuItem.GetLabelText.1.py new file mode 100644 index 00000000..f92fbf0e --- /dev/null +++ b/docs/sphinx/rest_substitutions/snippets/python/converted/MenuItem.GetLabelText.1.py @@ -0,0 +1,2 @@ + + wx.MenuItem.GetLabelfromText("&Hello\tCtrl-h") diff --git a/docs/sphinx/rest_substitutions/snippets/python/converted/MenuItem.SetItemLabel.1.py b/docs/sphinx/rest_substitutions/snippets/python/converted/MenuItem.SetItemLabel.1.py new file mode 100644 index 00000000..f1e4eb06 --- /dev/null +++ b/docs/sphinx/rest_substitutions/snippets/python/converted/MenuItem.SetItemLabel.1.py @@ -0,0 +1,5 @@ + + self.myMenuItem.SetItemLabel("My &item\tCTRL+I") + self.myMenuItem2.SetItemLabel("Clean and build\tF7") + self.myMenuItem3.SetItemLabel("Simple item") + self.myMenuItem4.SetItemLabel("Item with &accelerator") diff --git a/docs/sphinx/rest_substitutions/snippets/python/converted/MenuItem.__init__.1.py b/docs/sphinx/rest_substitutions/snippets/python/converted/MenuItem.__init__.1.py new file mode 100644 index 00000000..399023ef --- /dev/null +++ b/docs/sphinx/rest_substitutions/snippets/python/converted/MenuItem.__init__.1.py @@ -0,0 +1,11 @@ + + # use all stock properties: + helpMenu.Append(wx.ID_ABOUT) + + # use the stock label and the stock accelerator but not the stock help string: + helpMenu.Append(wx.ID_ABOUT, "", "My custom help string") + + # use all stock properties except for the bitmap: + mymenu = wx.MenuItem(helpMenu, wx.ID_ABOUT) + mymenu.SetBitmap(wx.ArtProvider.GetBitmap(wx.ART_WARNING)) + helpMenu.Append(mymenu) diff --git a/docs/sphinx/rest_substitutions/snippets/python/converted/MessageDialog.SetYesNoLabels.1.py b/docs/sphinx/rest_substitutions/snippets/python/converted/MessageDialog.SetYesNoLabels.1.py new file mode 100644 index 00000000..a9e57a2b --- /dev/null +++ b/docs/sphinx/rest_substitutions/snippets/python/converted/MessageDialog.SetYesNoLabels.1.py @@ -0,0 +1,3 @@ + + dlg = wx.MessageDialog(parent, message, caption) + dlg.SetYesNoLabels(wx.ID_SAVE, "&Don't save") diff --git a/docs/sphinx/rest_substitutions/snippets/python/converted/MessageDialog.SetYesNoLabels.2.py b/docs/sphinx/rest_substitutions/snippets/python/converted/MessageDialog.SetYesNoLabels.2.py new file mode 100644 index 00000000..c8875dd0 --- /dev/null +++ b/docs/sphinx/rest_substitutions/snippets/python/converted/MessageDialog.SetYesNoLabels.2.py @@ -0,0 +1,6 @@ + + dlg = wx.MessageDialog(parent, message, caption) + if dlg.SetYesNoLabels("&Quit", "&Don't quit"): + dlg.SetMessage("What do you want to do?") + else: # buttons have standard "Yes"/"No" values, so rephrase the question + dlg.SetMessage("Do you really want to quit?") diff --git a/docs/sphinx/rest_substitutions/snippets/python/converted/NonOwnedWindow.SetShape.1.py b/docs/sphinx/rest_substitutions/snippets/python/converted/NonOwnedWindow.SetShape.1.py new file mode 100644 index 00000000..c4d477c5 --- /dev/null +++ b/docs/sphinx/rest_substitutions/snippets/python/converted/NonOwnedWindow.SetShape.1.py @@ -0,0 +1,7 @@ + + size = self.GetSize() + + path = wx.GraphicsRenderer.GetDefaultRenderer().CreatePath() + path.AddCircle(size.x/2, size.y/2, 30) + + self.SetShape(path) diff --git a/docs/sphinx/rest_substitutions/snippets/python/converted/Notebook.1.py b/docs/sphinx/rest_substitutions/snippets/python/converted/Notebook.1.py new file mode 100644 index 00000000..4c9697ad --- /dev/null +++ b/docs/sphinx/rest_substitutions/snippets/python/converted/Notebook.1.py @@ -0,0 +1,2 @@ + + wx.SystemOptions.SetOption("msw.notebook.themed-background", 0) diff --git a/docs/sphinx/rest_substitutions/snippets/python/converted/Notebook.2.py b/docs/sphinx/rest_substitutions/snippets/python/converted/Notebook.2.py new file mode 100644 index 00000000..423c8b64 --- /dev/null +++ b/docs/sphinx/rest_substitutions/snippets/python/converted/Notebook.2.py @@ -0,0 +1,6 @@ + + col = notebook.GetThemeBackgroundColour() + + if col.IsOk(): + page.SetBackgroundColour(col) + diff --git a/docs/sphinx/rest_substitutions/snippets/python/converted/PaintEvent.1.py b/docs/sphinx/rest_substitutions/snippets/python/converted/PaintEvent.1.py new file mode 100644 index 00000000..a83661de --- /dev/null +++ b/docs/sphinx/rest_substitutions/snippets/python/converted/PaintEvent.1.py @@ -0,0 +1,6 @@ + + def OnPaint(self, event): + + dc = wx.PaintDC(self) + DrawMyDocument(dc) + diff --git a/docs/sphinx/rest_substitutions/snippets/python/converted/PaintEvent.2.py b/docs/sphinx/rest_substitutions/snippets/python/converted/PaintEvent.2.py new file mode 100644 index 00000000..1fa22ada --- /dev/null +++ b/docs/sphinx/rest_substitutions/snippets/python/converted/PaintEvent.2.py @@ -0,0 +1,21 @@ + + # Called when window needs to be repainted. + def OnPaint(self, event): + + dc = wx.PaintDC(self) + + # Find out where the window is scrolled to + vbX, vbY = self.GetViewStart() + + # get the update rect list + upd = wx.RegionIterator(self.GetUpdateRegion()) + + while upd.HaveRects(): + + rect = upd.GetRect() + + # Repaint this rectangle + PaintRectangle(rect, dc) + + upd.Next() + diff --git a/docs/sphinx/rest_substitutions/snippets/python/converted/PlatformInfo.1.py b/docs/sphinx/rest_substitutions/snippets/python/converted/PlatformInfo.1.py new file mode 100644 index 00000000..d4639bf3 --- /dev/null +++ b/docs/sphinx/rest_substitutions/snippets/python/converted/PlatformInfo.1.py @@ -0,0 +1,2 @@ + + wx.LogMessage("This application is running under %s." % wx.PlatformInfo.Get().GetOperatingSystemIdName()) diff --git a/docs/sphinx/rest_substitutions/snippets/python/converted/Point.SetDefaults.1.py b/docs/sphinx/rest_substitutions/snippets/python/converted/Point.SetDefaults.1.py new file mode 100644 index 00000000..107ffff8 --- /dev/null +++ b/docs/sphinx/rest_substitutions/snippets/python/converted/Point.SetDefaults.1.py @@ -0,0 +1,5 @@ + + if not pos.IsFullySpecified(): + + pos.SetDefaults(GetDefaultPosition()) + diff --git a/docs/sphinx/rest_substitutions/snippets/python/converted/Scrolled.DoPrepareDC.1.py b/docs/sphinx/rest_substitutions/snippets/python/converted/Scrolled.DoPrepareDC.1.py new file mode 100644 index 00000000..bc66f2ea --- /dev/null +++ b/docs/sphinx/rest_substitutions/snippets/python/converted/Scrolled.DoPrepareDC.1.py @@ -0,0 +1,16 @@ + + def OnEvent(self, event): + + dc = wx.ClientDC(self) + self.DoPrepareDC(dc) + + dc.SetPen(wx.BLACK_PEN) + + x, y = event.GetPosition() + + if (xpos > -1 and ypos > -1 and event.Dragging()): + dc.DrawLine(xpos, ypos, x, y) + + xpos = x + ypos = y + diff --git a/docs/sphinx/rest_substitutions/snippets/python/converted/Scrolled.SetScrollbars.1.py b/docs/sphinx/rest_substitutions/snippets/python/converted/Scrolled.SetScrollbars.1.py new file mode 100644 index 00000000..f0a76730 --- /dev/null +++ b/docs/sphinx/rest_substitutions/snippets/python/converted/Scrolled.SetScrollbars.1.py @@ -0,0 +1,2 @@ + + window.SetScrollbars(20, 20, 50, 50) diff --git a/docs/sphinx/rest_substitutions/snippets/python/converted/SearchCtrl.1.py b/docs/sphinx/rest_substitutions/snippets/python/converted/SearchCtrl.1.py new file mode 100644 index 00000000..cba3b21b --- /dev/null +++ b/docs/sphinx/rest_substitutions/snippets/python/converted/SearchCtrl.1.py @@ -0,0 +1,2 @@ + + event.GetString() diff --git a/docs/sphinx/rest_substitutions/snippets/python/converted/SingleInstanceChecker.1.py b/docs/sphinx/rest_substitutions/snippets/python/converted/SingleInstanceChecker.1.py new file mode 100644 index 00000000..bb4a63b9 --- /dev/null +++ b/docs/sphinx/rest_substitutions/snippets/python/converted/SingleInstanceChecker.1.py @@ -0,0 +1,14 @@ + + def OnInit(self): + + self.name = "SingleApp-%s" % wx.GetUserId() + self.instance = wx.SingleInstanceChecker(self.name) + + if self.instance.IsAnotherRunning(): + wx.MessageBox("Another instance is running", "ERROR") + return False + + frame = SingleAppFrame(None, "SingleApp") + frame.Show() + return True + diff --git a/docs/sphinx/rest_substitutions/snippets/python/converted/Size.SetDefaults.1.py b/docs/sphinx/rest_substitutions/snippets/python/converted/Size.SetDefaults.1.py new file mode 100644 index 00000000..d762072b --- /dev/null +++ b/docs/sphinx/rest_substitutions/snippets/python/converted/Size.SetDefaults.1.py @@ -0,0 +1,5 @@ + + if not size.IsFullySpecified(): + + size.SetDefaults(GetDefaultSize()) + diff --git a/docs/sphinx/rest_substitutions/snippets/python/converted/Sizer.AddSpacer.1.py b/docs/sphinx/rest_substitutions/snippets/python/converted/Sizer.AddSpacer.1.py new file mode 100644 index 00000000..5e416ee5 --- /dev/null +++ b/docs/sphinx/rest_substitutions/snippets/python/converted/Sizer.AddSpacer.1.py @@ -0,0 +1,2 @@ + + wx.Sizer.Add(size, size, 0) diff --git a/docs/sphinx/rest_substitutions/snippets/python/converted/Sizer.AddStretchSpacer.1.py b/docs/sphinx/rest_substitutions/snippets/python/converted/Sizer.AddStretchSpacer.1.py new file mode 100644 index 00000000..ffdb4516 --- /dev/null +++ b/docs/sphinx/rest_substitutions/snippets/python/converted/Sizer.AddStretchSpacer.1.py @@ -0,0 +1,2 @@ + + wx.Sizer.Add(0, 0, proportion) diff --git a/docs/sphinx/rest_substitutions/snippets/python/converted/SizerFlags.1.py b/docs/sphinx/rest_substitutions/snippets/python/converted/SizerFlags.1.py new file mode 100644 index 00000000..98ed9811 --- /dev/null +++ b/docs/sphinx/rest_substitutions/snippets/python/converted/SizerFlags.1.py @@ -0,0 +1,2 @@ + + sizer.Add(ctrl, 0, wx.EXPAND | wx.ALL, 10) diff --git a/docs/sphinx/rest_substitutions/snippets/python/converted/SizerFlags.2.py b/docs/sphinx/rest_substitutions/snippets/python/converted/SizerFlags.2.py new file mode 100644 index 00000000..2f2d358f --- /dev/null +++ b/docs/sphinx/rest_substitutions/snippets/python/converted/SizerFlags.2.py @@ -0,0 +1,2 @@ + + sizer.Add(ctrl, wx.SizerFlags().Expand().Border(wx.ALL, 10)) diff --git a/docs/sphinx/rest_substitutions/snippets/python/converted/SizerFlags.3.py b/docs/sphinx/rest_substitutions/snippets/python/converted/SizerFlags.3.py new file mode 100644 index 00000000..b7734172 --- /dev/null +++ b/docs/sphinx/rest_substitutions/snippets/python/converted/SizerFlags.3.py @@ -0,0 +1,6 @@ + + flagsExpand = wx.SizerFlags(1) + flagsExpand.Expand().Border(wx.ALL, 10) + + sizer.Add(ctrl1, flagsExpand) + sizer.Add(ctrl2, flagsExpand) diff --git a/docs/sphinx/rest_substitutions/snippets/python/converted/StandardPaths.MSWGetShellDir.1.py b/docs/sphinx/rest_substitutions/snippets/python/converted/StandardPaths.MSWGetShellDir.1.py new file mode 100644 index 00000000..2e965c82 --- /dev/null +++ b/docs/sphinx/rest_substitutions/snippets/python/converted/StandardPaths.MSWGetShellDir.1.py @@ -0,0 +1,6 @@ + + if wx.Platform == '__WXMSW__': + # get the location of files waiting to be burned on a CD + cdburnArea = wx.StandardPaths.MSWGetShellDir(CSIDL_CDBURN_AREA) + + # endif __WXMSW__ diff --git a/docs/sphinx/rest_substitutions/snippets/python/converted/StandardPaths.UseAppInfo.1.py b/docs/sphinx/rest_substitutions/snippets/python/converted/StandardPaths.UseAppInfo.1.py new file mode 100644 index 00000000..68ecf065 --- /dev/null +++ b/docs/sphinx/rest_substitutions/snippets/python/converted/StandardPaths.UseAppInfo.1.py @@ -0,0 +1,2 @@ + + info = AppInfo_AppName | AppInfo_VendorName diff --git a/docs/sphinx/rest_substitutions/snippets/python/converted/StaticBox.1.py b/docs/sphinx/rest_substitutions/snippets/python/converted/StaticBox.1.py new file mode 100644 index 00000000..8c3b87d0 --- /dev/null +++ b/docs/sphinx/rest_substitutions/snippets/python/converted/StaticBox.1.py @@ -0,0 +1,9 @@ + + def CreateControls(self): + + panel = wx.Panel(self) + box = wx.StaticBox(panel, wx.ID_ANY, "StaticBox") + + text = wx.StaticText(box, wx.ID_ANY, "This window is a child of the staticbox") + + # Other code... diff --git a/docs/sphinx/rest_substitutions/snippets/python/converted/StaticBox.2.py b/docs/sphinx/rest_substitutions/snippets/python/converted/StaticBox.2.py new file mode 100644 index 00000000..c44137bd --- /dev/null +++ b/docs/sphinx/rest_substitutions/snippets/python/converted/StaticBox.2.py @@ -0,0 +1,6 @@ + + box = wx.StaticBox(panel, wx.ID_ANY, "StaticBox") + + text = wx.StaticText(panel, wx.ID_ANY, "This window is a child of the panel") + + # Other code... diff --git a/docs/sphinx/rest_substitutions/snippets/python/converted/StaticBoxSizer.1.py b/docs/sphinx/rest_substitutions/snippets/python/converted/StaticBoxSizer.1.py new file mode 100644 index 00000000..6786e090 --- /dev/null +++ b/docs/sphinx/rest_substitutions/snippets/python/converted/StaticBoxSizer.1.py @@ -0,0 +1,12 @@ + + def CreateControls(self): + + panel = wx.Panel(self) + # Other controls here... + + sz = wx.StaticBoxSizer(wx.VERTICAL, panel, "Box") + sz.Add(wx.StaticText(sz.GetStaticBox(), wx.ID_ANY, + "This window is a child of the staticbox")) + + # Other code... + diff --git a/docs/sphinx/rest_substitutions/snippets/python/converted/TextCompleterSimple.1.py b/docs/sphinx/rest_substitutions/snippets/python/converted/TextCompleterSimple.1.py new file mode 100644 index 00000000..3bfe6db0 --- /dev/null +++ b/docs/sphinx/rest_substitutions/snippets/python/converted/TextCompleterSimple.1.py @@ -0,0 +1,29 @@ + + class MyTextCompleter(wx.TextCompleterSimple): + + def __init__(self): + + wx.TextCompleterSimple.__init__(self) + + + def GetCompletions(self, prefix, res): + + firstWord = prefix.split()[0] + + if firstWord == "white": + res.append("white pawn") + res.append("white rook") + + elif firstWord == "black": + res.append("black king") + res.append("black queen") + + else: + res.append("white") + res.append("black") + + + # Later on... + text = wx.TextCtrl(parent, wx.ID_ANY, 'My Text') + text.AutoComplete(MyTextCompleter) + diff --git a/docs/sphinx/rest_substitutions/snippets/python/converted/TextCtrl.1.py b/docs/sphinx/rest_substitutions/snippets/python/converted/TextCtrl.1.py new file mode 100644 index 00000000..37df47dd --- /dev/null +++ b/docs/sphinx/rest_substitutions/snippets/python/converted/TextCtrl.1.py @@ -0,0 +1,7 @@ + + text.SetDefaultStyle(wx.TextAttr(wx.RED)) + text.AppendText("Red text\n") + text.SetDefaultStyle(wx.TextAttr(wx.NullColour, wx.LIGHT_GREY)) + text.AppendText("Red on grey text\n") + text.SetDefaultStyle(wx.TextAttr(wx.BLUE)) + text.AppendText("Blue on grey text\n") diff --git a/docs/sphinx/rest_substitutions/snippets/python/converted/TimerEvent.1.py b/docs/sphinx/rest_substitutions/snippets/python/converted/TimerEvent.1.py new file mode 100644 index 00000000..c8cb533e --- /dev/null +++ b/docs/sphinx/rest_substitutions/snippets/python/converted/TimerEvent.1.py @@ -0,0 +1,19 @@ + + class MyFrame(wx.Frame): + + def __init__(self, parent): + + wx.Frame.__init__(self, parent) + + self.timer = wx.Timer(self, TIMER_ID) + self.Bind(wx.EVT_TIMER, self.OnTimer) + + self.timer.Start(1000) # 1 second interval + + + def OnTimer(self, event): + + # do whatever you want to do every second here + print 'Hello' + + diff --git a/docs/sphinx/rest_substitutions/snippets/python/converted/Validator.SetWindow.1.py b/docs/sphinx/rest_substitutions/snippets/python/converted/Validator.SetWindow.1.py new file mode 100644 index 00000000..7950c113 --- /dev/null +++ b/docs/sphinx/rest_substitutions/snippets/python/converted/Validator.SetWindow.1.py @@ -0,0 +1,3 @@ + + wx.TextCtrl(self, wx.ID_ANY, u'', wx.DefaultPosition, wx.DefaultSize, 0, + validator=MyValidator()) diff --git a/docs/sphinx/rest_substitutions/snippets/python/converted/Window.DoUpdateWindowUI.1.py b/docs/sphinx/rest_substitutions/snippets/python/converted/Window.DoUpdateWindowUI.1.py new file mode 100644 index 00000000..a388a604 --- /dev/null +++ b/docs/sphinx/rest_substitutions/snippets/python/converted/Window.DoUpdateWindowUI.1.py @@ -0,0 +1,13 @@ + + # do the window-specific processing after processing the update event + def DoUpdateWindowUI(self, event): + + if event.GetSetEnabled(): + self.Enable(event.GetEnabled()) + + if event.GetSetText(): + + if event.GetText() != self.GetTitle(): + self.SetTitle(event.GetText()) + + diff --git a/docs/sphinx/rest_substitutions/snippets/python/converted/Window.Fit.1.py b/docs/sphinx/rest_substitutions/snippets/python/converted/Window.Fit.1.py new file mode 100644 index 00000000..401ed691 --- /dev/null +++ b/docs/sphinx/rest_substitutions/snippets/python/converted/Window.Fit.1.py @@ -0,0 +1,2 @@ + + window.SetClientSize(child.GetSize()) diff --git a/docs/sphinx/rest_substitutions/snippets/python/converted/Window.HandleWindowEvent.1.py b/docs/sphinx/rest_substitutions/snippets/python/converted/Window.HandleWindowEvent.1.py new file mode 100644 index 00000000..f0c2c6e2 --- /dev/null +++ b/docs/sphinx/rest_substitutions/snippets/python/converted/Window.HandleWindowEvent.1.py @@ -0,0 +1,2 @@ + + GetEventHandler().SafelyProcessEvent(event) diff --git a/docs/sphinx/rest_substitutions/snippets/python/converted/Window.Move.1.py b/docs/sphinx/rest_substitutions/snippets/python/converted/Window.Move.1.py new file mode 100644 index 00000000..bdfe9905 --- /dev/null +++ b/docs/sphinx/rest_substitutions/snippets/python/converted/Window.Move.1.py @@ -0,0 +1,2 @@ + + self.SetSize(x, y, -1, -1, wx.SIZE_USE_EXISTING) diff --git a/docs/sphinx/rest_substitutions/snippets/python/converted/Window.Move.2.py b/docs/sphinx/rest_substitutions/snippets/python/converted/Window.Move.2.py new file mode 100644 index 00000000..bdfe9905 --- /dev/null +++ b/docs/sphinx/rest_substitutions/snippets/python/converted/Window.Move.2.py @@ -0,0 +1,2 @@ + + self.SetSize(x, y, -1, -1, wx.SIZE_USE_EXISTING) diff --git a/docs/sphinx/rest_substitutions/snippets/python/converted/Window.Move.3.py b/docs/sphinx/rest_substitutions/snippets/python/converted/Window.Move.3.py new file mode 100644 index 00000000..bdfe9905 --- /dev/null +++ b/docs/sphinx/rest_substitutions/snippets/python/converted/Window.Move.3.py @@ -0,0 +1,2 @@ + + self.SetSize(x, y, -1, -1, wx.SIZE_USE_EXISTING) diff --git a/docs/sphinx/rest_substitutions/snippets/python/converted/Window.ProcessEvent.1.py b/docs/sphinx/rest_substitutions/snippets/python/converted/Window.ProcessEvent.1.py new file mode 100644 index 00000000..fd31708d --- /dev/null +++ b/docs/sphinx/rest_substitutions/snippets/python/converted/Window.ProcessEvent.1.py @@ -0,0 +1,2 @@ + + self.GetEventHandler().ProcessEvent() diff --git a/docs/sphinx/rest_substitutions/snippets/python/converted/Window.ProcessWindowEvent.1.py b/docs/sphinx/rest_substitutions/snippets/python/converted/Window.ProcessWindowEvent.1.py new file mode 100644 index 00000000..a5d0604d --- /dev/null +++ b/docs/sphinx/rest_substitutions/snippets/python/converted/Window.ProcessWindowEvent.1.py @@ -0,0 +1,2 @@ + + self.GetEventHandler().ProcessEvent(event) diff --git a/docs/sphinx/rest_substitutions/snippets/python/converted/Window.PushEventHandler.1.py b/docs/sphinx/rest_substitutions/snippets/python/converted/Window.PushEventHandler.1.py new file mode 100644 index 00000000..acf01b22 --- /dev/null +++ b/docs/sphinx/rest_substitutions/snippets/python/converted/Window.PushEventHandler.1.py @@ -0,0 +1,3 @@ + + W.PushEventHandler(A) + W.PushEventHandler(B) diff --git a/docs/sphinx/rest_substitutions/snippets/python/converted/Window.SetMaxClientSize.1.py b/docs/sphinx/rest_substitutions/snippets/python/converted/Window.SetMaxClientSize.1.py new file mode 100644 index 00000000..349f9dfb --- /dev/null +++ b/docs/sphinx/rest_substitutions/snippets/python/converted/Window.SetMaxClientSize.1.py @@ -0,0 +1,2 @@ + + self.SetMaxSize(self.ClientToWindowSize(size)) diff --git a/docs/sphinx/rest_substitutions/snippets/python/converted/Window.SetMinClientSize.1.py b/docs/sphinx/rest_substitutions/snippets/python/converted/Window.SetMinClientSize.1.py new file mode 100644 index 00000000..bb7ea7b5 --- /dev/null +++ b/docs/sphinx/rest_substitutions/snippets/python/converted/Window.SetMinClientSize.1.py @@ -0,0 +1,2 @@ + + self.SetMinSize(self.ClientToWindowSize(size)) diff --git a/docs/sphinx/rest_substitutions/snippets/python/converted/Window.SetScrollbar.1.py b/docs/sphinx/rest_substitutions/snippets/python/converted/Window.SetScrollbar.1.py new file mode 100644 index 00000000..3ab3016b --- /dev/null +++ b/docs/sphinx/rest_substitutions/snippets/python/converted/Window.SetScrollbar.1.py @@ -0,0 +1,2 @@ + + self.SetScrollbar(wx.VERTICAL, 0, 16, 50) diff --git a/docs/sphinx/rest_substitutions/snippets/python/converted/Window.UpdateWindowUI.1.py b/docs/sphinx/rest_substitutions/snippets/python/converted/Window.UpdateWindowUI.1.py new file mode 100644 index 00000000..cfddf366 --- /dev/null +++ b/docs/sphinx/rest_substitutions/snippets/python/converted/Window.UpdateWindowUI.1.py @@ -0,0 +1,6 @@ + + def OnInternalIdle(self): + + if wx.UpdateUIEvent.CanUpdate(self): + self.UpdateWindowUI(wx.UPDATE_UI_FROMIDLE) + diff --git a/docs/sphinx/rest_substitutions/snippets/python/converted/WindowModalDialogEvent.Clone.1.py b/docs/sphinx/rest_substitutions/snippets/python/converted/WindowModalDialogEvent.Clone.1.py new file mode 100644 index 00000000..1fc0e19e --- /dev/null +++ b/docs/sphinx/rest_substitutions/snippets/python/converted/WindowModalDialogEvent.Clone.1.py @@ -0,0 +1,4 @@ + + def Clone(self): + + return MyEvent() diff --git a/docs/sphinx/rest_substitutions/snippets/python/converted/dataview.DataViewModel.1.py b/docs/sphinx/rest_substitutions/snippets/python/converted/dataview.DataViewModel.1.py new file mode 100644 index 00000000..b8419a77 --- /dev/null +++ b/docs/sphinx/rest_substitutions/snippets/python/converted/dataview.DataViewModel.1.py @@ -0,0 +1,7 @@ + + musicCtrl = wx.dataview.DataViewCtrl(self, wx.ID_ANY) + musicModel = MyMusicModel() + musicCtrl.AssociateModel(musicModel) + musicModel.DecRef() # avoid memory leak !! + + # add columns now diff --git a/docs/sphinx/rest_substitutions/snippets/python/converted/dataview.DataViewModel.2.py b/docs/sphinx/rest_substitutions/snippets/python/converted/dataview.DataViewModel.2.py new file mode 100644 index 00000000..74c8ab57 --- /dev/null +++ b/docs/sphinx/rest_substitutions/snippets/python/converted/dataview.DataViewModel.2.py @@ -0,0 +1,6 @@ + + musicCtrl = wx.dataview.DataViewCtrl(self, wx.ID_ANY) + musicModel = MyMusicModel() + musicCtrl.AssociateModel(musicModel.get()) + + # add columns now diff --git a/docs/sphinx/rest_substitutions/snippets/python/converted/dataview.DataViewRenderer.DisableEllipsize.1.py b/docs/sphinx/rest_substitutions/snippets/python/converted/dataview.DataViewRenderer.DisableEllipsize.1.py new file mode 100644 index 00000000..d6cbab59 --- /dev/null +++ b/docs/sphinx/rest_substitutions/snippets/python/converted/dataview.DataViewRenderer.DisableEllipsize.1.py @@ -0,0 +1,2 @@ + + EnableEllipsize(wx.ELLIPSIZE_NONE) diff --git a/docs/sphinx/rest_substitutions/snippets/python/converted/functions.DirSelector.1.py b/docs/sphinx/rest_substitutions/snippets/python/converted/functions.DirSelector.1.py new file mode 100644 index 00000000..429c74c5 --- /dev/null +++ b/docs/sphinx/rest_substitutions/snippets/python/converted/functions.DirSelector.1.py @@ -0,0 +1,6 @@ + + selector = wx.DirSelector("Choose a folder") + if selector.strip(): + # Do something with the folder name + print selector + diff --git a/docs/sphinx/rest_substitutions/snippets/python/converted/functions.FileSelector.1.py b/docs/sphinx/rest_substitutions/snippets/python/converted/functions.FileSelector.1.py new file mode 100644 index 00000000..b4e63dcb --- /dev/null +++ b/docs/sphinx/rest_substitutions/snippets/python/converted/functions.FileSelector.1.py @@ -0,0 +1,2 @@ + + wildcard = "BMP files (*.bmp)|*.bmp|GIF files (*.gif)|*.gif" diff --git a/docs/sphinx/rest_substitutions/snippets/python/converted/functions.FileSelector.2.py b/docs/sphinx/rest_substitutions/snippets/python/converted/functions.FileSelector.2.py new file mode 100644 index 00000000..f7571d72 --- /dev/null +++ b/docs/sphinx/rest_substitutions/snippets/python/converted/functions.FileSelector.2.py @@ -0,0 +1,8 @@ + + filename = wx.FileSelector("Choose a file to open") + + if filename.strip(): + # work with the file + print filename + + # else: cancelled by user diff --git a/docs/sphinx/rest_substitutions/snippets/python/converted/functions.Kill.1.py b/docs/sphinx/rest_substitutions/snippets/python/converted/functions.Kill.1.py new file mode 100644 index 00000000..15f2be95 --- /dev/null +++ b/docs/sphinx/rest_substitutions/snippets/python/converted/functions.Kill.1.py @@ -0,0 +1,20 @@ + + # Signal enumeration + + wx.SIGNONE # verify if the process exists under Unix + wx.SIGHUP + wx.SIGINT + wx.SIGQUIT + wx.SIGILL + wx.SIGTRAP + wx.SIGABRT + wx.SIGEMT + wx.SIGFPE + wx.SIGKILL # forcefully kill, dangerous! + wx.SIGBUS + wx.SIGSEGV + wx.SIGSYS + wx.SIGPIPE + wx.SIGALRM + wx.SIGTERM # terminate the process gently + diff --git a/docs/sphinx/rest_substitutions/snippets/python/converted/functions.Kill.2.py b/docs/sphinx/rest_substitutions/snippets/python/converted/functions.Kill.2.py new file mode 100644 index 00000000..b732d472 --- /dev/null +++ b/docs/sphinx/rest_substitutions/snippets/python/converted/functions.Kill.2.py @@ -0,0 +1,9 @@ + + # KillError enumeration + + wx.KILL_OK # no error + wx.KILL_BAD_SIGNAL # no such signal + wx.KILL_ACCESS_DENIED # permission denied + wx.KILL_NO_PROCESS # no such process + wx.KILL_ERROR # another, unspecified error + diff --git a/docs/sphinx/rest_substitutions/snippets/python/converted/functions.MessageBox.1.py b/docs/sphinx/rest_substitutions/snippets/python/converted/functions.MessageBox.1.py new file mode 100644 index 00000000..036b36fc --- /dev/null +++ b/docs/sphinx/rest_substitutions/snippets/python/converted/functions.MessageBox.1.py @@ -0,0 +1,5 @@ + + answer = wx.MessageBox("Quit program?", "Confirm", + wx.YES_NO | wx.CANCEL, main_frame) + if answer == wx.YES: + main_frame.Close() diff --git a/docs/sphinx/rest_substitutions/tables/ColourDatabase.1.rst b/docs/sphinx/rest_substitutions/tables/ColourDatabase.1.rst new file mode 100644 index 00000000..aec8b6a6 --- /dev/null +++ b/docs/sphinx/rest_substitutions/tables/ColourDatabase.1.rst @@ -0,0 +1,22 @@ +================================= ================================ ==================================== ================================== +``AQUAMARINE`` ``FIREBRICK`` ``MEDIUM FOREST GREEN`` ``RED`` +``BLACK`` ``FOREST GREEN`` ``MEDIUM GOLDENROD`` ``SALMON`` +``BLUE`` ``GOLD`` ``MEDIUM ORCHID`` ``SEA GREEN`` +``BLUE VIOLET`` ``GOLDENROD`` ``MEDIUM SEA GREEN`` ``SIENNA`` +``BROWN`` ``GREY`` ``MEDIUM SLATE BLUE`` ``SKY BLUE`` +``CADET BLUE`` ``GREEN`` ``MEDIUM SPRING GREEN`` ``SLATE BLUE`` +``CORAL`` ``GREEN YELLOW`` ``MEDIUM TURQUOISE`` ``SPRING GREEN`` +``CORNFLOWER BLUE`` ``INDIAN RED`` ``MEDIUM VIOLET RED`` ``STEEL BLUE`` +``CYAN`` ``KHAKI`` ``MIDNIGHT BLUE`` ``TAN`` +``DARK GREY`` ``LIGHT BLUE`` ``NAVY`` ``THISTLE`` +``DARK GREEN`` ``LIGHT GREY`` ``ORANGE`` ``TURQUOISE`` +``DARK OLIVE GREEN`` ``LIGHT STEEL BLUE`` ``ORANGE RED`` ``VIOLET`` +``DARK ORCHID`` ``LIME GREEN`` ``ORCHID`` ``VIOLET RED`` +``DARK SLATE BLUE`` ``MAGENTA`` ``PALE GREEN`` ``WHEAT`` +``DARK SLATE GREY`` ``MAROON`` ``PINK`` ``WHITE`` +``DARK TURQUOISE`` ``MEDIUM AQUAMARINE`` ``PLUM`` ``YELLOW`` +``DIM GREY`` ``MEDIUM BLUE`` ``PURPLE`` ``YELLOW GREEN`` +================================= ================================ ==================================== ================================== + +| + diff --git a/docs/sphinx/rest_substitutions/tables/Sizer.1.rst b/docs/sphinx/rest_substitutions/tables/Sizer.1.rst new file mode 100644 index 00000000..2508dc3d --- /dev/null +++ b/docs/sphinx/rest_substitutions/tables/Sizer.1.rst @@ -0,0 +1,49 @@ ++---------------------------------------------------------------------+-----------------------------------------------------------------------------+ +| Sizer Flag | Description | ++=====================================================================+=============================================================================+ +| ``TOP`` | These flags are used to specify which side(s) of the sizer | ++---------------------------------------------------------------------+ item the border width will apply to. | +| ``BOTTOM`` | | ++---------------------------------------------------------------------+ | +| ``LEFT`` | | ++---------------------------------------------------------------------+ | +| ``RIGHT`` | | ++---------------------------------------------------------------------+ | +| ``ALL`` | | ++---------------------------------------------------------------------+-----------------------------------------------------------------------------+ +| ``EXPAND`` | The item will be expanded to fill the space assigned to | +| | the item. | ++---------------------------------------------------------------------+-----------------------------------------------------------------------------+ +| ``SHAPED`` | The item will be expanded as much as possible while also | +| | maintaining its aspect ratio | ++---------------------------------------------------------------------+-----------------------------------------------------------------------------+ +| ``FIXED_MINSIZE`` | Normally `Sizers` will use | +| | :meth:`Window.GetAdjustedBestSize` to | +| | determine what the minimal size of window items should be, and will use that| +| | size to calculate the layout. This allows layouts to adjust when an item | +| | changes and its best size becomes different. If you would rather have a | +| | window item stay the size it started with then use ``FIXED_MINSIZE``. | ++---------------------------------------------------------------------+-----------------------------------------------------------------------------+ +| ``RESERVE_SPACE_EVEN_IF_HIDDEN`` | Normally `Sizers` don't allocate space for hidden windows or other items. | +| | This flag overrides this behavior so that sufficient space is allocated for | +| .. versionadded:: 2.8.8 | the window even if it isn't visible. This makes it possible to dynamically | +| | show and hide controls without resizing parent dialog, for example. | +| | Available since version 2.8.8 | ++---------------------------------------------------------------------+-----------------------------------------------------------------------------+ +| ``ALIGN_CENTER`` **or** ``ALIGN_CENTRE`` | The ``ALIGN*`` flags allow you to specify the alignment of the item | ++---------------------------------------------------------------------+ within the space allotted to it by the sizer, adjusted for the border if | +| ``ALIGN_LEFT`` | any. | ++---------------------------------------------------------------------+ | +| ``ALIGN_RIGHT`` | | ++---------------------------------------------------------------------+ | +| ``ALIGN_TOP`` | | ++---------------------------------------------------------------------+ | +| ``ALIGN_BOTTOM`` | | ++---------------------------------------------------------------------+ | +| ``ALIGN_CENTER_VERTICAL`` **or** ``ALIGN_CENTRE_VERTICAL`` | | ++---------------------------------------------------------------------+ | +| ``ALIGN_CENTER_HORIZONTAL`` **or** ``ALIGN_CENTRE_HORIZONTAL`` | | ++---------------------------------------------------------------------+-----------------------------------------------------------------------------+ + +| + diff --git a/docs/sphinx/rest_substitutions/tables/VScrolledWindow.1.rst b/docs/sphinx/rest_substitutions/tables/VScrolledWindow.1.rst new file mode 100644 index 00000000..e52adb49 --- /dev/null +++ b/docs/sphinx/rest_substitutions/tables/VScrolledWindow.1.rst @@ -0,0 +1,18 @@ +======================================= ============================================================================================================================================================================================================================================================================== +`GetFirstVisibleLine()` Deprecated for :meth:`~VarVScrollHelper.GetVisibleRowsBegin` +`GetLastVisibleLine()` Deprecated for :meth:`~VarVScrollHelper.GetVisibleRowsEnd` This function originally had a slight design flaw in that it was possible to return ``sys.maxint-1`` (ie: a large positive number) if the scroll position was 0 and the first line wasn't completely visible. +`GetLineCount()` Deprecated for :meth:`~VarVScrollHelper.GetRowCount` +`HitTest(x, y)` +`HitTest(pt)` Deprecated for :meth:`~VScrolledWindow.VirtualHitTest`. +`OnGetLineHeight(line)` Deprecated for :meth:`~VarVScrollHelper.OnGetRowHeight` +`OnGetLinesHint(lineMin, lineMax)` Deprecated for :meth:`~VarVScrollHelper.OnGetRowsHeightHint` +`RefreshLine(line)` Deprecated for :meth:`~VarVScrollHelper.RefreshRow` +`RefreshLines(from_, to_)` Deprecated for :meth:`~VarVScrollHelper.RefreshRows` +`ScrollLines(lines)` Deprecated for :meth:`~VarVScrollHelper.ScrollRows` +`ScrollPages(pages)` Deprecated for :meth:`~VarVScrollHelper.ScrollRowPages` +`ScrollToLine(line)` Deprecated for :meth:`~VarVScrollHelper.ScrollToRow` +`SetLineCount(count)` Deprecated for :meth:`~VarVScrollHelper.SetRowCount` +======================================= ============================================================================================================================================================================================================================================================================== + +| + diff --git a/etg/app.py b/etg/app.py index 8b116264..84704b80 100644 --- a/etg/app.py +++ b/etg/app.py @@ -127,7 +127,8 @@ def run(): # like normal, their docs will be able to be generated, etc. c.addItem(etgtools.MethodDef( protection='public', type='wxAppAssertMode', name='GetAssertMode', argsString='()', - briefDoc="Returns the current mode for how the application responds to wx asserts.")) + briefDoc="Returns the current mode for how the application responds to wx asserts.", + className=c.name)) m = etgtools.MethodDef( protection='public', type='void', name='SetAssertMode', argsString='(wxAppAssertMode mode)', @@ -135,13 +136,15 @@ def run(): Set the mode indicating how the application responds to wx assertion statements. Valid settings are a combination of these flags: - wx.APP_ASSERT_SUPPRESS - wx.APP_ASSERT_EXCEPTION - wx.APP_ASSERT_DIALOG - wx.APP_ASSERT_LOG + - wx.APP_ASSERT_SUPPRESS + - wx.APP_ASSERT_EXCEPTION + - wx.APP_ASSERT_DIALOG + - wx.APP_ASSERT_LOG The default behavior is to raise a wx.wxAssertionError exception. - """) + """, + className=c.name) + m.addItem(etgtools.ParamDef(type='wxAppAssertMode', name='wxAppAssertMode')) c.addItem(m) @@ -149,7 +152,8 @@ def run(): protection='public', isStatic=True, type='bool', name='IsDisplayAvailable', argsString='()', briefDoc="""\ Returns True if the application is able to connect to the system's - display, or whatever the equivallent is for the platform.""")) + display, or whatever the equivallent is for the platform.""", + className=c.name)) c.addProperty('AssertMode GetAssertMode SetAssertMode') diff --git a/etgtools/extractors.py b/etgtools/extractors.py index 4aa69994..de8244b9 100644 --- a/etgtools/extractors.py +++ b/etgtools/extractors.py @@ -18,6 +18,7 @@ import pprint import xml.etree.ElementTree as et from tweaker_tools import removeWxPrefix, magicMethods +from sphinxtools.utilities import FindDescendants #--------------------------------------------------------------------------- # These classes simply hold various bits of information about the classes, @@ -263,7 +264,7 @@ class FunctionDef(BaseDef): """ Use the given C++ code instead of that automatically generated by the back-end. This is similar to adding a new C++ method, except it uses - info we've alread received from the source XML such as the argument + info we've already received from the source XML such as the argument types and names, docstring, etc. The code generated for this verison will expect the given code to use @@ -278,7 +279,7 @@ class FunctionDef(BaseDef): """ Use the given C++ code instead of that automatically generated by the back-end. This is similar to adding a new C++ method, except it uses - info we've already received from the source XML such as the argument + info we've alread received from the source XML such as the argument types and names, docstring, etc. The code generated for this version will put the given code in a @@ -312,13 +313,13 @@ class FunctionDef(BaseDef): return o return None - + def hasOverloads(self): """ Returns True if there are any overloads that are not ignored. """ return bool([x for x in self.overloads if not x.ignored]) - + def ignore(self, val=True): # If the item being ignored has overloads then try to reorder the @@ -338,7 +339,6 @@ class FunctionDef(BaseDef): idx = parent.items.index(self) parent.items[idx] = first - def _findItems(self): items = list(self.items) @@ -526,6 +526,9 @@ class ClassDef(BaseDef): self.protection = '' self.templateParams = [] # class is a template self.bases = [] # base class names + self.subClasses = [] # sub classes + self.nodeBases = [] # for the inheritance diagram + self.enum_file = '' # To link sphinx output classes to enums self.includes = [] # .h file for this class self.abstract = False # is it an abstract base class? self.deprecated = False # mark all methods as deprecated @@ -553,19 +556,57 @@ class ClassDef(BaseDef): if element is not None: self.extract(element) + + def findHierarchy(self, element, all_classes, specials, read): + + from etgtools import XMLSRC + + if not read: + nodename = fullname = self.name + specials = [nodename] + else: + nodename = fullname = element.text + + baselist = [] + + if read: + refid = element.get('refid') + if refid is None: + return all_classes, specials + fname = os.path.join(XMLSRC, refid+'.xml') + root = et.parse(fname).getroot() + compounds = FindDescendants(root, 'basecompoundref') + else: + compounds = element.findall('basecompoundref') + + for c in compounds: + baselist.append(c.text) + + all_classes[nodename] = (nodename, fullname, baselist) + + for c in compounds: + all_classes, specials = self.findHierarchy(c, all_classes, specials, True) + + return all_classes, specials + + def extract(self, element): super(ClassDef, self).extract(element) + self.nodeBases = self.findHierarchy(element, {}, [], False) + for node in element.findall('basecompoundref'): - self.bases.append(node.text) + self.bases.append(node.text) + for node in element.findall('derivedcompoundref'): + self.subClasses.append(node.text) for node in element.findall('includes'): self.includes.append(node.text) for node in element.findall('templateparamlist/param'): txt = node.find('type').text txt = txt.replace('class ', '') self.templateParams.append(txt) - + for node in element.findall('innerclass'): if node.get('prot') == 'private': continue @@ -596,7 +637,7 @@ class ClassDef(BaseDef): v = MemberVarDef(node) self.items.append(v) elif kind == 'enum': - e = EnumDef(node) + e = EnumDef(node, [self]) self.items.append(e) elif kind == 'typedef': # callback function prototype, see wx/filedlg.h for an instance of this @@ -908,8 +949,9 @@ class EnumDef(BaseDef): """ A named or anonymous enumeration. """ - def __init__(self, element=None, inClass=False, **kw): + def __init__(self, element=None, inClass=[], **kw): super(EnumDef, self).__init__() + self.inClass = inClass if element is not None: prot = element.get('prot') if prot is not None: @@ -1056,6 +1098,7 @@ class PyCodeDef(BaseDef): self.order = order self.__dict__.update(kw) + #--------------------------------------------------------------------------- class PyFunctionDef(BaseDef): @@ -1069,12 +1112,13 @@ class PyFunctionDef(BaseDef): def __init__(self, name, argsString, body, doc=None, order=None, **kw): super(PyFunctionDef, self).__init__() self.name = name - self.argsString = argsString + self.argsString = self.pyArgsString = argsString self.body = body self.briefDoc = doc self.order = order self.deprecated = False self.isStatic = False + self.overloads = [] self.__dict__.update(kw) #--------------------------------------------------------------------------- @@ -1090,11 +1134,28 @@ class PyClassDef(BaseDef): super(PyClassDef, self).__init__() self.name = name self.bases = bases - self.briefDoc = doc + self.briefDoc = self.pyDocstring = doc + self.enum_file = '' + self.nodeBases = [] + self.subClasses = [] self.items.extend(items) self.deprecated = False self.order = order self.__dict__.update(kw) + + self.nodeBases = self.findHierarchy() + + + def findHierarchy(self): + + all_classes = {} + nodename = fullname = self.name + specials = [nodename] + + baselist = [base for base in self.bases if base != 'object'] + all_classes[nodename] = (nodename, fullname, baselist) + + return all_classes, specials #--------------------------------------------------------------------------- @@ -1197,10 +1258,15 @@ class ModuleDef(BaseDef): self.items.append(item) elif kind == 'enum': - extractingMsg(kind, element) - item = EnumDef(element) - self.items.append(item) + inClass = [] + for el in self.items: + if isinstance(el, ClassDef): + inClass.append(el) + extractingMsg(kind, element) + item = EnumDef(element, inClass) + self.items.append(item) + elif kind == 'variable': extractingMsg(kind, element) item = GlobalVarDef(element) @@ -1277,7 +1343,7 @@ class ModuleDef(BaseDef): order ) - + def addPyFunction(self, name, argsString, body, doc=None, order=None, **kw): """ Add a Python function to this module. @@ -1295,6 +1361,8 @@ class ModuleDef(BaseDef): self.items.append(pc) return pc + + #--------------------------------------------------------------------------- # Some helper functions and such #--------------------------------------------------------------------------- @@ -1310,7 +1378,7 @@ def flattenNode(node, rstrip=True): return node text = node.text or "" for n in node: - text += flattenNode(n) + text += flattenNode(n, rstrip) if node.tail: text += node.tail if rstrip: diff --git a/etgtools/generators.py b/etgtools/generators.py index 87862997..891b1365 100644 --- a/etgtools/generators.py +++ b/etgtools/generators.py @@ -31,6 +31,10 @@ class StubbedDocsGenerator(DocsGeneratorBase): pass +class SphinxGenerator(DocsGeneratorBase): + def generate(self, module): + pass + #--------------------------------------------------------------------------- # helpers diff --git a/etgtools/sphinx_generator.py b/etgtools/sphinx_generator.py index 0f3d45c8..e09d23a9 100644 --- a/etgtools/sphinx_generator.py +++ b/etgtools/sphinx_generator.py @@ -1,13 +1,3091 @@ +# -*- coding: utf-8 -*- +#!/usr/bin/env python + #--------------------------------------------------------------------------- # Name: etgtools/sphinx_generator.py -# Author: Robin Dunn +# Author: Andrea Gavana # -# Created: 3-Nov-2010 +# Created: 30-Nov-2010 # Copyright: (c) 2011 by Total Control Software # License: wxWindows License #--------------------------------------------------------------------------- +""" +This generator will create the docstrings for Sphinx to process, by refactoring +the various XML elements passed by the Phoenix extractors into ReST format. +""" -""" -This page is intentionally left blank, at least for now... -""" +# Standard library stuff +import os +import operator +import shutil +import textwrap + +from StringIO import StringIO + +import xml.etree.ElementTree as et + +# Phoenix-specific stuff +import extractors +import generators + +# Sphinx-Phoenix specific stuff +from sphinxtools.inheritance import InheritanceDiagram + +from sphinxtools import templates + +from sphinxtools.utilities import odict +from sphinxtools.utilities import ConvertToPython +from sphinxtools.utilities import RemoveWxPrefix, WriteSphinxOutput +from sphinxtools.utilities import FindControlImages, MakeSummary, PickleItem +from sphinxtools.utilities import ChopDescription, PythonizeType, Wx2Sphinx +from sphinxtools.utilities import PickleClassInfo, IsNumeric +from sphinxtools.utilities import Underscore2Capitals, CountSpaces + +from sphinxtools.constants import VERSION, REMOVED_LINKS, SECTIONS +from sphinxtools.constants import MAGIC_METHODS, MODULENAME_REPLACE +from sphinxtools.constants import IGNORE +from sphinxtools.constants import SPHINXROOT, DOXYROOT +from sphinxtools.constants import SNIPPETROOT, TABLEROOT, OVERVIEW_IMAGES_ROOT + + +# ----------------------------------------------------------------------- # + +class Node(object): + """ + This is the base class of all the subsequent classes in this script, and it + holds information about a XML element coming from doxygen and this `Node` + parent element (another `Node`). + """ + + # ----------------------------------------------------------------------- + + def __init__(self, element, parent): + """ + Class constructor. + + :param xml.etree.ElementTree.Element `element`: a XML element containing the + information coming from Doxygen. + :param Node `parent`: the parent node, or ``None``. + """ + + self.element = element + self.parent = parent + + self.children = [] + + if parent is not None: + parent.Add(self) + + + # ----------------------------------------------------------------------- + + def Add(self, node): + """ + Adds a node to its children list. + + :param Node `node`: another `Node` class. + """ + + self.children.append(node) + + + # ----------------------------------------------------------------------- + + def GetParent(self): + """ + Returns this node parent or ``None`` if it has no parent. + + :rtype: :class:`Node` + """ + + return self.parent + + + # ----------------------------------------------------------------------- + + def GetTopLevelParent(self): + """ + Returns the top level ancestor for this node or ``None``. If the ancestor + is not ``None``, then it should be an instance of :class:`Root`. + + :rtype: :class:`Node` + """ + + parent = self.parent + + while 1: + + if parent is None: + return + + if isinstance(parent, Root): + return parent + + parent = parent.parent + + + # ----------------------------------------------------------------------- + + def GetTag(self, tag_name): + """ + Given a `tag_name` for the element stored in this node, return the content + of that tag (or ``None`` if this element has no such tag). + + :param string `tag_name`: the element tag name. + + :returns: The element text for the input `tag_name` or ``None``. + """ + + if isinstance(self.element, basestring): + return None + + return self.element.get(tag_name) + + + # ----------------------------------------------------------------------- + + def GetHierarchy(self): + """ + Returns a list of strings representing this node hierarchy up to the :class:`Root` + node. + + :rtype: `list` + """ + + hierarchy = [self.__class__.__name__] + parent = self.parent + + while parent: + hierarchy.append(parent.__class__.__name__) + parent = parent.parent + + return hierarchy + + + # ----------------------------------------------------------------------- + + def IsClassDescription(self): + """ + Returns a non-empty string if this node holds information about a class general description + (i.e., its `element` attribute does not contain information on a method, a property, + and so on). + + This is needed to resolve ReST link conflicts in the :class:`XRef` below. + + :rtype: `string`. + """ + + top_level = self.GetTopLevelParent() + + if top_level is None: + return '' + + xml_docs = top_level.xml_docs + + if xml_docs.kind != 'class': + return '' + + dummy, class_name = Wx2Sphinx(xml_docs.class_name) + return class_name + + + # ----------------------------------------------------------------------- + + def Find(self, klass, node=None): + """ + This method returns ``True`` if this node contains a specific class into its + descendants. + + :param `klass`: can be any of the classes definied in this script except :class:`XMLDocString`. + :param `node`: another `Node` instance or ``None`` if this is the first invocation of + this function. + + :rtype: `bool` + + .. note:: This is a recursive method. + + """ + + + if node is None: + node = self + + for child in node.children: + if isinstance(child, klass): + return True + + return self.Find(klass, child) + + return False + + + # ----------------------------------------------------------------------- + + def GetSpacing(self): + + hierarchy = self.GetHierarchy() + if 'ParameterList' in hierarchy: + return ' ' + + elif not isinstance(self, ListItem) and 'List' in hierarchy: + return ' '*2 + + return '' + + + # ----------------------------------------------------------------------- + + def Join(self, with_tail=True): + """ + Join this node `element` attribute text and tail, adding all its children's + node text and tail in the meanwhile. + + :param `with_tail`: ``True`` if the element tail should be included in the + text, ``False`` otherwise. + + :rtype: `string` + + :returns: A string containing the ReSTified version of this node `element` text and + tail plus all its children's element text and tail. + + .. note:: For some of the classes in this script (for example the :class:`Emphasis`, + :class:`ComputerOutput`) the `with_tail` parameter should be set to ``False`` in order + to avoid wrong ReST output. + """ + + text = tail = '' + + if self.element is None: + return text + + if isinstance(self.element, basestring): + text = self.element + else: + text, tail = self.element.text, self.element.tail + text = (text is not None and [text] or [''])[0] + tail = (tail is not None and [tail] or [''])[0] + + if text.strip() in REMOVED_LINKS: + return '' + + text = ConvertToPython(text) + + for child in self.children: + text += child.Join(with_tail) + + if with_tail and tail: + text += ConvertToPython(tail) + + if text.strip() and not text.endswith('\n'): + text += ' ' + + return text + + +# ----------------------------------------------------------------------- # + +class Root(Node): + """ + This is the root class which has as its children all the other classes in + this script (excluding :class:`XMLDocString`). It is used to hold information + about an XML Doxygen item describing a class, a method or a function. + """ + + # ----------------------------------------------------------------------- + + def __init__(self, xml_docs, is_overload, share_docstrings): + """ + Class constructor. + + :param XMLDocString `xml_docs`: an instance of :class:`XMLDocString`. + :param bool `is_overload`: ``True`` if the root node describes an overloaded + method/function, ``False`` otherwise. + :param bool `share_docstrings`: ``True`` if all the overloaded methods/functions + share the same docstrings. + """ + + Node.__init__(self, '', None) + + self.xml_docs = xml_docs + self.is_overload = is_overload + self.share_docstrings = share_docstrings + + self.sections = odict() + + + # ----------------------------------------------------------------------- + + def Insert(self, node, before=None, after=None, dontcare=True): + """ + Inserts a node into the root children, depending of the `before` and `after` + input arguments. + """ + + insert_at = -1 + + for index, child in enumerate(self.children): + if (before and child.Find(before)) or (after and child.Find(after)): + insert_at = index + break + + node.parent = self + + if insert_at >= 0: + if before: + self.children.insert(insert_at, node) + else: + self.children.insert(insert_at+1, node) + else: + if dontcare: + self.children.append(node) + else: + return False + + return True + + + # ----------------------------------------------------------------------- + + def Join(self, with_tail=True): + """ + Join this node `element` attribute text and tail, adding all its children's + node text and tail in the meanwhile. + + :param `with_tail`: ``True`` if the element tail should be included in the + text, ``False`` otherwise. + + :rtype: `string` + + :returns: A string containing the ReSTified version of this node `element` text and + tail plus all its children's element text and tail. + + .. note:: For some of the classes in this script (for example the :class:`Emphasis`, + :class:`ComputerOutput`) the `with_tail` parameter should be set to ``False`` in order + to avoid wrong ReST output. + """ + + if self.is_overload and self.share_docstrings: + # If it is an overloaded method and the docstrings are shared, we only return + # information about the parameter list and admonition sections + return self.CommonJoin(self, '') + + text = Node.Join(self, with_tail) + + # Health check + existing_sections = self.sections.keys()[:] + + for section_name, dummy in SECTIONS: + if section_name not in self.sections: + continue + + existing_sections.remove(section_name) + for section in self.sections[section_name]: + text += '\n\n%s\n\n' % section.Join() + + # Health check + if any(existing_sections): + raise Exception('Unconverted sections remain: %s'%(', '.join(existing_sections))) + + return text + + + # ----------------------------------------------------------------------- + + def CommonJoin(self, node, docstrings): + """ + Selectively join this node `element` attribute text and tail, adding all its children's + node text and tail in the meanwhile but only if they are instances of :class:`ParameterList` + or :class:`Section`. + + :param `node`: either `self` or a child node. + :param string `docstrings`: the resulting docstrings obtained (they will go as output as well). + + :rtype: `string` + + .. note:: This is a recursive method. + """ + + for child in node.children: + if isinstance(child, (ParameterList, Section)): + docstrings += child.Join() + + docstrings = self.CommonJoin(child, docstrings) + + return docstrings + + + # ----------------------------------------------------------------------- + + def AddSection(self, section): + """ + Adds an admonition section to the root node (i.e., `.. seealso::`, `.. note::`, + `:returns:` and so on). + + Admonitions are somewhat different from other nodes as they need to be refactored and + handled differently when, for example, the return value of a method is different in Phoenix + than in wxWidgets or when the XML docs are a mess and an admonition ends up into + a tail of an xml element... + + :param Section `section`: an instance of :class:`Section`. + + """ + + kind = section.section_type + + if kind == 'return': + self.sections[kind] = [section] + + elif kind == 'available': + + if kind not in self.sections: + + text = section.element.text + text = text.split(',') + newtext = [] + for t in text: + newtext.append(t[2:].upper()) + + newtext = ', '.join(newtext) + newtext = 'Only available for %s'%newtext + + if section.element.tail and section.element.tail.strip(): + newtext += ' ' + section.element.tail.strip() + ' ' + else: + newtext += '. ' + + section.element.text = newtext + self.sections[kind] = [section] + + else: + + prevsection = self.sections[kind][0] + prevtext = prevsection.element.text + + currtext = section.element.text + + pos = 1000 + if '.' in currtext: + pos = currtext.index('.') + + if currtext and currtext.strip(): + prevtext = prevtext + currtext[pos+1:].strip() + + prevsection.element.text = prevtext + self.sections[kind] = [prevsection] + + + else: + if kind not in self.sections: + self.sections[kind] = [] + + self.sections[kind].append(section) + + +# ----------------------------------------------------------------------- # + +class ParameterList(Node): + """ + This class holds information about XML elements with a ```` tag. + """ + + # ----------------------------------------------------------------------- + + def __init__(self, element, parent, xml_item, kind): + """ + Class constructor. + + :param xml.etree.ElementTree.Element `element`: a XML element containing the + information coming from Doxygen about the ```` tag + :param Node `parent`: the parent node, must not be ``None`` + :param `xml_item`: one of the classes available in `etgtools/extractors.py`, such as + `PyMethodDef`, `PyFunctionDef` and so on + :param string `kind`: one of `class`, `method`, `function`. + """ + + Node.__init__(self, element, parent) + + self.xml_item = xml_item + self.kind = kind + + self.checked = False + self.py_parameters = odict() + + for pdef in xml_item.items: + + if pdef.out: + continue + + name = pdef.name + parameter = Parameter(self, pdef) + self.py_parameters[name] = parameter + + + # ----------------------------------------------------------------------- + + def Get(self, element_name): + """ + Returns an instance of :class:`Parameter` if this parameter name (retrieved using + the input `element_name`) is actually in the list of parameters held by this class. + + :param string `element_name`: the parameter name. + + :rtype: :class:`Parameter` or ``None`` + + .. note:: Very often the list of parameters in wxWidgets does not match the Phoenix Python + signature, as some of the parameters in Python get merged into one or removed altogether. + + """ + + name = element_name.strip() + + if name not in self.py_parameters: + return + + return self.py_parameters[name] + + + # ----------------------------------------------------------------------- + + def CheckSignature(self): + """ + Checks if the function/method signature for items coming from pure C++ implementation + matches the parameter list itself. + + This is mostly done as health check, as there are some instances (like `wx.Locale.Init`) + for which the function signature does not match the parameter list (see, for example, + the `shortName` parameter in the signature against the `name` in the parameter list). + + These kind of mismatches can sometimes break the ReST docstrings. + """ + + if self.checked: + return + + self.checked = True + xml_item = self.xml_item + + if isinstance(xml_item, (extractors.PyFunctionDef, extractors.CppMethodDef)): + return + + name = xml_item.name or xml_item.pyName + name = RemoveWxPrefix(name) + + is_overload = self.GetTopLevelParent().is_overload + + if xml_item.overloads and not is_overload: + return + + arguments = xml_item.pyArgsString + if not arguments: + return + + if hasattr(xml_item, 'isStatic') and not xml_item.isStatic: + if arguments[:2] == '()': + return + + arguments = arguments[1:] + + if '->' in arguments: + arguments, dummy = arguments.split("->") + + arguments = arguments.strip() + if arguments.endswith(','): + arguments = arguments[0:-1] + + if arguments.startswith('('): + arguments = arguments[1:] + if arguments.endswith(')'): + arguments = arguments[0:-1] + + signature = name + '(%s)'%arguments + arguments = arguments.split(',') + py_parameters = self.py_parameters.keys() + + message = '\nSEVERE: Incompatibility between function/method signature and list of parameters in `%s`:\n\n' \ + 'The parameter `%s` appears in the method signature but could not be found in the parameter list.\n\n' \ + ' ==> Function/Method signature from `extractors`: %s\n' \ + ' ==> Parameter list from wxWidgets XML items: %s\n\n' \ + 'This may be a documentation bug in wxWidgets or a side-effect of removing the `wx` prefix from signatures.\n\n' + + for arg in arguments: + + if '*' in arg or ')' in arg: + continue + + arg = arg.split('=')[0].strip() + + if arg and arg not in py_parameters: + + class_name = '' + if hasattr(xml_item, 'className') and xml_item.className is not None: + class_name = Wx2Sphinx(xml_item.className)[1] + '.' + + print message % (class_name + name, arg, signature, py_parameters) + + + # ----------------------------------------------------------------------- + + def Join(self, with_tail=True): + """ + Join this node `element` attribute text and tail, adding all its children's + node text and tail in the meanwhile. + + :param `with_tail`: ``True`` if the element tail should be included in the + text, ``False`` otherwise. + + :rtype: `string` + + :returns: A string containing the ReSTified version of this node `element` text and + tail plus all its children's element text and tail. + + .. note:: For some of the classes in this script (for example the :class:`Emphasis`, + :class:`ComputerOutput`) the `with_tail` parameter should be set to ``False`` in order + to avoid wrong ReST output. + """ + + docstrings = '' + + for name, parameter in self.py_parameters.items(): + docstrings += ':param %s `%s`: %s\n'%(parameter.type, name, parameter.Join().lstrip('\n')) + + if docstrings: + docstrings = '\n\n\n%s\n\n'%docstrings + + for child in self.children: + if not isinstance(child, Parameter): + docstrings += child.Join() + '\n\n' + + return docstrings + + +# ----------------------------------------------------------------------- # + +class Parameter(Node): + """ + This class holds information about XML elements with ```` + ```` tags. + """ + + # ----------------------------------------------------------------------- + + def __init__(self, parent, pdef): + """ + Class constructor. + + :param Node `parent`: the parent node, must not be ``None`` + :param `pdef`: a `ParamDef` class, as described in `etgtools/extractors.py`. + """ + + Node.__init__(self, '', parent) + + self.pdef = pdef + self.name = pdef.name + + self.type = PythonizeType(pdef.type) + + +# ----------------------------------------------------------------------- # + +class Paragraph(Node): + """ + This class holds information about XML elements with a ```` tag. + """ + + # ----------------------------------------------------------------------- + + def __init__(self, element, parent, kind): + """ + Class constructor. + + :param xml.etree.ElementTree.Element `element`: a XML element containing the + information coming from Doxygen about the ```` tag + :param Node `parent`: the parent node, must not be ``None`` + :param string `kind`: one of `class`, `method`, `function`. + """ + + Node.__init__(self, element, parent) + + self.kind = kind + + + # ----------------------------------------------------------------------- + + def Join(self, with_tail=True): + """ + Join this node `element` attribute text and tail, adding all its children's + node text and tail in the meanwhile. + + :param `with_tail`: ``True`` if the element tail should be included in the + text, ``False`` otherwise. + + :rtype: `string` + + :returns: A string containing the ReSTified version of this node `element` text and + tail plus all its children's element text and tail. + + .. note:: For some of the classes in this script (for example the :class:`Emphasis`, + :class:`ComputerOutput`) the `with_tail` parameter should be set to ``False`` in order + to avoid wrong ReST output. + """ + + text = Node.Join(self, with_tail) + + if 'Availability:' not in text: + return text + + newtext = '' + + for line in text.splitlines(): + + if 'Availability:' in line: + + first = line.index('Availability:') + + element = et.Element('available', kind='available') + element.text = line[first+13:] + + section = Section(element, None, self.kind) + + root = self.GetTopLevelParent() + root.AddSection(section) + + else: + + newtext += line + '\n' + + return newtext + + +# ----------------------------------------------------------------------- # + +class ReturnType(Node): + """ + A special admonition section to customize the `:rtype:` ReST role from + the XML / Python description. + """ + + # ----------------------------------------------------------------------- + + def __init__(self, element, parent): + """ + Class constructor. + + :param xml.etree.ElementTree.Element `element`: a XML element + :param Node `parent`: the parent node, must not be ``None`` + """ + + Node.__init__(self, element, parent) + + + # ----------------------------------------------------------------------- + + def Join(self, with_tail=True): + """ + Join this node `element` attribute text and tail, adding all its children's + node text and tail in the meanwhile. + + :param `with_tail`: ``True`` if the element tail should be included in the + text, ``False`` otherwise. + + :rtype: `string` + + :returns: A string containing the ReSTified version of this node `element` text and + tail plus all its children's element text and tail. + + .. note:: For some of the classes in this script (for example the :class:`Emphasis`, + :class:`ComputerOutput`) the `with_tail` parameter should be set to ``False`` in order + to avoid wrong ReST output. + """ + + docstrings = '\n\n:rtype: %s\n\n' % self.element + + return docstrings + + +# ----------------------------------------------------------------------- # + +class List(Node): + """ + This class holds information about XML elements with the ```` + and ```` tags. + """ + + # ----------------------------------------------------------------------- + + def __init__(self, element, parent): + """ + Class constructor. + + :param xml.etree.ElementTree.Element `element`: a XML element containing the + information coming from Doxygen about the ```` and ```` tags + :param Node `parent`: the parent node, must not be ``None`` + """ + + Node.__init__(self, element, parent) + + + # ----------------------------------------------------------------------- + + def Join(self, with_tail=True): + """ + Join this node `element` attribute text and tail, adding all its children's + node text and tail in the meanwhile. + + :param `with_tail`: ``True`` if the element tail should be included in the + text, ``False`` otherwise. + + :rtype: `string` + + :returns: A string containing the ReSTified version of this node `element` text and + tail plus all its children's element text and tail. + + .. note:: For some of the classes in this script (for example the :class:`Emphasis`, + :class:`ComputerOutput`) the `with_tail` parameter should be set to ``False`` in order + to avoid wrong ReST output. + """ + + docstrings = Node.Join(self, with_tail=False) + docstrings = '\n\n%s\n'%docstrings + + if self.element.tail: + spacer = ('ParameterList' in self.GetHierarchy() and [' '] or [''])[0] + text = '%s%s\n'%(spacer, ConvertToPython(self.element.tail.strip())) + docstrings += text + + return docstrings + + +# ----------------------------------------------------------------------- # + +class ListItem(Node): + """ + This class holds information about XML elements with the ```` tag. + """ + + # ----------------------------------------------------------------------- + + def __init__(self, element, parent): + """ + Class constructor. + + :param xml.etree.ElementTree.Element `element`: a XML element containing the + information coming from Doxygen about the ```` tag + :param Node `parent`: the parent node, must not be ``None`` + """ + + Node.__init__(self, element, parent) + + self.level = parent.GetHierarchy().count('List') - 1 + + + # ----------------------------------------------------------------------- + + def GetSpacing(self): + + hierarchy = self.GetHierarchy() + + if 'ParameterList' in hierarchy: + return ' ' + + elif 'Section' in hierarchy: + return ' '*3 + + return ' ' * self.level + + + # ----------------------------------------------------------------------- + + def Join(self, with_tail=True): + """ + Join this node `element` attribute text and tail, adding all its children's + node text and tail in the meanwhile. + + :param `with_tail`: ``True`` if the element tail should be included in the + text, ``False`` otherwise. + + :rtype: `string` + + :returns: A string containing the ReSTified version of this node `element` text and + tail plus all its children's element text and tail. + + .. note:: For some of the classes in this script (for example the :class:`Emphasis`, + :class:`ComputerOutput`) the `with_tail` parameter should be set to ``False`` in order + to avoid wrong ReST output. + """ + + spacer = self.GetSpacing() + + to_remove = ['(id, event, func)', '(id1, id2, event, func)', '(id1, id2, func)', + '(id, func)', '(func)', + '(id, event, func)', '(id1, id2, event, func)', '(id1, id2, func)', + '(id, func)'] + + docstrings = '' + + for child in self.children: + child_text = child.Join(with_tail) + for rem in to_remove: + child_text = child_text.replace(rem, '') + + if '_:' in child_text: + child_text = child_text.replace('_:', '_*:') + + docstrings += child_text + + docstrings = '%s- %s\n'%(spacer, docstrings) + return docstrings + + +# ----------------------------------------------------------------------- # + +class Section(Node): + """ + This class holds information about XML elements with the ```` and + ```` tags. + """ + + # ----------------------------------------------------------------------- + + def __init__(self, element, parent, kind, is_overload=False, share_docstrings=False): + """ + Class constructor. + + :param xml.etree.ElementTree.Element `element`: a XML element containing the + information coming from Doxygen about the ```` and ```` tags + :param Node `parent`: the parent node, can be ``None`` + :param string `kind`: one of `class`, `method`, `function` + :param bool `is_overload`: ``True`` if the root node describes an overloaded + method/function, ``False`` otherwise. + :param bool `share_docstrings`: ``True`` if all the overloaded methods/functions + share the same docstrings. + """ + + Node.__init__(self, element, parent) + + self.kind = kind + self.is_overload = is_overload + self.share_docstrings = share_docstrings + + dummy, section_type = self.element.items()[0] + self.section_type = section_type.split("_")[0] + + + # ----------------------------------------------------------------------- + + def Join(self, with_tail=True): + """ + Join this node `element` attribute text and tail, adding all its children's + node text and tail in the meanwhile. + + :param `with_tail`: ``True`` if the element tail should be included in the + text, ``False`` otherwise. + + :rtype: `string` + + :returns: A string containing the ReSTified version of this node `element` text and + tail plus all its children's element text and tail. + + .. note:: For some of the classes in this script (for example the :class:`Emphasis`, + :class:`ComputerOutput`) the `with_tail` parameter should be set to ``False`` in order + to avoid wrong ReST output. + """ + + section_type = self.section_type + + text = Node.Join(self, with_tail=False) + + if not text.strip() or len(text.strip()) < 3: + # Empy text or just trailing commas + return '' + + if self.is_overload and self.share_docstrings: + return '' + + sub_spacer = ' '*3 + + if section_type == 'since': + # Special treatment for the versionadded + if len(text) > 6: + version, remainder = text[0:6], text[6:] + text = '%s\n%s%s'%(version, sub_spacer, remainder) + + elif section_type == 'deprecated': + # Special treatment for deprecated, wxWidgets devs do not put the version number + text = '%s\n%s%s'%(VERSION, sub_spacer, text.lstrip('Deprecated')) + + if section_type in ['note', 'remark', 'remarks', 'return']: + text = '\n\n' + sub_spacer + text + + for section, replacement in SECTIONS: + if section == section_type: + break + + docstrings = '' + section_spacer = '' + + if section_type != 'return': + section_spacer = self.GetSpacing() + + docstrings = '\n%s%s %s\n\n'%(section_spacer, replacement, text) + + return '\n' + docstrings + + +# ----------------------------------------------------------------------- # + +class Image(Node): + """ + This class holds information about XML elements with the ```` tag. + """ + + # ----------------------------------------------------------------------- + + def __init__(self, element, parent): + """ + Class constructor. + + :param xml.etree.ElementTree.Element `element`: a XML element containing the + information coming from Doxygen about the ```` tag + :param Node `parent`: the parent node, must not be ``None`` + """ + + Node.__init__(self, element, parent) + + + # ----------------------------------------------------------------------- + + def Join(self, with_tail=True): + """ + Join this node `element` attribute text and tail, adding all its children's + node text and tail in the meanwhile. + + :param `with_tail`: ``True`` if the element tail should be included in the + text, ``False`` otherwise. + + :rtype: `string` + + :returns: A string containing the ReSTified version of this node `element` text and + tail plus all its children's element text and tail. + + .. note:: For some of the classes in this script (for example the :class:`Emphasis`, + :class:`ComputerOutput`) the `with_tail` parameter should be set to ``False`` in order + to avoid wrong ReST output. + """ + + for key, value in self.element.items(): + if key == 'name': + break + + image_path = os.path.normpath(os.path.join(DOXYROOT, 'images', value)) + static_path = os.path.join(OVERVIEW_IMAGES_ROOT, os.path.split(image_path)[1]) + + if not os.path.isfile(static_path): + shutil.copyfile(image_path, static_path) + + rel_path_index = static_path.rfind('_static') + rel_path = os.path.normpath(static_path[rel_path_index:]) + + docstrings = '\n\n' + docstrings += '.. figure:: %s\n' % rel_path + docstrings += ' :align: center\n\n\n' + docstrings += '|\n\n' + + if self.element.tail and self.element.tail.strip(): + docstrings += ConvertToPython(self.element.tail.rstrip()) + + return docstrings + +# ----------------------------------------------------------------------- # + +class Table(Node): + """ + This class holds information about XML elements with the ```` tag. + """ + + # ----------------------------------------------------------------------- + + def __init__(self, element, parent, xml_item_name): + """ + Class constructor. + + :param xml.etree.ElementTree.Element `element`: a XML element containing the + information coming from Doxygen about the ``
    `` tag + :param Node `parent`: the parent node, must not be ``None`` + :param string `xml_item_name`: if a custom version of a table has been created + inside the ``TABLEROOT`` folder, the `xml_item_name` string will match the + ``*.rst`` file name for the custom table. + + .. note:: + + There are 3 customized versions of 3 XML tables up to now, for various reasons: + + 1. The `wx.Sizer` flags table is a flexible grid table, very difficult to ReSTify automatically + 2. The `wx.ColourDatabase` table of colour comes up all messy when ReSTified from XML + 3. The "wxWidgets 2.8 Compatibility Functions" table for `wx.VScrolledWindow` + + """ + + Node.__init__(self, element, parent) + + self.xml_item_name = xml_item_name + + + # ----------------------------------------------------------------------- + + def Join(self, with_tail=True): + """ + Join this node `element` attribute text and tail, adding all its children's + node text and tail in the meanwhile. + + :param `with_tail`: ``True`` if the element tail should be included in the + text, ``False`` otherwise. + + :rtype: `string` + + :returns: A string containing the ReSTified version of this node `element` text and + tail plus all its children's element text and tail. + + .. note:: For some of the classes in this script (for example the :class:`Emphasis`, + :class:`ComputerOutput`) the `with_tail` parameter should be set to ``False`` in order + to avoid wrong ReST output. + """ + + needs_space = 'ParameterList' in self.GetHierarchy() + spacer = (needs_space and [' '] or [''])[0] + + rows, cols = int(self.element.get('rows')), int(self.element.get('cols')) + + longest = [0]*cols + has_title = False + + count = 0 + for row in xrange(rows): + for col in xrange(cols): + child = self.children[count] + + text = child.Join(with_tail) + longest[col] = max(len(text), longest[col]) + + if (row == 0 and col == 0 and '**' in text) or child.GetTag('thead') == 'yes': + has_title = True + + count += 1 + + table = '\n\n' + table += spacer + formats = [] + + for lng in longest: + table += '='* lng + ' ' + formats.append('%-' + '%ds'%(lng+1)) + + table += '\n' + + count = 0 + + for row in xrange(rows): + + table += spacer + + for col in xrange(cols): + table += formats[col] % (self.children[count].Join(with_tail).strip()) + count += 1 + + table += '\n' + + if row == 0 and has_title: + + table += spacer + + for lng in longest: + table += '='* lng + ' ' + + table += '\n' + + table += spacer + + for lng in longest: + table += '='* lng + ' ' + + table += '\n\n%s|\n\n'%spacer + + possible_rest_input = os.path.join(TABLEROOT, self.xml_item_name) + + if os.path.isfile(possible_rest_input): + table = '\n\n' + spacer + '.. include:: %s\n\n'%possible_rest_input + + if self.element.tail and self.element.tail.strip(): + table += ConvertToPython(self.element.tail.rstrip()) + + return table + +# ----------------------------------------------------------------------- # + +class TableEntry(Node): + """ + This class holds information about XML elements with the ```` tag. + """ + pass + +# ----------------------------------------------------------------------- # + +class Snippet(Node): + """ + This class holds information about XML elements with the ````, + ````, ````, ```` and ```` (but only when the + ```` tags appears as a child of ````) tags. + """ + + # ----------------------------------------------------------------------- + + def __init__(self, element, parent, cpp_file, python_file, converted_py): + """ + Class constructor. + + :param xml.etree.ElementTree.Element `element`: a XML element containing the + information coming from Doxygen about the aforementioned tags + :param Node `parent`: the parent node, must not be ``None`` + :param string `cpp_file`: the path to the C++ snippet of code found in the XML + wxWidgets docstring, saved into the ``SNIPPETROOT/cpp`` folder + :param string `python_file`: the path to the roughly-converted to Python + snippet of code found in the XML wxWidgets docstring, saved into the + ``SNIPPETROOT/python`` folder + :param string `converted_py`: the path to the fully-converted to Python + snippet of code found in the XML wxWidgets docstring, saved into the + ``SNIPPETROOT/python/converted`` folder. + """ + + Node.__init__(self, element, parent) + + self.cpp_file = cpp_file + self.python_file = python_file + self.converted_py = converted_py + + self.snippet = '' + + + # ----------------------------------------------------------------------- + + def AddCode(self, element): + """ + Adds a C++ part of the code snippet. + + :param xml.etree.ElementTree.Element `element`: a XML element containing the + information coming from Doxygen about the aforementioned tags. + """ + + tag = element.tag + + if tag == 'codeline': + self.snippet += '\n' + + elif tag in ['highlight', 'ref', 'sp']: + + if tag == 'sp': + self.snippet += ' ' + + if isinstance(element, basestring): + self.snippet += element + else: + if element.text: + self.snippet += element.text.strip(' ') + if element.tail: + self.snippet += element.tail.strip(' ') + + else: + raise Exception('Unhandled tag in class Snippet: %s'%tag) + + + # ----------------------------------------------------------------------- + + def Join(self, with_tail=True): + """ + Join this node `element` attribute text and tail, adding all its children's + node text and tail in the meanwhile. + + :param `with_tail`: ``True`` if the element tail should be included in the + text, ``False`` otherwise. + + :rtype: `string` + + :returns: A string containing the ReSTified version of this node `element` text and + tail plus all its children's element text and tail. + + .. note:: For some of the classes in this script (for example the :class:`Emphasis`, + :class:`ComputerOutput`) the `with_tail` parameter should be set to ``False`` in order + to avoid wrong ReST output. + """ + + docstrings = '' + + fid = open(self.cpp_file, 'wt') + fid.write(self.snippet) + fid.close() + + if not os.path.isfile(self.converted_py): + + message = '\nWARNING: Missing C++ => Python conversion of the snippet of code for %s'%(os.path.split(self.cpp_file)[1]) + message += '\n\nA slightly Pythonized version of this snippet has been saved into:\n\n ==> %s\n\n'%self.python_file + + print message + + py_code = self.snippet.replace(';', '') + py_code = py_code.replace('{', '').replace('}', '') + py_code = py_code.replace('->', '.').replace('//', '#') + py_code = py_code.replace('m_', 'self.') + py_code = py_code.replace('::', '.') + py_code = py_code.replace('wx', 'wx.') + py_code = py_code.replace('new ', '').replace('this', 'self') + py_code = py_code.replace('( ', '(').replace(' )', ')') + py_code = py_code.replace('||', 'or').replace('&&', 'and') + + spacer = ' '*4 + new_py_code = '' + + for code in py_code.splitlines(): + new_py_code += spacer + code + '\n' + + fid = open(self.python_file, 'wt') + fid.write(new_py_code) + fid.close() + + else: + + fid = open(self.converted_py, 'rt') + + while 1: + tline = fid.readline() + if not tline.strip(): + continue + + code = tline + fid.read() + fid.close() + break + + docstrings += '::\n\n' + docstrings += code.rstrip() + '\n\n' + + if self.element.tail and len(self.element.tail.strip()) > 1: + spacer = ('Section' in self.GetHierarchy() and [' '] or [''])[0] + tail = ConvertToPython(self.element.tail.lstrip()) + tail = tail.replace('\n', ' ') + docstrings += spacer + tail.replace(' ', ' ') + + return docstrings + + +# ----------------------------------------------------------------------- # + +class XRef(Node): + """ + This class holds information about XML elements with the ```` tag, excluding + when these elements are children of a ```` element. + """ + + # ----------------------------------------------------------------------- + + def __init__(self, element, parent): + """ + Class constructor. + + :param xml.etree.ElementTree.Element `element`: a XML element containing the + information coming from Doxygen about the aforementioned tags + :param Node `parent`: the parent node, must not be ``None``. + """ + + Node.__init__(self, element, parent) + + + # ----------------------------------------------------------------------- + + def Join(self, with_tail=True): + """ + Join this node `element` attribute text and tail, adding all its children's + node text and tail in the meanwhile. + + :param `with_tail`: ``True`` if the element tail should be included in the + text, ``False`` otherwise. + + :rtype: `string` + + :returns: A string containing the ReSTified version of this node `element` text and + tail plus all its children's element text and tail. + + .. note:: For some of the classes in this script (for example the :class:`Emphasis`, + :class:`ComputerOutput`) the `with_tail` parameter should be set to ``False`` in order + to avoid wrong ReST output. + """ + + element = self.element + text = element.text + + tail = element.tail + tail = (tail is not None and [tail] or [''])[0] + + hascomma = '::' in text + + original = text + text = RemoveWxPrefix(text) + text = text.replace("::", ".") + + if "(" in text: + text = text[0:text.index("(")] + + refid, link = element.items()[0] + remainder = link.split('_')[-1] + + space_before, space_after = CountSpaces(text) + stripped = text.strip() + + if stripped in IGNORE: + return space_before + text + space_after + tail + + if ' ' in stripped or 'overview' in link: + if 'classwx_' in link: + ref = 1000 + if '_1' in link: + ref = link.index('_1') + + ref = Underscore2Capitals(link[6:ref]) + text = ':ref:`%s <%s>`'%(stripped, ref) + + elif 'funcmacro' in link or 'samples' in link or 'debugging' in text.lower() or \ + 'unix' in text.lower() or 'page_libs' in link: + text = space_before + space_after + elif 'library list' in stripped.lower(): + text = space_before + text + space_after + else: + backlink = stripped.lower() + if 'device context' in backlink: + backlink = 'device contexts' + elif 'reference count' in backlink or 'refcount' in link: + backlink = 'reference counting' + elif 'this list' in backlink: + backlink = 'stock items' + elif 'window deletion' in backlink: + backlink = 'window deletion' + elif 'programming with wxboxsizer' in backlink: + stripped = 'Programming with BoxSizer' + backlink = 'programming with boxsizer' + + text = ':ref:`%s <%s>`'%(stripped, backlink) + + elif (text.upper() == text and len(stripped) > 4): + + if not original.strip().startswith('wx') or ' ' in stripped: + text = '' + + elif not IsNumeric(text): + text = '``%s``'%text + + elif 'funcmacro' in link: + if '(' in stripped: + stripped = stripped[0:stripped.index('(')].strip() + + text = ':func:`%s`'%stripped + + elif hascomma or len(remainder) > 30: + if '.m_' in text: + text = '``%s``'%stripped + else: + # it was :meth: + if '.wx' in text: + prev = text.split('.') + text = '.'.join(prev[:-1]) + '.__init__' + text = ':meth:`%s` '%text.strip() + + else: + stripped = text.strip() + + if '(' in stripped: + stripped = stripped[0:stripped.index('(')].strip() + + if '.' not in stripped: + klass = self.IsClassDescription() + if klass: + text = ':meth:`~%s.%s`'%(klass, stripped) + else: + text = ':meth:`%s` '%stripped + else: + text = ':meth:`%s` '%stripped + + else: + text = ':ref:`%s`'%Wx2Sphinx(stripped)[1] + + return space_before + text + space_after + ConvertToPython(tail) + + +# ----------------------------------------------------------------------- # + +class ComputerOutput(Node): + """ + This class holds information about XML elements with the ```` tag. + """ + + def __init__(self, element, parent): + """ + Class constructor. + + :param xml.etree.ElementTree.Element `element`: a XML element containing the + information coming from Doxygen about the aforementioned tags + :param Node `parent`: the parent node, must not be ``None``. + """ + + Node.__init__(self, element, parent) + + + # ----------------------------------------------------------------------- + + def Join(self, with_tail=True): + """ + Join this node `element` attribute text and tail, adding all its children's + node text and tail in the meanwhile. + + :param `with_tail`: ``True`` if the element tail should be included in the + text, ``False`` otherwise. + + :rtype: `string` + + :returns: A string containing the ReSTified version of this node `element` text and + tail plus all its children's element text and tail. + + .. note:: For some of the classes in this script (for example the :class:`Emphasis`, + :class:`ComputerOutput`) the `with_tail` parameter should be set to ``False`` in order + to avoid wrong ReST output. + """ + + text = self.element.text + if not text and not self.children: + return '' + + if text is not None: + stripped = text.strip() + space_before, space_after = CountSpaces(text) + + text = RemoveWxPrefix(text.strip()) + + else: + text = '' + + for child in self.children: + text += child.Join(with_tail=False) + + if '`' not in text: + text = "``%s`` "%text + + if self.element.tail: + text += ConvertToPython(self.element.tail) + + space_before, space_after = CountSpaces(text) + + return space_before + text + space_after + + +# ----------------------------------------------------------------------- # + +class Emphasis(Node): + """ + This class holds information about XML elements with the ```` and + ```` tags. + """ + + # ----------------------------------------------------------------------- + + def __init__(self, element, parent): + """ + Class constructor. + + :param xml.etree.ElementTree.Element `element`: a XML element containing the + information coming from Doxygen about the aforementioned tags + :param Node `parent`: the parent node, must not be ``None``. + """ + + Node.__init__(self, element, parent) + + + # ----------------------------------------------------------------------- + + def Join(self, with_tail=True): + """ + Join this node `element` attribute text and tail, adding all its children's + node text and tail in the meanwhile. + + :param `with_tail`: ``True`` if the element tail should be included in the + text, ``False`` otherwise. + + :rtype: `string` + + :returns: A string containing the ReSTified version of this node `element` text and + tail plus all its children's element text and tail. + + .. note:: For some of the classes in this script (for example the :class:`Emphasis`, + :class:`ComputerOutput`) the `with_tail` parameter should be set to ``False`` in order + to avoid wrong ReST output. + """ + + if self.element.tag == 'emphasis': + format = '`%s`' + elif self.element.tag == 'bold': + format = '**%s**' + + spacing = ('ParameterList' in self.GetHierarchy() and [' '] or [''])[0] + + text = Node.Join(self, with_tail=False) + + if text.strip(): + text = spacing + format % text.strip() + + if self.element.tail: + text += ConvertToPython(self.element.tail) + + return text + + +# ----------------------------------------------------------------------- # + +class Title(Node): + """ + This class holds information about XML elements with the ```` tag. + """ + + # ----------------------------------------------------------------------- + + def __init__(self, element, parent): + """ + Class constructor. + + :param xml.etree.ElementTree.Element `element`: a XML element containing the + information coming from Doxygen about the aforementioned tags + :param Node `parent`: the parent node, must not be ``None``. + """ + + Node.__init__(self, element, parent) + + + # ----------------------------------------------------------------------- + + def Join(self, with_tail=True): + """ + Join this node `element` attribute text and tail, adding all its children's + node text and tail in the meanwhile. + + :param `with_tail`: ``True`` if the element tail should be included in the + text, ``False`` otherwise. + + :rtype: `string` + + :returns: A string containing the ReSTified version of this node `element` text and + tail plus all its children's element text and tail. + + .. note:: For some of the classes in this script (for example the :class:`Emphasis`, + :class:`ComputerOutput`) the `with_tail` parameter should be set to ``False`` in order + to avoid wrong ReST output. + """ + + text = '|phoenix_title| ' + ConvertToPython(self.element.text) + lentext = len(text) + text = '\n\n%s\n%s\n\n'%(text, '='*lentext) + + return text + + +# ----------------------------------------------------------------------- # + +class ULink(Node): + """ + This class holds information about XML elements with the ``<ulink>`` tag. + """ + + # ----------------------------------------------------------------------- + + def __init__(self, element, parent): + """ + Class constructor. + + :param xml.etree.ElementTree.Element `element`: a XML element containing the + information coming from Doxygen about the aforementioned tags + :param Node `parent`: the parent node, must not be ``None``. + """ + + Node.__init__(self, element, parent) + + + # ----------------------------------------------------------------------- + + def Join(self, with_tail=True): + """ + Join this node `element` attribute text and tail, adding all its children's + node text and tail in the meanwhile. + + :param `with_tail`: ``True`` if the element tail should be included in the + text, ``False`` otherwise. + + :rtype: `string` + + :returns: A string containing the ReSTified version of this node `element` text and + tail plus all its children's element text and tail. + + .. note:: For some of the classes in this script (for example the :class:`Emphasis`, + :class:`ComputerOutput`) the `with_tail` parameter should be set to ``False`` in order + to avoid wrong ReST output. + """ + + dummy, link = self.element.items()[0] + text = self.element.text + + text = '`%s <%s>`_'%(text, link) + + if self.element.tail: + text += ConvertToPython(self.element.tail) + + return text + + +# ----------------------------------------------------------------------- # + +class XMLDocString(object): + """ + This is the main class of this script, and it uses heavily the :class:`Node` + subclasses documented above. + + The :class:`XMLDocString` is responsible for building function/method signatures, + class descriptions, window styles and events and so on. + """ + + # ----------------------------------------------------------------------- + + def __init__(self, xml_item, is_overload=False, share_docstrings=False): + """ + Class constructor. + + :param `xml_item`: one of the classes available in `etgtools/extractors.py`, such as + `PyMethodDef`, `PyFunctionDef` and so on + :param bool `is_overload`: ``True`` if this class describes an overloaded + method/function, ``False`` otherwise. + :param bool `share_docstrings`: ``True`` if all the overloaded methods/functions + share the same docstrings. + """ + + self.xml_item = xml_item + self.is_overload = is_overload + self.share_docstrings = share_docstrings + + self.docstrings = '' + + self.class_name = '' + + self.snippet_count = 0 + self.table_count = 0 + + self.list_level = 1 + self.list_order = {} + + self.parameter_list = None + + self.root = Root(self, is_overload, share_docstrings) + + self.appearance = [] + self.overloads = [] + + if isinstance(xml_item, extractors.MethodDef): + self.kind = 'method' + elif isinstance(xml_item, (extractors.FunctionDef, extractors.PyFunctionDef)): + self.kind = 'function' + elif isinstance(xml_item, (extractors.ClassDef, extractors.PyClassDef)): + self.kind = 'class' + self.appearance = FindControlImages(xml_item) + self.class_name = RemoveWxPrefix(xml_item.name) or xml_item.pyName + elif isinstance(xml_item, extractors.EnumDef): + self.kind = 'enum' + else: + raise Exception('Unhandled docstring kind for %s'%xml_item.__class__.__name__) + + if hasattr(xml_item, 'deprecated') and xml_item.deprecated: + element = et.Element('deprecated', kind='deprecated') + element.text = VERSION + + deprecated_section = Section(element, None, self.kind, self.is_overload, self.share_docstrings) + self.root.AddSection(deprecated_section) + + + # ----------------------------------------------------------------------- + + def ToReST(self): + """ Auxiliary method. """ + + brief, detailed = self.xml_item.briefDoc, self.xml_item.detailedDoc + + self.RecurseXML(brief, self.root) + + for detail in detailed: + blank_element = Node('\n\n\n', self.root) + self.RecurseXML(detail, self.root) + + self.InsertParameterList() + self.BuildSignature() + self.docstrings = self.root.Join() + + self.LoadOverLoads() + + + # ----------------------------------------------------------------------- + + def GetBrief(self): + """ + Returns a ReSTified version of the `briefDoc` attribute for the XML docstrings. + + :rtype: `string` + """ + + brief = self.xml_item.briefDoc + + dummy_root = Root(self, False, False) + rest_class = self.RecurseXML(brief, dummy_root) + return rest_class.Join() + + + # ----------------------------------------------------------------------- + + def LoadOverLoads(self): + """ + Extracts the overloaded implementations of a method/function, unless this + class is itself an overload or the current method/function has no overloads. + """ + + if self.is_overload: + return + + if self.kind not in ['method', 'function'] or not self.xml_item.overloads: + return + + share_docstrings = True + all_docs = [] + + for sub_item in [self.xml_item] + self.xml_item.overloads: + + if sub_item.ignored: + continue + + dummy_root = Root(self, False, False) + self.RecurseXML(sub_item.briefDoc, dummy_root) + + for det in sub_item.detailedDoc: + self.RecurseXML(det, dummy_root) + + all_docs.append(dummy_root.Join()) + + if len(all_docs) == 1: + # Only one overload, don't act like there were more + self.xml_item.overloads = [] + return + + zero = all_docs[0] + for docs in all_docs[1:]: + if docs != zero: + share_docstrings = False + break + + self.share_docstrings = share_docstrings + + for sub_item in [self.xml_item] + self.xml_item.overloads: + + if sub_item.ignored: + continue + + sub_item.name = self.xml_item.pyName or RemoveWxPrefix(self.xml_item.name) + docstring = XMLDocString(sub_item, is_overload=True, share_docstrings=share_docstrings) + docstring.class_name = self.class_name + docstring.current_module = self.current_module + + docs = docstring.Dump() + self.overloads.append(docs) + + + # ----------------------------------------------------------------------- + + def RecurseXML(self, element, parent): + """ + Scan recursively all the XML elements which make up the whole documentation for + a particular class/method/function. + + :param xml.etree.ElementTree.Element `element`: a XML element containing the + information coming from Doxygen about the aforementioned tags + :param Node `parent`: the parent node, a subclass of the :class:`Node` class. + + :rtype: a subclass of :class:`Node` + + .. note: This is a recursive method. + """ + + if element is None: + return Node('', parent) + + if isinstance(element, basestring): + rest_class = Paragraph(element, parent, self.kind) + return rest_class + + tag, text, tail = element.tag, element.text, element.tail + + text = (text is not None and [text] or [''])[0] + tail = (tail is not None and [tail] or [''])[0] + + if tag == 'parameterlist': + rest_class = ParameterList(element, parent, self.xml_item, self.kind) + self.parameter_list = rest_class + + elif tag == 'parametername': + self.parameter_name = text + rest_class = self.parameter_list + + elif tag == 'parameterdescription': + parameter_class = self.parameter_list.Get(self.parameter_name) + if parameter_class: + rest_class = parameter_class + parameter_class.element = element + else: + rest_class = self.parameter_list + + elif tag in ['itemizedlist', 'orderedlist']: + rest_class = List(element, parent) + + elif tag == 'listitem': + rest_class = ListItem(element, parent) + + elif tag in ['simplesect', 'xrefsect']: + if 'ListItem' in parent.GetHierarchy(): + rest_class = Section(element, parent, self.kind, self.is_overload, self.share_docstrings) + else: + if element.tail: + Node(element.tail, parent) + + rest_class = Section(element, None, self.kind, self.is_overload, self.share_docstrings) + self.root.AddSection(rest_class) + + elif tag == 'image': + rest_class = Image(element, parent) + + elif tag == 'table': + fullname = self.GetFullName() + self.table_count += 1 + fullname = '%s.%d.rst'%(fullname, self.table_count) + rest_class = Table(element, parent, fullname) + self.table = rest_class + + elif tag == 'entry': + rest_class = TableEntry(element, self.table) + + elif tag == 'row': + rest_class = self.table + + elif tag == 'programlisting': + cpp_file, python_file, converted_py = self.SnippetName() + rest_class = Snippet(element, parent, cpp_file, python_file, converted_py) + self.code = rest_class + + elif tag in ['codeline', 'highlight', 'sp']: + self.code.AddCode(element) + rest_class = self.code + + elif tag == 'ref': + if 'Snippet' in parent.GetHierarchy(): + self.code.AddCode(element) + rest_class = self.code + else: + rest_class = XRef(element, parent) + + elif tag == 'computeroutput': + rest_class = ComputerOutput(element, parent) + + elif tag in ['emphasis', 'bold']: + rest_class = Emphasis(element, parent) + + elif tag == 'title': + rest_class = Title(element, parent) + + elif tag == 'para': + rest_class = Paragraph(element, parent, self.kind) + + elif tag == 'linebreak': + spacer = '' + dummy = Node('\n\n%s%s'%(spacer, tail.strip()), parent) + rest_class = parent + + elif tag == 'ulink': + rest_class = ULink(element, parent) + + elif tag == 'onlyfor': + onlyfor = et.Element('available', kind='available') + onlyfor.text = text + onlyfor.tail = tail + + section = Section(onlyfor, None, self.kind) + + self.root.AddSection(section) + rest_class = parent + + else: + rest_class = Node('', parent) + + for child_element in element: + self.RecurseXML(child_element, rest_class) + + return rest_class + + + # ----------------------------------------------------------------------- + + def GetFullName(self): + """ + Returns the complete name for a class/method/function, including + its module/package. + + :rtype: `string` + """ + + if self.kind == 'class': + klass = self.xml_item + name = RemoveWxPrefix(klass.name) or klass.pyName + dummy, fullname = Wx2Sphinx(name) + elif self.kind == 'method': + method = self.xml_item + if method.isCtor: + method_name = '__init__' + else: + method_name = method.name or method.pyName + method_name = RemoveWxPrefix(method_name) + dummy, fullname = Wx2Sphinx(method.className) + fullname = fullname + '.' + method_name + elif self.kind == 'function': + function = self.xml_item + name = function.pyName or function.name + fullname = self.current_module + 'functions.%s'%name + + return fullname + + + # ----------------------------------------------------------------------- + + def SnippetName(self): + """ + Returns a tuple of 3 elements (3 file paths), representing the following: + + 1. `cpp_file`: the path to the C++ snippet of code found in the XML + wxWidgets docstring, saved into the ``SNIPPETROOT/cpp`` folder + 2. `python_file`: the path to the roughly-converted to Python + snippet of code found in the XML wxWidgets docstring, saved into the + ``SNIPPETROOT/python`` folder + 3. `converted_py`: the path to the fully-converted to Python + snippet of code found in the XML wxWidgets docstring, saved into the + ``SNIPPETROOT/python/converted`` folder. + """ + + fullname = self.GetFullName() + + self.snippet_count += 1 + + cpp_file = os.path.join(SNIPPETROOT, 'cpp', fullname + '.%d.cpp'%self.snippet_count) + python_file = os.path.join(SNIPPETROOT, 'python', fullname + '.%d.py'%self.snippet_count) + converted_py = os.path.join(SNIPPETROOT, 'python', 'converted', fullname + '.%d.py'%self.snippet_count) + + return cpp_file, python_file, converted_py + + + # ----------------------------------------------------------------------- + + def Dump(self, write=True): + """ + Dumps the whole ReSTified docstrings and returns its correct ReST representation. + + :param bool `write`: ``True`` to write the resulting docstrings to a file, ``False`` + otherwise. + + :rtype: `string` + """ + + self.ToReST() + + methodMap = { + 'class' : self.DumpClass, + 'method' : self.DumpMethod, + 'function' : self.DumpFunction, + 'enum' : self.DumpEnum, + } + + function = methodMap[self.kind] + return function(write) + + + # ----------------------------------------------------------------------- + + def DumpClass(self, write): + """ + Dumps a ReSTified class description and returns its correct ReST representation. + + :param bool `write`: ``True`` to write the resulting docstrings to a file, ``False`` + otherwise. + + :rtype: `string` + """ + + stream = StringIO() + + # class declaration + klass = self.xml_item + name = self.class_name + dummy, fullname = Wx2Sphinx(name) + + stream.write(templates.TEMPLATE_DESCRIPTION % (fullname, name)) + + self.Reformat(stream) + + inheritance_diagram = InheritanceDiagram(klass.nodeBases) + png, map = inheritance_diagram.MakeInheritanceDiagram() + + image_desc = templates.TEMPLATE_INHERITANCE % (name, png, name, map) + stream.write(image_desc) + + if self.appearance: + appearance_desc = templates.TEMPLATE_APPEARANCE % tuple(self.appearance) + stream.write(appearance_desc) + + if klass.subClasses: + subs = [':ref:`%s`'%Wx2Sphinx(cls)[1] for cls in klass.subClasses] + subs = ', '.join(subs) + subs_desc = templates.TEMPLATE_SUBCLASSES % subs + stream.write(subs_desc) + + if klass.method_list: + summary = MakeSummary(name, klass.method_list, templates.TEMPLATE_METHOD_SUMMARY, 'meth') + stream.write(summary) + + if klass.property_list: + summary = MakeSummary(name, klass.property_list, templates.TEMPLATE_PROPERTY_SUMMARY, 'attr') + stream.write(summary) + + stream.write(templates.TEMPLATE_API) + stream.write("\n.. class:: %s"%name) + + bases = klass.bases or ['object'] + + if bases: + stream.write('(') + bases = [RemoveWxPrefix(b) for b in bases] + stream.write(', '.join(bases)) + stream.write(')') + + stream.write('\n\n') + + py_docs = klass.pyDocstring + + if isinstance(self.xml_item, extractors.PyClassDef): + newlines = self.xml_item.briefDoc.splitlines() + else: + newlines = [] + + found = False + for line in py_docs.splitlines(): + + if line.startswith(name): + if not found: + newlines.append("**Possible constructors**::\n") + found = True + else: + found = False + newlines.append(ConvertToPython(line)) + + if found: + newlines = self.CodeIndent(line, newlines) + + newdocs = u'' + for line in newlines: + newdocs += ' '*3 + line + "\n" + + stream.write(newdocs + "\n\n") + + if write: + WriteSphinxOutput(stream, self.output_file) + else: + return stream.getvalue() + + + # ----------------------------------------------------------------------- + + def BuildSignature(self): + """ Builds a function/method signature. """ + + if self.kind not in ['method', 'function']: + return + + if self.kind == 'method': + + method = self.xml_item + name = method.name or method.pyName + name = RemoveWxPrefix(name) + + if method.overloads and not self.is_overload: + if not method.isStatic: + arguments = '(self, *args, **kw)' + else: + arguments = '(*args, **kw)' + else: + arguments = method.pyArgsString + if not arguments: + arguments = '()' + if not method.isStatic: + if arguments[:2] == '()': + arguments = '(self)' + arguments[2:] + else: + arguments = '(self, ' + arguments[1:] + + if '->' in arguments: + arguments, after = arguments.split("->") + self.AddReturnType(after, name) + + arguments = arguments.rstrip() + if arguments.endswith(','): + arguments = arguments[0:-1] + + if not arguments.endswith(')'): + arguments += ')' + + if self.is_overload: + arguments = '`%s`'%arguments.strip() + + elif self.kind == 'function': + + function = self.xml_item + name = function.name or function.pyName + name = RemoveWxPrefix(name) + + if function.overloads and not self.is_overload: + arguments = '(*args, **kw)' + else: + if "->" in function.pyArgsString: + arguments, after = function.pyArgsString.split("->") + self.AddReturnType(after, name) + else: + arguments = function.pyArgsString + + if self.is_overload: + arguments = '`%s`'%arguments.strip() + + self.arguments = arguments + + + # ----------------------------------------------------------------------- + + def InsertParameterList(self): + """ + Inserts a :class:`ParameterList` item in the correct position into the + :class:`Root` hierarchy, and checks the signature validity against the + parameter list itself. + """ + + if self.kind not in ['method', 'function']: + return + + if self.parameter_list is not None: + self.parameter_list.CheckSignature() + return + + if not self.xml_item.overloads or self.is_overload: + self.parameter_list = ParameterList('', None, self.xml_item, self.kind) + self.root.Insert(self.parameter_list, before=Section) + self.parameter_list.CheckSignature() + + + # ----------------------------------------------------------------------- + + def AddReturnType(self, after, name): + + after = after.strip() + + if not after: + return + + if '(' in after: + + rtype = ReturnType('`tuple`', None) + + return_section = after.lstrip('(').rstrip(')') + return_section = return_section.split(',') + new_section = [] + + for ret in return_section: + if ret[0].isupper(): + new_section.append(':ref:`%s`'%ret.strip()) + else: + new_section.append('`%s`'%ret.strip()) + + element = et.Element('return', kind='return') + element.text = '( %s )'%(', '.join(new_section)) + + return_section = Section(element, None, self.kind, self.is_overload, self.share_docstrings) + self.root.AddSection(return_section) + + else: + + rtype = PythonizeType(after) + + if not rtype: + return + + if rtype[0].isupper() or '.' in rtype: + rtype = ':ref:`%s`'%rtype + else: + rtype = '`%s`'%rtype + + rtype = ReturnType(rtype, None) + + if self.parameter_list: + self.parameter_list.Add(rtype) + else: + self.root.Insert(rtype, before=Section) + + + # ----------------------------------------------------------------------- + + def DumpMethod(self, write): + """ + Dumps a ReSTified method description and returns its correct ReST representation. + + :param bool `write`: ``True`` to write the resulting docstrings to a file, ``False`` + otherwise. + + :rtype: `string` + """ + + stream = StringIO() + + method = self.xml_item + name = method.name or method.pyName + name = RemoveWxPrefix(name) + + if self.is_overload: + definition = '**%s** '%name + else: + if method.isStatic: + definition = ' .. staticmethod:: ' + name + else: + definition = ' .. method:: ' + name + + # write the method declaration + stream.write('\n%s'%definition) + + stream.write(self.arguments) + stream.write('\n\n') + + self.Reformat(stream) + stream.write("\n\n") + + if not self.is_overload and write: + WriteSphinxOutput(stream, self.output_file) + + return stream.getvalue() + + + # ----------------------------------------------------------------------- + + def DumpFunction(self, write): + """ + Dumps a ReSTified function description and returns its correct ReST representation. + + :param bool `write`: ``True`` to write the resulting docstrings to a file, ``False`` + otherwise. + + :rtype: `string` + """ + + stream = StringIO() + + function = self.xml_item + name = function.pyName or function.name + + if self.is_overload: + definition = '**%s** '%name + else: + definition = '.. function:: ' + name + + stream.write('\n%s'%definition) + + stream.write(self.arguments.strip()) + stream.write('\n\n') + + self.Reformat(stream) + + if not self.is_overload and write: + PickleItem(stream.getvalue(), self.current_module, name, 'function') + + return stream.getvalue() + + + # ----------------------------------------------------------------------- + + def DumpEnum(self, write): + """ + Dumps a ReSTified enumeration description and returns its correct ReST representation. + + :param bool `write`: ``True`` to write the resulting docstrings to a file, ``False`` + otherwise. + + :rtype: `string` + """ + + enum_name, fullname = Wx2Sphinx(self.xml_item.name) + + if '@' in enum_name: + return + + stream = StringIO() + self.output_file = self.current_module + "%s.enumeration.txt"%enum_name + + stream.write(templates.TEMPLATE_DESCRIPTION % (fullname, enum_name)) + stream.write('\n\nThe `%s` enumeration provides the following values:\n\n'%enum_name) + + stream.write('\n\n' + '='*80 + ' ' + '='*80 + '\n') + stream.write('%-80s **Value**\n'%'**Description**') + stream.write('='*80 + ' ' + '='*80 + '\n') + + count = 0 + + for v in self.xml_item.items: + if v.ignored: + continue + + docstrings = v.briefDoc + name = ConvertToPython(RemoveWxPrefix(v.name)) + stream.write('%-80s'%name) + + if not isinstance(docstrings, basestring): + rest_class = self.RecurseXML(docstrings, self.root) + docstrings = rest_class.Join() + + stream.write(' %s\n'%docstrings) + count += 1 + + stream.write('='*80 + ' ' + '='*80 + '\n\n|\n\n') + + text_file = os.path.join(SPHINXROOT, self.output_file) + + if os.path.isfile(text_file): + message = '\nWARNING: Duplicated description for `%s` enumeration.\n\n' \ + 'The duplicated instance will still be written to its output ReST file but\n' \ + 'Sphinx/Docutils will issue a warning when building the HTML docs.\n\n' + + duplicated = self.output_file.replace('.enumeration.txt', '') + print message % duplicated + + if count > 0 and write: + WriteSphinxOutput(stream, self.output_file) + + return stream.getvalue() + + + # ----------------------------------------------------------------------- + + def EventsInStyle(self, line, class_name): + + docstrings = '' + newline = line + + if 'supports the following styles:' in line: + docstrings += templates.TEMPLATE_WINDOW_STYLES % class_name + + elif 'The following event handler macros' in line: + last = line.index(':') + line = line[last+1:].strip() + + if line.count(':') > 2: + newline = 'Handlers bound for the following event types will receive one of the %s parameters.'%line + else: + newline = 'Handlers bound for the following event types will receive a %s parameter.'%line + + docstrings += templates.TEMPLATE_EVENTS % class_name + + elif 'Event macros for events' in line: + docstrings += templates.TEMPLATE_EVENTS % class_name + + elif 'following extra styles:' in line: + docstrings += templates.TEMPLATE_WINDOW_EXTRASTYLES % class_name + + return docstrings, newline + + + # ----------------------------------------------------------------------- + + def CodeIndent(self, code, newlines): + + if len(code) < 72: + newlines.append(' %s'%code) + newlines.append(' ') + return newlines + + start = code.index('(') + wrapped = textwrap.wrap(code, width=72) + + newcode = '' + for indx, line in enumerate(wrapped): + if indx == 0: + newlines.append(' %s'%line) + else: + newlines.append(' '*(start+5) + line) + + newlines.append(' ') + + return newlines + + + # ----------------------------------------------------------------------- + + def Indent(self, class_name, item, spacer, docstrings): + + for line in item.splitlines(): + if line.strip(): + newdocs, newline = self.EventsInStyle(line, class_name) + docstrings += newdocs + docstrings += spacer + newline + '\n' + else: + docstrings += line + '\n' + + return docstrings + + + # ----------------------------------------------------------------------- + + def Reformat(self, stream): + + spacer = '' + + if not self.is_overload: + if self.kind == 'function': + spacer = 3*' ' + elif self.kind == 'method': + spacer = 6*' ' + + if self.overloads and not self.share_docstrings: + + docstrings = '' + + elif self.is_overload and self.share_docstrings: + + docstrings = self.Indent(None, self.docstrings, spacer, u'') + + else: + + class_name = None + + if self.kind == 'class': + class_name = self.class_name + + if isinstance(self.xml_item, (extractors.PyFunctionDef, extractors.PyClassDef)): + docstrings = self.xml_item.briefDoc + if docstrings: + docstrings = self.Indent(class_name, docstrings, spacer, u'') + else: + docstrings = '' + else: + docstrings = self.Indent(class_name, self.docstrings, spacer, u'') + + if self.kind == 'class': + desc = ChopDescription(docstrings) + class_name = self.class_name.lower() + PickleItem(desc, self.current_module, self.class_name, 'class') + + if self.overloads: + + docstrings += '\n\n%s|overload| **Overloaded Implementations**:\n\n'%spacer + docstrings += '%s**~~~**\n\n'%spacer + + for index, over in enumerate(self.overloads): + for line in over.splitlines(): + docstrings += spacer + line + '\n' + + docstrings += '%s**~~~**\n\n'%spacer + + stream.write(docstrings + "\n\n") + + +# --------------------------------------------------------------------------- + +class SphinxGenerator(generators.DocsGeneratorBase): + + def generate(self, module): + + self.current_module = MODULENAME_REPLACE[module.module] + self.module_name = module.name + self.current_class = None + + self.generateModule(module) + + # ----------------------------------------------------------------------- + + def RemoveDuplicated(self, class_name, class_items): + + duplicated_indexes = [] + done = [] + + properties = (extractors.PropertyDef, extractors.PyPropertyDef) + methods = (extractors.MethodDef, extractors.CppMethodDef, extractors.CppMethodDef_sip, + extractors.PyMethodDef, extractors.PyFunctionDef) + + message = '\nWARNING: Duplicated instance of %s `%s` encountered in class `%s`.\n' \ + 'The last occurrence of `%s` (an instance of `%s`) will be discarded.\n\n' + + for index, item in enumerate(class_items): + if isinstance(item, methods): + name, dummy = self.getName(item) + kind = 'method' + elif isinstance(item, properties): + name = item.name + kind = 'property' + else: + continue + + if name in done: + print message % (kind, name, class_name, name, item.__class__.__name__) + duplicated_indexes.append(index) + continue + + done.append(name) + + duplicated_indexes.reverse() + for index in duplicated_indexes: + class_items.pop(index) + + return class_items + + + # ----------------------------------------------------------------------- + + def generateModule(self, module): + """ + Generate code for each of the top-level items in the module. + """ + assert isinstance(module, extractors.ModuleDef) + + methodMap = { + extractors.ClassDef : self.generateClass, + extractors.DefineDef : self.generateDefine, + extractors.FunctionDef : self.generateFunction, + extractors.EnumDef : self.generateEnum, + extractors.GlobalVarDef : self.generateGlobalVar, + extractors.TypedefDef : self.generateTypedef, + extractors.WigCode : self.generateWigCode, + extractors.PyCodeDef : self.generatePyCode, + extractors.CppMethodDef : self.generateFunction, + extractors.CppMethodDef_sip : self.generateFunction, + extractors.PyFunctionDef : self.generatePyFunction, + extractors.PyClassDef : self.generatePyClass, + } + + for item in module: + if item.ignored: + continue + + function = methodMap[item.__class__] + function(item) + + + # ----------------------------------------------------------------------- + + def generatePyFunction(self, function): + + function.overloads = [] + function.pyArgsString = function.argsString + # docstring + docstring = XMLDocString(function) + docstring.kind = 'function' + docstring.current_module = self.current_module + + docstring.Dump() + + + # ----------------------------------------------------------------------- + + def generateFunction(self, function): + + # docstring + docstring = XMLDocString(function) + docstring.kind = 'function' + docstring.current_module = self.current_module + + docstring.Dump() + + + # ----------------------------------------------------------------------- + + def generatePyClass(self, klass): + + klass.module = self.current_module + self.current_class = klass + + name = klass.name + self.current_class.method_list = [] + self.current_class.property_list = [] + + class_items = [i for i in klass if not i.ignored] + class_items = sorted(class_items, key=operator.attrgetter('name')) + + class_items = self.RemoveDuplicated(name, class_items) + + init_position = -1 + + for index, item in enumerate(class_items): + if isinstance(item, extractors.PyFunctionDef): + method_name, simple_docs = self.getName(item) + if method_name == '__init__': + init_position = index + self.current_class.method_list.insert(0, (method_name, simple_docs)) + else: + self.current_class.method_list.append((method_name, simple_docs)) + elif isinstance(item, extractors.PyPropertyDef): + simple_docs = self.createPropertyLinks(name, item) + self.current_class.property_list.append((item.name, simple_docs)) + + PickleClassInfo(self.current_module + name, self.current_class) + + if init_position >= 0: + init_method = class_items.pop(init_position) + class_items.insert(0, init_method) + + docstring = XMLDocString(klass) + docstring.kind = 'class' + + filename = self.current_module + "%s.txt"%name + docstring.output_file = filename + docstring.current_module = self.current_module + + docstring.Dump() + + # these are the only kinds of items allowed to be items in a PyClass + dispatch = { + extractors.PyFunctionDef : self.generateMethod, + extractors.PyPropertyDef : self.generatePyProperty, + extractors.PyCodeDef : self.generatePyCode, + extractors.PyClassDef : self.generatePyClass, + } + + for item in class_items: + item.klass = klass + f = dispatch[item.__class__] + f(item) + + + # ----------------------------------------------------------------------- + + def generatePyProperty(self, prop): + + name = RemoveWxPrefix(self.current_class.name) or self.current_class.pyName + getter_setter = self.createPropertyLinks(name, prop) + + stream = StringIO() + stream.write('\n .. attribute:: %s\n\n' % prop.name) + stream.write(' %s\n\n'%getter_setter) + + filename = self.current_module + "%s.txt"%name + + WriteSphinxOutput(stream, filename) + + # ----------------------------------------------------------------------- + + def generateClass(self, klass): + + assert isinstance(klass, extractors.ClassDef) + + if klass.ignored: + return + + # generate nested classes + for item in klass.innerclasses: + self.generateClass(item) + + name = RemoveWxPrefix(klass.name) or klass.pyName + +## # Hack for App/PyApp... +## if name == 'PyApp': +## klass.name = name = 'App' + + klass.module = self.current_module + self.current_class = klass + + self.current_class.method_list = [] + self.current_class.property_list = [] + + # Inspected class Method to call Sort order + dispatch = { + extractors.MethodDef : (self.generateMethod, 1), + extractors.CppMethodDef : (self.generateMethod, 1), + extractors.CppMethodDef_sip : (self.generateMethod, 1), + extractors.PyMethodDef : (self.generatePyMethod, 1), + extractors.MemberVarDef : (self.generateMemberVar, 2), + extractors.PropertyDef : (self.generateProperty, 2), + extractors.PyPropertyDef : (self.generateProperty, 2), + extractors.EnumDef : (self.generateEnum, 0), + extractors.PyCodeDef : (self.generatePyCode, 3), + extractors.WigCode : (self.generateWigCode, 4), + } + + # Build a list to check if there are any properties + properties = (extractors.PropertyDef, extractors.PyPropertyDef) + methods = (extractors.MethodDef, extractors.CppMethodDef, extractors.CppMethodDef_sip, extractors.PyMethodDef) + + # Split the items documenting the __init__ methods first + ctors = [i for i in klass if + isinstance(i, extractors.MethodDef) and + i.protection == 'public' and (i.isCtor or i.isDtor)] + + class_items = [i for i in klass if i not in ctors and not i.ignored] + + for item in class_items: + item.sort_order = dispatch[item.__class__][1] + + class_items = sorted(class_items, key=operator.attrgetter('sort_order', 'name')) + class_items = self.RemoveDuplicated(name, class_items) + + for item in class_items: + if isinstance(item, methods) and not self.IsFullyDeprecated(item): + method_name, simple_docs = self.getName(item) + self.current_class.method_list.append((method_name, simple_docs)) + elif isinstance(item, properties): + simple_docs = self.createPropertyLinks(name, item) + self.current_class.property_list.append((item.name, simple_docs)) + + for item in ctors: + if item.isCtor: + method_name, simple_docs = self.getName(item) + self.current_class.method_list.insert(0, ('__init__', simple_docs)) + + PickleClassInfo(self.current_module + name, self.current_class) + + docstring = XMLDocString(klass) + + filename = self.current_module + "%s.txt"%name + docstring.output_file = filename + docstring.current_module = self.current_module + + docstring.Dump() + + for item in ctors: + if item.isCtor: + self.generateMethod(item, name='__init__', docstring=klass.pyDocstring) + + for item in class_items: + f = dispatch[item.__class__][0] + f(item) + + # ----------------------------------------------------------------------- + + def generateMethod(self, method, name=None, docstring=None): + + if method.ignored: + return + + name = name or self.getName(method)[0] +## if name.startswith("__") and "__init__" not in name: +## return + + class_name = RemoveWxPrefix(self.current_class.name) or self.current_class.pyName + + # docstring + method.name = name + method.pyArgsString = method.pyArgsString.replace('(self)', ' ').replace('(self, ', ' ') + docstring = XMLDocString(method) + docstring.kind = 'method' + + name = RemoveWxPrefix(self.current_class.name) or self.current_class.pyName + filename = self.current_module + "%s.txt"%class_name + + docstring.output_file = filename + docstring.class_name = class_name + docstring.current_module = self.current_module + + docstring.Dump() + + # ----------------------------------------------------------------------- + + def IsFullyDeprecated(self, pyMethod): + + if not isinstance(pyMethod, extractors.PyMethodDef): + return False + + if pyMethod.deprecated: + brief, detailed = pyMethod.briefDoc, pyMethod.detailedDoc + if not brief and not detailed: + # Skip simple wrappers unless they have a brief or a detailed doc + return True + + return False + + + def generatePyMethod(self, pm): + + assert isinstance(pm, extractors.PyMethodDef) + + if pm.ignored: + return + + if self.IsFullyDeprecated(pm): + return + + stream = StringIO() + stream.write('\n .. method:: %s%s\n\n' % (pm.name, pm.argsString)) + + docstrings = ConvertToPython(pm.pyDocstring).replace('\n', ' ') + + newdocs = '' + for line in docstrings.splitlines(): + newdocs += ' '*6 + line + "\n" + + stream.write(newdocs + '\n\n') + + name = RemoveWxPrefix(self.current_class.name) or self.current_class.pyName + filename = self.current_module + "%s.txt"%name + + WriteSphinxOutput(stream, filename) + + # ----------------------------------------------------------------------- + + def generateMemberVar(self, memberVar): + assert isinstance(memberVar, extractors.MemberVarDef) + if memberVar.ignored: + return + + # ----------------------------------------------------------------------- + + def generateProperty(self, prop): + + if prop.ignored: + return + + name = RemoveWxPrefix(self.current_class.name) or self.current_class.pyName + + getter_setter = self.createPropertyLinks(name, prop) + + stream = StringIO() + stream.write('\n .. attribute:: %s\n\n' % prop.name) + stream.write(' %s\n\n'%getter_setter) + + filename = self.current_module + "%s.txt"%name + + WriteSphinxOutput(stream, filename) + + + def createPropertyLinks(self, name, prop): + + if prop.getter and prop.setter: + return 'See :meth:`~%s.%s` and :meth:`~%s.%s`'%(name, prop.getter, name, prop.setter) + else: + method = (prop.getter and [prop.getter] or [prop.setter])[0] + return 'See :meth:`~%s.%s`'%(name, method) + + + # ----------------------------------------------------------------------- + def generateEnum(self, enum): + + assert isinstance(enum, extractors.EnumDef) + if enum.ignored: + return + + docstring = XMLDocString(enum) + docstring.current_module = self.current_module + + docstring.Dump() + + + # ----------------------------------------------------------------------- + def generateGlobalVar(self, globalVar): + assert isinstance(globalVar, extractors.GlobalVarDef) + if globalVar.ignored: + return + name = globalVar.pyName or globalVar.name + if guessTypeInt(globalVar): + valTyp = '0' + elif guessTypeFloat(globalVar): + valTyp = '0.0' + elif guessTypeStr(globalVar): + valTyp = '""' + else: + valTyp = RemoveWxPrefix(globalVar.type) + '()' + + # ----------------------------------------------------------------------- + def generateDefine(self, define): + assert isinstance(define, extractors.DefineDef) + # write nothing for this one + + # ----------------------------------------------------------------------- + def generateTypedef(self, typedef): + assert isinstance(typedef, extractors.TypedefDef) + # write nothing for this one + + # ----------------------------------------------------------------------- + def generateWigCode(self, wig): + assert isinstance(wig, extractors.WigCode) + # write nothing for this one + + # ----------------------------------------------------------------------- + def generatePyCode(self, pc): + + assert isinstance(pc, extractors.PyCodeDef) + + # ----------------------------------------------------------------------- + def getName(self, method): + + if hasattr(method, 'isCtor') and method.isCtor: + method_name = '__init__' + else: + method_name = method.pyName or method.name + if method_name in MAGIC_METHODS: + method_name = MAGIC_METHODS[method_name] + + simple_docs = '' + + if isinstance(method, extractors.PyMethodDef): + simple_docs = ConvertToPython(method.pyDocstring) + else: + brief = method.briefDoc + if not isinstance(brief, basestring): + docstring = XMLDocString(method) + docstring.kind = 'method' + docstring.current_module = self.current_module + simple_docs = docstring.GetBrief() + elif brief is not None: + simple_docs = ConvertToPython(brief) + + simple_docs = ChopDescription(simple_docs) + + return method_name, simple_docs + + +# --------------------------------------------------------------------------- +# helpers + +def guessTypeInt(v): + if isinstance(v, extractors.EnumValueDef): + return True + if isinstance(v, extractors.DefineDef) and '"' not in v.value: + return True + type = v.type.replace('const', '') + type = type.replace(' ', '') + if type in ['int', 'long', 'byte', 'size_t']: + return True + if 'unsigned' in type: + return True + return False + + +def guessTypeFloat(v): + type = v.type.replace('const', '') + type = type.replace(' ', '') + if type in ['float', 'double', 'wxDouble']: + return True + return False + +def guessTypeStr(v): + if hasattr(v, 'value') and '"' in v.value: + return True + if 'wxString' in v.type: + return True + return False + +# --------------------------------------------------------------------------- diff --git a/etgtools/tweaker_tools.py b/etgtools/tweaker_tools.py index a5299b21..69500f88 100644 --- a/etgtools/tweaker_tools.py +++ b/etgtools/tweaker_tools.py @@ -30,7 +30,6 @@ magicMethods = { # TODO: add more } - def removeWxPrefixes(node): """ Rename items with a 'wx' prefix to not have the prefix. If the back-end @@ -54,6 +53,10 @@ def removeWxPrefixes(node): def removeWxPrefix(name): if name.startswith('wx') and not name.startswith('wxEVT_'): name = name[2:] + + if name.startswith('``wx') and not name.startswith('``wxEVT_'): + name = name[0:2] + name[4:] + return name @@ -363,7 +366,8 @@ def runGenerators(module): generators.append(pi_generator.PiWrapperGenerator()) # And finally add the documentation generator - generators.append(getDocsGenerator()) + import sphinx_generator + generators.append(sphinx_generator.SphinxGenerator()) # run them for g in generators: diff --git a/sphinxtools/__init__.py b/sphinxtools/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/sphinxtools/constants.py b/sphinxtools/constants.py new file mode 100644 index 00000000..9b897bc6 --- /dev/null +++ b/sphinxtools/constants.py @@ -0,0 +1,142 @@ +# -*- coding: utf-8 -*- +#!/usr/bin/env python + +#--------------------------------------------------------------------------- +# Name: sphinxtools/constants.py +# Author: Andrea Gavana +# +# Created: 30-Nov-2010 +# Copyright: (c) 2011 by Total Control Software +# License: wxWindows License +#--------------------------------------------------------------------------- + +# Standard library imports +import os +import re +import datetime + +# Phoenix-specific imports +import buildtools.version as version + +# List of strings that should be ignored when creating inline literals +# such as ``ID_ANY`` or ``HORIZONtAL``, with double backticks +IGNORE = ['wxPython', 'wxWidgets', 'wxOSX', 'wxMGL', 'wxDFB', 'wxMAC', 'wxGTK', 'wxGTK2', 'wxUniversal', + 'OS', 'X', 'OSX', 'DFB', 'MAC', 'GTK', 'GTK2', 'MSW', 'wxMSW', 'X11', 'OS2', 'MS', 'XP', 'GTK+', + 'UI', 'GUI', '--', 'OTOH', 'GDI+', 'API', 'NT', 'RTL', 'GDI', '3D', 'MDI'] + +# C++ stuff to Python/ReST stuff +VALUE_MAP = {'true': '``True``', + 'false': '``False``', + '``NULL``': '``None``', + 'NULL': '``None``', + 'L{OSX}': '`OSX`', + 'ctor': 'constructor', + } + +# This is a list of instances in Phoenix (i.e., without documentation strings), and +# For the sake of beauty of the docs they get the inline literal treatment (double backticks) +CONSTANT_INSTANCES = ['NullAcceleratorTable', 'TheApp', 'DefaultPosition', 'DefaultSize', + 'DefaultCoord', 'Coord', 'TheBrushList', 'TheColourDatabase', + 'NullFont', 'NullBrush', 'NullPalette', 'NullPen', 'EmptyString', + 'TheFontList', 'NullIcon', 'NullBitmap', 'constructor', 'ThePenList', + 'DefaultValidator', 'String.Capitalize'] + +# Phoenix full version +VERSION = '%d.%d.%d' % (version.VER_MAJOR, version.VER_MINOR, version.VER_RELEASE) + +# Things to chop away when ReST-ifying the docstrings +PUNCTUATION = '!"#$%\'()*,./:;<=>?@\\^{|}~' + +# Conversion between XML sections and ReST sections +SECTIONS = [('return' , ':returns:'), + ('since' , '.. versionadded::'), + ('deprecated', '.. deprecated::'), + ('warning' , '.. warning::'), + ('remarks' , '.. note::'), + ('remark' , '.. note::'), + ('available' , '.. availability::'), + ('note' , '.. note::'), + ('see' , '.. seealso::'), + ('todo' , '.. todo::')] + + +# List of things to remove/ignore (there may be more) +REMOVED_LINKS = ['Library:', 'Category:', 'Predefined objects/pointers:'] + +# Dictionary mapping the etg module name to the real Phoenix module name +# This needs to be kept up to date when other stuff comes in (i.e., wx.grid, +# wx.html and so on) +MODULENAME_REPLACE = {'_core' : '', + '_dataview': 'dataview.' + } + +# Other C++ specific things to strip away +CPP_ITEMS = ['*', '&', 'const', 'unsigned', '(size_t)', 'size_t', 'void'] + +# Serie of paths containing the input data for Sphinx and for the scripts +# building the ReST docs: + +# The location of the Phoenix main folder +PHOENIXROOT = os.path.abspath(os.path.split(__file__)[0] + '/..') + +# The location of the Sphinx main folder +SPHINXROOT = os.path.join(PHOENIXROOT, 'docs', 'sphinx') + +# Where the snippets found in the XML docstrings live (There are C++, unconverted and +# converted Python snippets in 3 sub-folders +SNIPPETROOT = os.path.join(SPHINXROOT, 'rest_substitutions', 'snippets') + +# A folder where some of the difficult-to-translate-to-ReST tables are. There are 3 of +# them up to now, for various reasons: +# 1. The wx.Sizer flags table is a grid table, very difficult to ReSTify automatically +# 2. The wx.ColourDatabase table of colour comes up all messy when ReSTified from XML +# 3. The "wxWidgets 2.8 Compatibility Functions" table for wx.VScrolledWindow +TABLEROOT = os.path.join(SPHINXROOT, 'rest_substitutions', 'tables') + +# Folder where to save the inheritance diagrams for the classes +INHERITANCEROOT = os.path.join(SPHINXROOT, '_static', 'images', 'inheritance') + +# Folder where to save the images found in the wxWidgets overviews or in the XML +# docstrings +OVERVIEW_IMAGES_ROOT = os.path.join(SPHINXROOT, '_static', 'images', 'overviews') + +# Folder where to save the widgets screenshots (full-size, no thumbnails here) +WIDGETS_IMAGES_ROOT = os.path.join(SPHINXROOT, '_static', 'images', 'widgets', 'fullsize') + +# Folder for the icons used for titles, sub-titles and so on for the Sphinx documentation +SPHINX_IMAGES_ROOT = os.path.join(SPHINXROOT, '_static', 'images', 'sphinxdocs') + +# The Doxygen root for the XML docstrings +DOXYROOT = os.path.join(os.environ['WXWIN'], 'docs', 'doxygen') + +# Dictionary copied over from tweaker_tools +MAGIC_METHODS = { + 'operator!=' : '__ne__', + 'operator==' : '__eq__', + 'operator+' : '__add__', + 'operator-' : '__sub__', + 'operator*' : '__mul__', + 'operator/' : '__div__', + 'operator+=' : '__iadd__', + 'operator-=' : '__isub__', + 'operator*=' : '__imul__', + 'operator/=' : '__idiv__', + 'operator bool' : '__int__', # Why not __nonzero__? + # TODO: add more + } + +# A regex to split a string keeping the whitespaces +RE_KEEP_SPACES = re.compile(r'(\s+)') + +# A list of things used in the post-processing of the HTML files generated by Sphinx +# This list is used only to insert a HTML horizontal line (<hr>) after each method/function +# description +HTML_REPLACE = ['module', 'function', 'method', 'class', 'classmethod', 'staticmethod', 'attribute'] + +# The SVN revision of wxWidgets/Phoenix used to build the Sphinx docs. +# There must be a more intelligent way to get this information automatically. +SVN_REVISION = '70154' + +# Today's date representation for the Sphinx HTML docs +TODAY = datetime.date.today().strftime('%d %B %Y') + diff --git a/sphinxtools/inheritance.py b/sphinxtools/inheritance.py new file mode 100644 index 00000000..5c9da835 --- /dev/null +++ b/sphinxtools/inheritance.py @@ -0,0 +1,212 @@ +# -*- coding: utf-8 -*- +#!/usr/bin/env python + +#--------------------------------------------------------------------------- +# Name: sphinxtools/inheritance.py +# Author: Andrea Gavana +# +# Created: 30-Nov-2010 +# Copyright: (c) 2011 by Total Control Software +# License: wxWindows License +#--------------------------------------------------------------------------- + +# Standard library imports + +import os +import errno +from subprocess import Popen, PIPE + +# Phoenix-specific imports + +from utilities import Wx2Sphinx +from constants import INHERITANCEROOT + +ENOENT = getattr(errno, 'ENOENT', 0) +EPIPE = getattr(errno, 'EPIPE', 0) + + +class InheritanceDiagram(object): + """ + Given a list of classes, determines the set of classes that they inherit + from all the way to the root "object", and then is able to generate a + graphviz dot graph from them. + """ + + # ----------------------------------------------------------------------- # + + def __init__(self, class_info): + + self.class_info, self.specials = class_info + + + # These are the default attrs for graphviz + default_graph_attrs = { + 'rankdir': 'LR', + 'size': '"8.0, 12.0"', + } + default_node_attrs = { + 'shape': 'box', + 'fontsize': 10, + 'height': 0.3, + 'fontname': 'Vera Sans, DejaVu Sans, Liberation Sans, ' + 'Arial, Helvetica, sans', + 'style': '"setlinewidth(0.5)"', + } + default_edge_attrs = { + 'arrowsize': 0.5, + 'style': '"setlinewidth(0.5)"', + } + + + # ----------------------------------------------------------------------- # + + def FormatNodeAttrs(self, attrs): + + return ','.join(['%s=%s' % x for x in attrs.items()]) + + + # ----------------------------------------------------------------------- # + + def FormatGraphAttrs(self, attrs): + + return ''.join(['%s=%s;\n' % x for x in attrs.items()]) + + + # ----------------------------------------------------------------------- # + + def GenerateDot(self, name="dummy"): + """ + Generate a graphviz dot graph from the classes that were passed in to `__init__`. + + :param string `name`: the name of the graph. + + :rtype: `string` + + :returns: A string representing the Graphviz dot diagram. + """ + + inheritance_graph_attrs = dict(fontsize=9, ratio='auto', size='""', rankdir="LR") + inheritance_node_attrs = {"align": "center", 'shape': 'box', + 'fontsize': 10, 'height': 0.3, + 'fontname': 'Vera Sans, DejaVu Sans, Liberation Sans, ' + 'Arial, Helvetica, sans', 'style': '"setlinewidth(0.5)"', + 'labelloc': 'c', 'fontcolor': 'grey45'} + + inheritance_edge_attrs = {'arrowsize': 0.5, 'style': '"setlinewidth(0.5)"', "color": "black"} + + g_attrs = self.default_graph_attrs.copy() + n_attrs = self.default_node_attrs.copy() + e_attrs = self.default_edge_attrs.copy() + g_attrs.update(inheritance_graph_attrs) + n_attrs.update(inheritance_node_attrs) + e_attrs.update(inheritance_edge_attrs) + + res = [] + res.append('digraph %s {\n' % name) + res.append(self.FormatGraphAttrs(g_attrs)) + + for name, fullname, bases in self.class_info.values(): + # Write the node + this_node_attrs = n_attrs.copy() + + if name in self.specials: + this_node_attrs['fontcolor'] = 'black' + this_node_attrs['color'] = 'blue' + this_node_attrs['style'] = 'bold' + + newname, fullname = Wx2Sphinx(name) + + this_node_attrs['URL'] = '"%s.html"'%fullname + res.append(' "%s" [%s];\n' % + (newname, self.FormatNodeAttrs(this_node_attrs))) + + # Write the edges + for base_name in bases: + + this_edge_attrs = e_attrs.copy() + if name in self.specials: + this_edge_attrs['color'] = 'red' + + base_name, dummy = Wx2Sphinx(base_name) + + res.append(' "%s" -> "%s" [%s];\n' % + (base_name, newname, + self.FormatNodeAttrs(this_edge_attrs))) + res.append('}\n') + return ''.join(res) + + + # ----------------------------------------------------------------------- # + + def MakeInheritanceDiagram(self): + """ + Actually generates the inheritance diagram as a PNG file plus the corresponding + MAP file for mouse navigation over the inheritance boxes. + + These two files are saved into the ``INHERITANCEROOT`` folder (see `sphinxtools/constants.py` + for more information). + + :rtype: `tuple` + + :returns: a tuple containing the PNG file name and a string representing the content + of the MAP file (with newlines stripped away). + + .. note:: The MAP file is deleted as soon as its content has been read. + """ + + code = self.GenerateDot() + + # graphviz expects UTF-8 by default + if isinstance(code, unicode): + code = code.encode('utf-8') + + static_root = INHERITANCEROOT + + dot_args = ['dot'] + dummy, filename = Wx2Sphinx(self.specials[0]) + outfn = os.path.join(static_root, filename + '_inheritance.png') + + if os.path.isfile(outfn): + os.remove(outfn) + if os.path.isfile(outfn + '.map'): + os.remove(outfn + '.map') + + dot_args.extend(['-Tpng', '-o' + outfn]) + dot_args.extend(['-Tcmapx', '-o%s.map' % outfn]) + + try: + + p = Popen(dot_args, stdout=PIPE, stdin=PIPE, stderr=PIPE) + + except OSError, err: + + if err.errno != ENOENT: # No such file or directory + raise + + print '\nERROR: Graphviz command `dot` cannot be run (needed for Graphviz output), check your ``PATH`` setting' + + try: + # Graphviz may close standard input when an error occurs, + # resulting in a broken pipe on communicate() + stdout, stderr = p.communicate(code) + + except OSError, err: + + # in this case, read the standard output and standard error streams + # directly, to get the error message(s) + stdout, stderr = p.stdout.read(), p.stderr.read() + p.wait() + + if p.returncode != 0: + print '\nERROR: Graphviz `dot` command exited with error:\n[stderr]\n%s\n[stdout]\n%s\n\n' % (stderr, stdout) + + mapfile = outfn + '.map' + + fid = open(mapfile, 'rt') + map = fid.read() + fid.close() + + os.remove(mapfile) + + return os.path.split(outfn)[1], map.replace('\n', ' ') + diff --git a/sphinxtools/postprocess.py b/sphinxtools/postprocess.py new file mode 100644 index 00000000..b7ce2a86 --- /dev/null +++ b/sphinxtools/postprocess.py @@ -0,0 +1,566 @@ +# -*- coding: utf-8 -*- +#!/usr/bin/env python + +#--------------------------------------------------------------------------- +# Name: sphinxtools/postprocess.py +# Author: Andrea Gavana +# +# Created: 30-Nov-2010 +# Copyright: (c) 2011 by Total Control Software +# License: wxWindows License +#--------------------------------------------------------------------------- + +# Standard library imports +import os +import re +import cPickle +import glob +import random + +# Phoenix-specific imports +import templates + +from utilities import Wx2Sphinx +from constants import HTML_REPLACE, SVN_REVISION, TODAY, SPHINXROOT +from constants import CONSTANT_INSTANCES, WIDGETS_IMAGES_ROOT, SPHINX_IMAGES_ROOT + + +def MakeHeadings(): + """ + Generates the "headings.inc" file containing the substitution reference + for the small icons used in the Sphinx titles, sub-titles and so on. + + The small icons are stored into the ``SPHINX_IMAGES_ROOT`` folder. + + .. note:: The "headings.inc" file is created in the ``SPHINXROOT`` folder + (see `sphinxtools/constants.py`). + """ + + images = glob.glob(SPHINX_IMAGES_ROOT + '/*.png') + images.sort() + + heading_file = os.path.join(SPHINXROOT, 'headings.inc') + + fid = open(heading_file, 'wt') + + for img in images: + name = os.path.split(os.path.splitext(img)[0])[1] + rel_path_index = img.find('_static') + rel_path = img[rel_path_index:] + + width = ('overload' in name and [16] or [32])[0] + text = templates.TEMPLATE_HEADINGS % (name, os.path.normpath(rel_path), width) + + fid.write(text) + + fid.close() + + +# ----------------------------------------------------------------------- # + +def SphinxIndexes(sphinxDir): + """ + This is the main function called after the `etg` process has finished. + + It class other functions to generate the standalone functions page, the + main class index and some clean-up/maintenance of the generated ReST + files. + """ + + pklfiles = glob.glob(sphinxDir + '/*.pkl') + + for file in pklfiles: + if file.endswith('functions.pkl'): + ReformatFunctions(file) + elif 'classindex' in file: + MakeClassIndex(file) + + BuildEnumsAndMethods(sphinxDir) + + +# ----------------------------------------------------------------------- # + +def BuildEnumsAndMethods(sphinxDir): + """ + This function does some clean-up/refactoring of the generated ReST files by: + + 1. Removing the `:meth:` reference to Enums, as they are not methods, and replacing + it with the `:ref:` role. This information is unfortunately not known when the + main `etgtools/sphinx_generator.py` runs. + 2. Removing the "Perl note" stuff from the text (and we should clean up the + wxWidgets docs at the source to remove the wxPython notes as well). + 3. Substituting the `:ref:` role for unreferenced classes (these may be classes yet + to be ported to Phoenix or C++-specific classes which will never be ported to + Phoenix) with simple backticks. + 4. Some cleanup. + """ + + fid = open(os.path.join(sphinxDir, 'class_summary.lst'), 'rb') + class_summary = cPickle.load(fid) + fid.close() + + unreferenced_classes = {} + + textfiles = glob.glob(sphinxDir + '/*.txt') + enum_files = glob.glob(sphinxDir + '/*.enumeration.txt') + + enum_base = [os.path.split(os.path.splitext(enum)[0])[1] for enum in enum_files] + enum_base = [enum.replace('.enumeration', '') for enum in enum_base] + + enum_dict = {} + + for enum in enum_base: + enum_dict[':meth:`%s`'%enum] = ':ref:`%s`'%enum + + for input in textfiles: + + fid = open(input, 'rt') + text = fid.read() + fid.close() + + for old, new in enum_dict.items(): + text = text.replace(old, new) + + # Replace the "Perl Note" stuff, we don't need it + newtext = '' + for line in text.splitlines(): + if 'perl note' in line.lower(): + continue + newtext += line + '\n' + + text = newtext + + text = FindInherited(input, class_summary, enum_base, text) + text, unreferenced_classes = RemoveUnreferenced(input, class_summary, enum_base, unreferenced_classes, text) + + text = text.replace('wx``', '``') + text = text.replace('wx.``', '``') + text = text.replace('non-NULL', 'not ``None``') + text = text.replace(',,', ',').replace(', ,', ',') + text = text.replace(':note:', '.. note::') + + fid = open(input, 'wt') + fid.write(text) + fid.close() + + if not unreferenced_classes: + return + + warn = '\n\nWARNING: there are %d instances of referenced classes/enums, via the `:ref:` role, which\n' \ + 'are not in the list of available classes (these may be classes yet to be ported to Phoenix\n' \ + 'or C++-specific classes which will never be ported to Phoenix).\n\n' \ + '*sphinxgenerator* has replaced the `:ref:` role for them with simple backticks, i.e.:\n\n' \ + ' :ref:`MissingClass` ==> `MissingClass`\n\n' \ + 'to avoid warning from Sphinx and Docutils, and saved a list of their occurrences into\n' \ + 'the text file "unreferenced_classes.inc" together with the ReST file names where they\n' \ + 'appear.\n\n' + + keys = unreferenced_classes.keys() + keys.sort() + + fid = open(os.path.join(SPHINXROOT, 'unreferenced_classes.inc'), 'wt') + fid.write('\n') + fid.write('='*50 + ' ' + '='*50 + '\n') + fid.write('%-50s %-50s\n'%('Reference', 'File Name(s)')) + fid.write('='*50 + ' ' + '='*50 + '\n') + + for key in keys: + fid.write('%-50s %-50s\n'%(key, ', '.join(unreferenced_classes[key]))) + + fid.write('='*50 + ' ' + '='*50 + '\n') + fid.close() + + print warn%(len(keys)) + + +# ----------------------------------------------------------------------- # + +def FindInherited(input, class_summary, enum_base, text): + + regex = re.findall(':meth:\S+', text) + + for regs in regex: + + hasdot = '.' in regs + hastilde = '~' in regs + + if regs.count('`') < 2: + continue + + full_name = regs[regs.index('`')+1:regs.rindex('`')] + full_name = full_name.replace('~', '') + + curr_class = dummy = os.path.split(os.path.splitext(input)[0])[1] + + if hasdot: + newstr = full_name.split('.') + curr_class, meth_name = '.'.join(newstr[0:-1]), newstr[-1] + else: + meth_name = full_name + + if meth_name == curr_class: + newtext = ':ref:`%s`'%meth_name + text = text.replace(regs, newtext, 1) + continue + + +## elif meth_name in enum_base: +## newtext = ':ref:`%s`'%meth_name +## text = text.replace(regs, newtext, 1) +## continue + + + if meth_name in CONSTANT_INSTANCES: + text = text.replace(regs, '``%s``'%meth_name, 1) + continue + + if curr_class not in class_summary: + continue + + methods, bases = class_summary[curr_class] + + if meth_name in methods: + continue + + newstr = '' + + for cls in bases: + if cls not in class_summary: + continue + + submethods, subbases = class_summary[cls] + + if meth_name in submethods: + if not hasdot: + newstr = ':meth:`~%s.%s`'%(cls, meth_name) + elif not hastilde: + newstr = ':meth:`%s.%s`'%(cls, meth_name) + elif hasdot: + newstr = ':meth:`~%s.%s`'%(cls, meth_name) + else: + newstr = ':meth:`%s.%s`'%(cls, meth_name) + + break + + if newstr: + text = text.replace(regs, newstr, 1) + + return text + + +# ----------------------------------------------------------------------- # + +def RemoveUnreferenced(input, class_summary, enum_base, unreferenced_classes, text): + + regex = re.findall(':ref:`(.*?)`', text) + + for reg in regex: + if reg in class_summary or reg in enum_base: + continue + + if ' ' in reg or '-' in reg: + # Leave the items with spaces/dash alone, as they are + # Overview pages + continue + + if reg not in unreferenced_classes: + unreferenced_classes[reg] = [] + + split = os.path.split(input)[1] + if split not in unreferenced_classes[reg]: + unreferenced_classes[reg].append(split) + + text = text.replace(':ref:`%s`'%reg, '`%s`'%reg, 1) + + return text, unreferenced_classes + + +# ----------------------------------------------------------------------- # + +def ReformatFunctions(file): + + text_file = os.path.splitext(file)[0] + '.txt' + local_file = os.path.split(file)[1] + + fid = open(file, 'rb') + functions = cPickle.load(fid) + fid.close() + + if local_file.count('.') == 1: + # Core functions + label = 'Core' + else: + label = local_file.split('.')[0:-2][0] + + names = functions.keys() + names.sort() + + text = templates.TEMPLATE_FUNCTION_SUMMARY % (label, label) + + letters = [] + for fun in names: + if fun[0] not in letters: + letters.append(fun[0].upper()) + + text += ' | '.join(['`%s`_'%letter for letter in letters]) + text += '\n\n\n' + + for letter in letters: + text += '%s\n^\n\n'%letter + for fun in names: + if fun[0].upper() != letter: + continue + + text += '* :func:`%s`\n'%fun + + text += '\n\n' + + text += 'Functions\n=============\n\n' + + for fun in names: + text += functions[fun] + '\n' + + fid = open(text_file, 'wt') + fid.write(text) + fid.close() + + +# ----------------------------------------------------------------------- # + +def MakeClassIndex(file): + + text_file = os.path.splitext(file)[0] + '.txt' + local_file = os.path.split(file)[1] + + fid = open(file, 'rb') + classes = cPickle.load(fid) + fid.close() + + if local_file.count('.') == 1: + # Core functions + label = 'Core' + else: + label = local_file.split('.')[0:-2][0] + + names = classes.keys() + names.sort() + + text = templates.TEMPLATE_CLASS_INDEX % (label, label) + + text += 80*'=' + ' ' + 80*'=' + '\n' + text += '%-80s **Short Description**\n'%'**Class**' + text += 80*'=' + ' ' + 80*'=' + '\n' + + for cls in names: + text += '%-80s %s\n'%(':ref:`%s`'%Wx2Sphinx(cls)[1], classes[cls]) + + text += 80*'=' + ' ' + 80*'=' + '\n' + + fid = open(text_file, 'wt') + fid.write(text) + fid.close() + + +# ----------------------------------------------------------------------- # + +def GenGallery(): + + link = '<div class="gallery_class">' + + link_template = """\ + <table><caption align="bottom"><a href="%s"<b>%s</b></a</caption> + <tr> + <td><a href="%s"><img src="_static/%s/%s" border="20" alt="%s"/></a> + </td> + </tr> + </table> + """ + + image_folder = WIDGETS_IMAGES_ROOT + platforms = ['wxmsw', 'wxgtk', 'wxmac'] + + image_files = {} + + pwd = os.getcwd() + + for folder in platforms: + plat_folder = os.path.join(image_folder, folder) + os.chdir(plat_folder) + + image_files[folder] = glob.glob('*.png') + + os.chdir(pwd) + + txt_files = glob.glob(SPHINXROOT + '/*.txt') + html_files = {} + + for text in txt_files: + simple = os.path.split(os.path.splitext(text)[0])[1] + possible = simple.split('.')[-1] + possible = possible.lower() + html_files[possible + '.png'] = simple + '.html' + + keys = html_files.keys() + keys.sort() + + text = '' + + for key in keys: + possible_png = key + html = html_files[possible_png] + + rand_list = range(3) + random.shuffle(rand_list) + + for plat_index in rand_list: + platform = platforms[plat_index] + plat_images = image_files[platform] + + if possible_png in plat_images: + text += link_template%(html, os.path.splitext(html)[0], html, platform, possible_png, os.path.splitext(html)[0]) + text += '\n' + break + + gallery = os.path.join(SPHINXROOT, '_templates', 'gallery.html') + fid = open(gallery, 'wt') + fid.write(templates.TEMPLATE_GALLERY % text) + fid.close() + + +# ----------------------------------------------------------------------- # + +def AddPrettyTable(text): + """ Unused at the moment. """ + + newtext = """<br> +<table border="1" class="docutils"> """ + newtext2 = """<br> +<table border="1" class="last docutils"> """ + + text = text.replace('<table border="1" class="docutils">', newtext) + text = text.replace('<table border="1" class="last docutils">', newtext2) + + othertext = """class="pretty-table">""" + + text = text.replace('class="docutils">', othertext) + text = text.replace('class="last docutils">', othertext) + + return text + + +# ----------------------------------------------------------------------- # + +def ClassToFile(line): + + if '–' not in line: + return line + + if 'href' in line and '<li>' in line and '(' in line and ')' in line: + indx1 = line.index('href=') + if 'title=' in line: + indx2 = line.rindex('title=') + paramdesc = line[indx1+6:indx2-2] + + if '.html#' in paramdesc: + newparamdesc = paramdesc[:] + lower = paramdesc.index('#') + 1 + + letter = paramdesc[lower] + if letter.isupper(): + newparamdesc = newparamdesc[0:lower] + letter.lower() + newparamdesc[lower+1:] + newparamdesc = newparamdesc.replace(letter, letter.lower(), 1) + line = line.replace(paramdesc, newparamdesc) + + return line + + +# ----------------------------------------------------------------------- # + +def PostProcess(folder): + + fileNames = glob.glob(folder + "/html/*.html") + + phoenix_image = '<div class="floatcenter" style="background-color: white; text-align: middle; align: middle; padding: 40px 10px 15px 15px">\n' \ + '<img src="_static/phoenix_top.png" alt="Phoenix Logo" align="middle" />\n' \ + '</div>' + + + enum_files = glob.glob(folder + '/html/*.enumeration.html') + + enum_base = [os.path.split(os.path.splitext(enum)[0])[1] for enum in enum_files] + enum_base = [enum.replace('.enumeration', '') for enum in enum_base] + + enum_dict = {} + # ENUMS + + for indx, enum in enumerate(enum_base): + html_file = os.path.split(enum_files[indx])[1] + base = enum.split('.')[-1] + new = '(<a class="reference internal" href="%s" title="%s"><em>%s</em></a>)'%(html_file, base, base) + enum_dict['(<em>%s</em>)'%enum] = new + + for files in fileNames: + + if "genindex" in files or "modindex" in files: + continue + + methods_done = properties_done = False + + fid = open(files, "rt") + text = fid.read() + fid.close() + + text = text.replace('|SVN|', SVN_REVISION) + text = text.replace('|TODAY|', TODAY) + + split = os.path.split(files)[1] + + if split not in ['index.html', 'main.html']: + text = text.replace(phoenix_image, '') + +## text = AddPrettyTable(text) + text = text.replace('– <p>', '– ') + text = text.replace('<p><img alt="overload"', '<br><p><img alt="overload"') + text = text.replace('<strong>Overloaded Implementations</strong>', '<em><strong>Overloaded Implementations</strong></em>') + text = text.replace('<strong>~~~</strong></p>', '<hr style="color:#0000FF;background-color:#0000FF;height:1px;border:none;width:50%;float:left" /></p><br>') + + for item in HTML_REPLACE: + text = text.replace('<dl class="%s">'%item, '<br><hr />\n<dl class="%s">'%item) + + newtext = '' + splitted_text = text.splitlines() + len_split = len(splitted_text) + + for index, line in enumerate(splitted_text): + if '<div class="admonition-availability admonition' in line: + line = '<div class="admonition-availability admonition availability">' + + line = ClassToFile(line) + + if index < len_split - 1: + + if line.strip() == '<br><hr />': + + next_line = splitted_text[index+1] + stripline = next_line.strip() + + if (stripline == '<dl class="staticmethod">' or stripline == '<dl class="method">') and not methods_done: + line = '<br><h3>Methods<a class="headerlink" href="#methods" title="Permalink to this headline">¶</a></h3>' + '\n' + line + methods_done = True + + elif stripline == '<dl class="attribute">' and not properties_done: + line = '<br><h3>Properties<a class="headerlink" href="#properties" title="Permalink to this headline">¶</a></h3>' + '\n' + line + properties_done = True + + newtext += line + '\n' + + for old, new in enum_dict.items(): + newtext = newtext.replace(old, new) + + fid = open(files, "wt") + fid.write(newtext) + fid.close() + + +# ----------------------------------------------------------------------- # + diff --git a/sphinxtools/templates.py b/sphinxtools/templates.py new file mode 100644 index 00000000..30aabc1f --- /dev/null +++ b/sphinxtools/templates.py @@ -0,0 +1,243 @@ +# -*- coding: utf-8 -*- +#!/usr/bin/env python + +#--------------------------------------------------------------------------- +# Name: sphinxtools/templates.py +# Author: Andrea Gavana +# +# Created: 30-Nov-2010 +# Copyright: (c) 2011 by Total Control Software +# License: wxWindows License +#--------------------------------------------------------------------------- + + +# Main class description, with class name repeated twice +TEMPLATE_DESCRIPTION = ''' + +.. _%s: + +===================================================================================== +|phoenix_title| **%s** +===================================================================================== + +''' + + +# Inheritance diagram template, containing the class name, the PNG file representing +# the inheritance diagram, the "ALT" HTML flag (the class name again) and the full +# "MAP" HTML flag used for mouse navigation in the inheritance diagram boxes +TEMPLATE_INHERITANCE = ''' + +| + +|class_hierarchy| Inheritance Diagram +===================================== + +Inheritance diagram for: **%s** + +.. raw:: html + + <p class="graphviz"> + <img src="_static/images/inheritance/%s" alt="Inheritance diagram of %s" usemap="#dummy" class="inheritance"/> + %s + </p> + +| + +''' + + +# Template for the widget screenshots, with one screenshots image file for +# each platform +TEMPLATE_APPEARANCE = ''' +|appearance| Control Appearance +=============================== + +| + +.. figure:: _static/images/widgets/fullsize/wxmsw/%s + :alt: wxMSW + :figclass: floatleft + + **wxMSW** + + +.. figure:: _static/images/widgets/fullsize/wxmac/%s + :alt: wxMAC + :figclass: floatright + + **wxMAC** + + +.. figure:: _static/images/widgets/fullsize/wxgtk/%s + :alt: wxGTK + :figclass: floatcenter + + **wxGTK** + + +| + +''' + + +# Template for the subclasses of a class, with a string containing a list +# of comma separated class names with their ReST role as :ref: prepended +TEMPLATE_SUBCLASSES = ''' +|sub_classes| Known Subclasses +============================== + +%s + +| + +''' + + +# Template for the method summary of a class, containing a table made of +# ``method_name`` ``method description`` +TEMPLATE_METHOD_SUMMARY = ''' +|method_summary| Methods Summary +================================ + +%s + +| + +''' + + +# Template for the property summary of a class, containing a table made of +# ``property_name`` ``property description`` +TEMPLATE_PROPERTY_SUMMARY = ''' +|property_summary| Properties Summary +===================================== + +%s + +| + +''' + + +# Template for the Class API title, no input +TEMPLATE_API = ''' +|api| Class API +=============== + +''' + +# Template for the standalone function summary for a module (wx, wx.dataview +# and so on). + +TEMPLATE_FUNCTION_SUMMARY = ''' +.. include:: headings.inc + +========================================================================= +**%s** Functions +========================================================================= + +The functions and macros defined in the **%s** module are described here: you can look up a function using the alphabetical listing of them. + +Function Summary +================ + + +''' + + +# Template for the main class index for a module (wx, wx.dataview and so on). +TEMPLATE_CLASS_INDEX = ''' +.. include:: headings.inc + +========================================================================= +**%s** Classes +========================================================================= + +This is an alphabetical listing of all the classes defined in the **%s** module, together with a brief description of them (if available). + +You can look up a class using the alphabetical listing of them. + + +Class Summary +============= + + +''' + + +# Template for the class window styles, with the class name as input +TEMPLATE_WINDOW_STYLES = ''' + +.. _%s-styles: + +|styles| Window Styles +================================ + +''' + + +# Template for the class window extra styles, with the class name as input +TEMPLATE_WINDOW_EXTRASTYLES = ''' + +.. _%s-extra-styles: + +|extra_styles| Window Extra Styles +================================== + +''' + + +# Template for the class events, with the class name as input +TEMPLATE_EVENTS = ''' + +.. _%s-events: + +|events| Events Emitted by this Class +===================================== + +''' + + +# Template used to generate the widgets gallery (this needs some work) +TEMPLATE_GALLERY = ''' + +{%% extends "layout.html" %%} +{%% set title = "Thumbnail gallery" %%} + + +{%% block body %%} + +<h3>Click on any image to go to the relevant documentation</h3> +<br/> +The gallery is generated by randomly choosing a widget image between the 3 main +available ports of wxPython, namely <tt>wxMSW</tt>, <tt>wxGTK</tt> and <tt>wxMAC</tt> every +time the <b>Phoenix</b> documentation is built. + +<br/> +<br/> +<br/> +<br/> +<br/> + +<div class="gallery_class"> + +%s + +</div> +<br clear="all"> + +{%% endblock %%} +''' + + +# Template to generate the "headings.inc" file containing the substitution reference +# for the small icons used in the Sphinx titles, sub-titles and so on. +TEMPLATE_HEADINGS = ''' + +.. |%s| image:: %s + :align: middle + :width: %dpx + +''' + diff --git a/sphinxtools/utilities.py b/sphinxtools/utilities.py new file mode 100644 index 00000000..7649ed20 --- /dev/null +++ b/sphinxtools/utilities.py @@ -0,0 +1,589 @@ +# -*- coding: utf-8 -*- +#!/usr/bin/env python + +#--------------------------------------------------------------------------- +# Name: sphinxtools/utilities.py +# Author: Andrea Gavana +# +# Created: 30-Nov-2010 +# Copyright: (c) 2011 by Total Control Software +# License: wxWindows License +#--------------------------------------------------------------------------- + +# Standard library imports +import os +import codecs +import shutil +import cPickle + +from UserDict import UserDict + +# Phoenix-specific imports +from constants import IGNORE, PUNCTUATION +from constants import CPP_ITEMS, VERSION, VALUE_MAP +from constants import RE_KEEP_SPACES +from constants import DOXYROOT, SPHINXROOT, WIDGETS_IMAGES_ROOT + + +# ----------------------------------------------------------------------- # +class odict(UserDict): + """ + An ordered dict (odict). This is a dict which maintains an order to its items; + the order is rather like that of a list, in that new items are, by default, + added to the end, but items can be rearranged. + + .. note:: Note that updating an item (setting a value where the key is already + in the dict) is not considered to create a new item, and does not affect the + position of that key in the order. However, if an item is deleted, then a + new item with the same key is added, this is considered a new item. + + """ + + def __init__(self, dict = None): + self._keys = [] + UserDict.__init__(self, dict) + + def __delitem__(self, key): + UserDict.__delitem__(self, key) + self._keys.remove(key) + + def __setitem__(self, key, item): + UserDict.__setitem__(self, key, item) + if key not in self._keys: self._keys.append(key) + + def clear(self): + UserDict.clear(self) + self._keys = [] + + def copy(self): + dict = UserDict.copy(self) + dict._keys = self._keys[:] + return dict + + def items(self): + return zip(self._keys, self.values()) + + def keys(self): + return self._keys + + def popitem(self): + try: + key = self._keys[-1] + except IndexError: + raise KeyError('dictionary is empty') + + val = self[key] + del self[key] + + return (key, val) + + def setdefault(self, key, failobj = None): + UserDict.setdefault(self, key, failobj) + if key not in self._keys: self._keys.append(key) + + def update(self, dict): + UserDict.update(self, dict) + for key in dict.keys(): + if key not in self._keys: self._keys.append(key) + + def values(self): + return map(self.get, self._keys) + + +# ----------------------------------------------------------------------- # + +def RemoveWxPrefix(name): + """ + Removes the `wx` prefix from a string. + + :param string `name`: a string, possibly starting with "wx" or "``wx". + + :rtype: `string` + + .. note:: This function is similar to the one already present in `tweaker_tools` + but I had to extend it a bit to suite the ReSTification of the XML docs. + + """ + + if name.startswith('wx') and not name.startswith('wxEVT_') and not name.startswith('wx.'): + name = name[2:] + + if name.startswith('``wx') and not name.startswith('``wxEVT_') and not name.startswith('``wx.'): + name = name[0:2] + name[4:] + + return name + + +# ----------------------------------------------------------------------- # + +def IsNumeric(input_string): + """ + Checks if the string `input_string` actually represents a number. + + :param string `input_string`: any string. + + :rtype: `bool` + + :returns: ``True`` if the `input_string` can be converted to a number (any number), + ``False`` otherwise. + """ + + try: + float(input_string) + return True + except ValueError: + return False + + +# ----------------------------------------------------------------------- # + +def CountSpaces(text): + """ + Counts the number of spaces before and after a string. + + :param string `text`: any string. + + :rtype: `tuple` + + :returns: a tuple representing the number of spaces before and after the text. + """ + + space_before = ' '*(len(text) - len(text.lstrip(' '))) + space_after = ' '*(len(text) - len(text.rstrip(' '))) + + return space_before, space_after + + +# ----------------------------------------------------------------------- # + +def Underscore2Capitals(string): + """ + Replaces the underscore letter in a string with the following letter capitalized. + + :param string `string`: the string to be analyzed. + + :rtype: `string` + """ + + items = string.split('_')[1:] + newstr = '' + + for item in items: + newstr += item.capitalize() + + return newstr + + +# ----------------------------------------------------------------------- # + +def ReplaceCppItems(line): + """ + Replaces various C++ specific stuff with more Pythonized version of them. + + :param string `line`: any string. + + :rtype: `string` + """ + + newstr = [] + + for item in RE_KEEP_SPACES.split(line): + + if item in CPP_ITEMS: + continue + + if 'wxString' in item: + item = 'string' + elif item == 'char': + item = 'int' + elif item == 'double': + item = 'float' + + if len(item.replace('``', '')) > 2: + # Avoid replacing standalone '&&' and similar + for cpp in CPP_ITEMS[0:2]: + item = item.replace(cpp, '') + + newstr.append(item) + + newstr = ''.join(newstr) + newstr = newstr.replace(' *)', ' )') + return newstr + + +# ----------------------------------------------------------------------- # + +def PythonizeType(ptype): + """ + Replaces various C++ specific stuff with more Pythonized version of them, + for parameter lists and return types (i.e., the `:param:` and `:rtype:` + ReST roles). + + :param string `ptype`: any string. + + :rtype: `string` + """ + + ptype = Wx2Sphinx(ReplaceCppItems(ptype))[1] + ptype = ptype.replace('::', '.').replace('*&', '') + ptype = ptype.replace('int const', 'int') + ptype = ptype.replace('Uint32', 'int').replace('**', '').replace('Int32', 'int') + ptype = ptype.replace('FILE', 'file') + + for item in ['unsignedchar', 'unsignedint', 'unsignedlong', 'unsigned']: + ptype = ptype.replace(item, 'int') + + ptype = ptype.strip() + ptype = RemoveWxPrefix(ptype) + + if ptype.lower() == 'double': + ptype = 'float' + + if ptype.lower() in ['string', 'char']: + ptype = 'string' + + if 'Image.' in ptype: + ptype = ptype.split('.')[-1] + + return ptype + + +# ----------------------------------------------------------------------- # + +def ConvertToPython(text): + """ + Converts the input `text` into a more ReSTified version of it. + + This involves the following steps: + + 1. Any C++ specific declaration (like ``unsigned``, ``size_t`` and so on + is removed. + 2. Lines starting with "Include file" or "#include" are ignored. + 3. Uppercase constants (i.e., like ID_ANY, HORIZONTAL and so on) are converted + into inline literals (i.e., ``ID_ANY``, ``HORIZONTAL``). + 4. The "wx" prefix is removed from all the words in the input `text`. + + :param string `text`: any string. + + :rtype: `string` + """ + + newlines = [] + unwanted = ['Include file', '#include'] + + for line in text.splitlines(): + + newline = [] + + for remove in unwanted: + if remove in line: + line = line[0:line.index(remove)] + break + + spacer = ' '*(len(line) - len(line.lstrip())) + + line = ReplaceCppItems(line) + + for word in RE_KEEP_SPACES.split(line): + + if word == VERSION: + newline.append(word) + continue + + newword = word + for s in PUNCTUATION: + newword = newword.replace(s, "") + + if newword in VALUE_MAP: + word = word.replace(newword, VALUE_MAP[newword]) + newline.append(word) + continue + + if newword not in IGNORE and not newword.startswith('wx.'): + word = RemoveWxPrefix(word) + newword = RemoveWxPrefix(newword) + + if "::" in word and not word.endswith("::"): + word = word.replace("::", ".") + word = "`%s`"%word + newline.append(word) + continue + + if newword.upper() == newword and newword not in PUNCTUATION and \ + newword not in IGNORE and len(newword.strip()) > 1 and \ + not IsNumeric(newword) and newword not in ['DC', 'GCDC']: + + if '``' not in newword and '()' not in word and '**' not in word: + word = word.replace(newword, "``%s``"%newword) + + newline.append(word) + + newline = spacer + ''.join(newline) + newline = newline.replace(':see:', '.. seealso::') + newline = newline.replace(':note:', '.. note::') + newlines.append(newline) + + formatted = "\n".join(newlines) + formatted = formatted.replace('\\', '\\\\') + return formatted + + +# ----------------------------------------------------------------------- # + +def FindDescendants(element, tag, descendants=None): + """ + Finds and returns all descendants of a specific `xml.etree.ElementTree.Element` + whose tag matches the input `tag`. + + :param xml.etree.ElementTree.Element `element`: the XML element we want to examine. + :param string `tag`: the target tag we are looking for. + :param list `descendants`: a list of already-found descendants or ``None`` if this + is the first call to the function. + + :rtype: `list` + + .. note:: This is a recursive function, and it is only used in the `etgtools.extractors.py` + script. + + """ + + if descendants is None: + descendants = [] + + for childElement in element: + if childElement.tag == tag: + descendants.append(childElement) + + descendants = FindDescendants(childElement, tag, descendants) + + return descendants + + +# ----------------------------------------------------------------------- # + +def FindControlImages(element): + """ + Given the input `element` (an instance of `xml.etree.ElementTree.Element`) + representing a Phoenix class description, this function will scan the + doxygen image folder ``DOXYROOT`` to look for a widget screenshot. + + If this class indeed represents a widget and a screenshot is found, it is + then copied to the appropriate Sphinx input folder ``WIDGETS_IMAGES_ROOT`` + in one of its sub-folders (``wxmsw``, ``wxgtk``, ``wxmac``) depending on + which platform the screenshot was taken. + + :param xml.etree.ElementTree.Element `element`: the XML element we want to examine. + + :rtype: `list` + + :returns: A list of image paths, every element of it representing a screenshot on + a different platform. An empty list if returned if no screenshots have been found. + + .. note:: If a screenshot doesn't exist for one (or more) platform but it + exists for others, the missing images will be replaced by the "no_appearance.png" + file (you can find it inside the ``WIDGETS_IMAGES_ROOT`` folder. + + """ + + class_name = RemoveWxPrefix(element.name) or element.pyName + py_class_name = Wx2Sphinx(class_name)[1] + + class_name = class_name.lower() + py_class_name = py_class_name.lower() + + image_folder = os.path.join(DOXYROOT, 'images') + + appearance = odict() + + for sub_folder in ['wxmsw', 'wxmac', 'wxgtk']: + + png_file = class_name + '.png' + appearance[sub_folder] = '' + + possible_image = os.path.join(image_folder, sub_folder, png_file) + new_path = os.path.join(WIDGETS_IMAGES_ROOT, sub_folder) + + py_png_file = py_class_name + '.png' + new_file = os.path.join(new_path, py_png_file) + + if os.path.isfile(new_file): + + appearance[sub_folder] = py_png_file + + elif os.path.isfile(possible_image): + + if not os.path.isdir(new_path): + os.makedirs(new_path) + + if not os.path.isfile(new_file): + shutil.copyfile(possible_image, new_file) + + appearance[sub_folder] = py_png_file + + if not any(appearance.values()): + return [] + + for sub_folder, image in appearance.items(): + if not image: + appearance[sub_folder] = '../no_appearance.png' + + return appearance.values() + + +# ----------------------------------------------------------------------- # + +def MakeSummary(name, item_list, template, kind): + """ + This function generates a table containing a method/property name + and a shortened version of its docstrings. + + :param string `name`: the method/property class name. + :param list `item_list`: a list of tuples like `(method/property name, short docstrings)`. + :param string `template`: the template to use (from `sphinxtools/templates.py`, can + be the ``TEMPLATE_METHOD_SUMMARY`` or the ``TEMPLATE_PROPERTY_SUMMARY``. + :param string `kind`: can be ":meth:" or ":attr:". + + :rtype: `string` + """ + + summary = '='*80 + ' ' + '='*80 + "\n" + + for method, simple_docs in item_list: + summary += '%-80s %s'%(':%s:`~%s.%s`'%(kind, name, method), simple_docs) + '\n' + + summary += '='*80 + ' ' + '='*80 + "\n" + + return template % summary + + +# ----------------------------------------------------------------------- # + +def WriteSphinxOutput(stream, filename): + """ + Writes the text contained in the `stream` to the `filename` output file. + + :param StringIO.StringIO `stream`: the stream where the text lives. + :param string `filename`: the output file we want to write the text in. + """ + + text_file = os.path.join(SPHINXROOT, filename) + text = stream.getvalue() + + if not os.path.isfile(text_file): + text = '.. include:: headings.inc\n\n' + text + + fid = codecs.open(text_file, "a", encoding='utf-8') + fid.write(text) + fid.close() + + +# ----------------------------------------------------------------------- # + +def ChopDescription(text): + """ + Given the (possibly multiline) input text, this function will get the + first non-blank line up to the next newline character. + + :param string `text`: any string. + + :rtype: `string` + """ + + description = '' + + for line in text.splitlines(): + line = line.strip() + + if not line or line.startswith('..') or line.startswith('|'): + continue + + description = line + break + + return description + + +# ----------------------------------------------------------------------- # + +def PickleItem(description, current_module, name, kind): + """ + This function pickles/unpickles a dictionary containing class names as keys + and class brief description (chopped docstrings) as values to build the + main class index for Sphinx **or** the Phoenix standalone function names + as keys and their full description as values to build the function page. + + This step is necessary as the function names/description do not come out + in alphabetical order from the ``etg`` process. + + :param string `description`: the function/class description. + :param string `current_module`: the harmonized module name for this class + or function (see ``MODULENAME_REPLACE`` in `sphinxtools/constants.py`). + :param string `name`: the function/class name. + :param string `kind`: can be `function` or `class`. + """ + + if kind == 'function': + pickle_file = os.path.join(SPHINXROOT, current_module + 'functions.pkl') + else: + pickle_file = os.path.join(SPHINXROOT, current_module + '1classindex.pkl') + + if os.path.isfile(pickle_file): + fid = open(pickle_file, 'rb') + items = cPickle.load(fid) + fid.close() + else: + items = {} + + items[name] = description + fid = open(pickle_file, 'wb') + cPickle.dump(items, fid) + fid.close() + + +# ----------------------------------------------------------------------- # + +def PickleClassInfo(class_name, element): + + pickle_file = os.path.join(SPHINXROOT, 'class_summary.lst') + + if os.path.isfile(pickle_file): + fid = open(pickle_file, 'rb') + items = cPickle.load(fid) + fid.close() + else: + items = {} + + method_list, bases = [], [] + for method, description in element.method_list: + method_list.append(method) + + for base in element.bases: + bases.append(Wx2Sphinx(base)[1]) + + items[class_name] = (method_list, bases) + fid = open(pickle_file, 'wb') + cPickle.dump(items, fid) + fid.close() + + +# ----------------------------------------------------------------------- # + +def Wx2Sphinx(name): + """ + Converts a wxWidgets specific string into a Phoenix-ReST-ready string. + + :param string `name`: any string. + """ + + if '<' in name: + name = name[0:name.index('<')].strip() + + newname = fullname = RemoveWxPrefix(name) + + if 'DataView' in name: + fullname = 'dataview.' + fullname + + return newname, fullname + + +# ----------------------------------------------------------------------- # diff --git a/src/app_ex.py b/src/app_ex.py new file mode 100644 index 00000000..ec8d0f89 --- /dev/null +++ b/src/app_ex.py @@ -0,0 +1,263 @@ + +class PyOnDemandOutputWindow: + """ + A class that can be used for redirecting Python's stdout and + stderr streams. It will do nothing until something is wrriten to + the stream at which point it will create a Frame with a text area + and write the text there. + """ + def __init__(self, title="wxPython: stdout/stderr"): + self.frame = None + self.title = title + self.pos = wx.DefaultPosition + self.size = (450, 300) + self.parent = None + + def SetParent(self, parent): + """Set the window to be used as the popup Frame's parent.""" + self.parent = parent + + + def CreateOutputWindow(self, st): + self.frame = wx.Frame(self.parent, -1, self.title, self.pos, self.size, + style=wx.DEFAULT_FRAME_STYLE) + self.text = wx.TextCtrl(self.frame, -1, "", + style=wx.TE_MULTILINE|wx.TE_READONLY) + self.text.AppendText(st) + self.frame.Show(True) + self.frame.Bind(wx.EVT_CLOSE, self.OnCloseWindow) + + + def OnCloseWindow(self, event): + if self.frame is not None: + self.frame.Destroy() + self.frame = None + self.text = None + self.parent = None + + + # These methods provide the file-like output behaviour. + def write(self, text): + """ + Create the output window if needed and write the string to it. + If not called in the context of the gui thread then uses + CallAfter to do the work there. + """ + if self.frame is None: + if not wx.Thread.IsMain(): + wx.CallAfter(self.CreateOutputWindow, text) + else: + self.CreateOutputWindow(text) + else: + if not wx.Thread.IsMain(): + wx.CallAfter(self.text.AppendText, text) + else: + self.text.AppendText(text) + + + def close(self): + if self.frame is not None: + wx.CallAfter(self.frame.Close) + + + def flush(self): + pass + + + +#---------------------------------------------------------------------- + +class App(wx.PyApp): + """ + The ``wx.App`` class represents the application and is used to: + + * bootstrap the wxPython system and initialize the underlying + gui toolkit + * set and get application-wide properties + * implement the native windowing system main message or event loop, + and to dispatch events to window instances + * etc. + + Every wx application must have a single ``wx.App`` instance, and all + creation of UI objects should be delayed until after the ``wx.App`` object + has been created in order to ensure that the gui platform and wxWidgets + have been fully initialized. + + Normally you would derive from this class and implement an ``OnInit`` + method that creates a frame and then calls ``self.SetTopWindow(frame)``, + however ``wx.App`` is also usable on it's own without derivation. + """ + + outputWindowClass = PyOnDemandOutputWindow + + def __init__(self, + redirect=False, + filename=None, + useBestVisual=False, + clearSigInt=True): + """ + Construct a ``wx.App`` object. + + :param redirect: Should ``sys.stdout`` and ``sys.stderr`` be + redirected? Defaults to False. If ``filename`` is None + then output will be redirected to a window that pops up + as needed. (You can control what kind of window is created + for the output by resetting the class variable + ``outputWindowClass`` to a class of your choosing.) + + :param filename: The name of a file to redirect output to, if + redirect is True. + + :param useBestVisual: Should the app try to use the best + available visual provided by the system (only relevant on + systems that have more than one visual.) This parameter + must be used instead of calling `SetUseBestVisual` later + on because it must be set before the underlying GUI + toolkit is initialized. + + :param clearSigInt: Should SIGINT be cleared? This allows the + app to terminate upon a Ctrl-C in the console like other + GUI apps will. + + :note: You should override OnInit to do applicaition + initialization to ensure that the system, toolkit and + wxWidgets are fully initialized. + """ + + wx.PyApp.__init__(self) + + # make sure we can create a GUI + if not self.IsDisplayAvailable(): + + if wx.Port == "__WXMAC__": + msg = """This program needs access to the screen. +Please run with a Framework build of python, and only when you are +logged in on the main display of your Mac.""" + + elif wx.Port == "__WXGTK__": + msg ="Unable to access the X Display, is $DISPLAY set properly?" + + else: + msg = "Unable to create GUI" + # TODO: more description is needed for wxMSW... + + raise SystemExit(msg) + + # This has to be done before OnInit + self.SetUseBestVisual(useBestVisual) + + # Set the default handler for SIGINT. This fixes a problem + # where if Ctrl-C is pressed in the console that started this + # app then it will not appear to do anything, (not even send + # KeyboardInterrupt???) but will later segfault on exit. By + # setting the default handler then the app will exit, as + # expected (depending on platform.) + if clearSigInt: + try: + import signal + signal.signal(signal.SIGINT, signal.SIG_DFL) + except: + pass + + # Save and redirect the stdio to a window? + self.stdioWin = None + self.saveStdio = (_sys.stdout, _sys.stderr) + if redirect: + self.RedirectStdio(filename) + + # Use Python's install prefix as the default + wx.StandardPaths.Get().SetInstallPrefix(_sys.prefix) + +## # Until the new native control for wxMac is up to par, still use the generic one. +## wx.SystemOptions.SetOptionInt("mac.listctrl.always_use_generic", 1) + + # This finishes the initialization of wxWindows and then calls + # the OnInit that should be present in the derived class + self._BootstrapApp() + + + def OnPreInit(self): + """ + Things that must be done after _BootstrapApp has done its thing, but + would be nice if they were already done by the time that OnInit is + called. + """ + wx.StockGDI._initStockObjects() + + + def __del__(self): + self.RestoreStdio() # Just in case the MainLoop was overridden without calling RestoreStio + + + def Destroy(self): +## self.this.own(False) + wx.PyApp.Destroy(self) + + def SetTopWindow(self, frame): + """Set the \"main\" top level window""" + if self.stdioWin: + self.stdioWin.SetParent(frame) + wx.PyApp.SetTopWindow(self, frame) + + + def MainLoop(self): + """Execute the main GUI event loop""" + rv = wx.PyApp.MainLoop(self) + self.RestoreStdio() + return rv + + + def RedirectStdio(self, filename=None): + """Redirect sys.stdout and sys.stderr to a file or a popup window.""" + if filename: + _sys.stdout = _sys.stderr = open(filename, 'a') + else: + self.stdioWin = self.outputWindowClass() + _sys.stdout = _sys.stderr = self.stdioWin + + + def RestoreStdio(self): + try: + _sys.stdout, _sys.stderr = self.saveStdio + except: + pass + + + def SetOutputWindowAttributes(self, title=None, pos=None, size=None): + """ + Set the title, position and/or size of the output window if the stdio + has been redirected. This should be called before any output would + cause the output window to be created. + """ + if self.stdioWin: + if title is not None: + self.stdioWin.title = title + if pos is not None: + self.stdioWin.pos = pos + if size is not None: + self.stdioWin.size = size + +#---------------------------------------------------------------------------- + +@wx.deprecated +class PySimpleApp(App): + """ + This class is deprecated. Please use wx.App instead. + """ + def __init__(self, *args, **kw): + App.__init__(self, *args, **kw) + + +## #---------------------------------------------------------------------------- +## # DO NOT hold any other references to this object. This is how we +## # know when to cleanup system resources that wxWidgets is holding. When +## # the sys module is unloaded, the refcount on sys.__wxPythonCleanup +## # goes to zero and it calls the wx.App_CleanUp function. + +## #class __wxPyCleanup: +## #def __init__(self): +## #self.cleanup = _core_.App_CleanUp +## #def __del__(self): +## #self.cleanup() + +## #_sys.__wxPythonCleanup = __wxPyCleanup()